hexojs / hexo

A fast, simple & powerful blog framework, powered by Node.js.
https://hexo.io
MIT License
38.83k stars 4.76k forks source link

Provide another filter to handle the HTML(after all rendered) #4048

Closed jiangtj closed 4 years ago

jiangtj commented 4 years ago

Check List

Please check followings before submitting a new feature request.

Feature Request

I tested adding the following filters to the initial example.

let index = 0;
hexo.extend.filter.register('after_render:html', (data) => {
  console.log('--------------------:' + (index++))
  console.log(data.substr(0,10))
});

This filter will be executed many times, such as md to html or ejs to html, etc.

image

I noticed that there are some built-in filters in hexo, but they are expected to be executed after the template engine to html rendering. If you can provide more accurate filters, you can reduce the number of regular matches and improve performance

https://github.com/hexojs/hexo/blob/a9bbc42219f522a0423f6dfb366f8a160821e48c/lib/plugins/filter/after_render/index.js#L6-L7

~Here are two ideas~ ~- Provide after_render:${input}-${output}~ ~- Provide after_render:generate~

Others

SukkaW commented 4 years ago

Hexo use hexo.render.getOutput() to find the ext of rendered output. So after_render:html will execute after every rendering of post, partial, tag plugins.

https://github.com/hexojs/hexo/blob/0bebf604dda615cbaad86d86f9d18b464dcbe421/lib/hexo/render.js#L83-L89

https://github.com/hexojs/hexo/blob/a9bbc42219f522a0423f6dfb366f8a160821e48c/lib/theme/view.js#L116-L126

jiangtj commented 4 years ago

Hexo use hexo.render.getOutput() to find the ext of rendered output. So after_render:html will execute after every partial rendering.

Or provide another filter to handle the HTML(after all rendered), after_render:html isn't very accurate, due to md to html or partial will trigger this filter. But expect to filter the final rendered HTML

SukkaW commented 4 years ago

https://github.com/hexojs/hexo/issues/4048#issuecomment-570119228

So after_render:html will execute after every rendering of post, partial, tag plugins.

Firstly, hexo.render.render and hexo.render.renderSync will trigger hexo.extend.filter.execFilter and hexo.extend.filter.execFilterSync.

https://github.com/hexojs/hexo/blob/0bebf604dda615cbaad86d86f9d18b464dcbe421/lib/hexo/render.js#L83-L89

layout will trigger filter execution during precompile:

https://github.com/hexojs/hexo/blob/a9bbc42219f522a0423f6dfb366f8a160821e48c/lib/theme/view.js#L116-L126

Tag plugins will trigger filter execution because they are using hexo.render.renderSync:

https://github.com/hexojs/hexo/blob/a9bbc42219f522a0423f6dfb366f8a160821e48c/lib/plugins/tag/blockquote.js#L64

https://github.com/hexojs/hexo/blob/087b3fa456aa97279df61a7f05e59c932051ee2b/lib/plugins/tag/pullquote.js#L14

https://github.com/hexojs/hexo/blob/0b26940f7e0a35f6937b944012468bbf0d844010/lib/plugins/helper/render.js#L3-L8

SukkaW commented 4 years ago

@jiangtj What about adding a new parameter noAfterRenderFilter? We could then disable after_render for tag plugins and helpers.

There is no way to determine if it is rendering the final HTML.

jiangtj commented 4 years ago

There is no way to determine if it is rendering the final HTML.

image

https://github.com/hexojs/hexo/blob/f332669ddd5437d632338fb9dbcdcca606958703/lib/hexo/index.js#L58

This may be the starting point

SukkaW commented 4 years ago

This may be the starting point

@jiangtj

https://github.com/hexojs/hexo/blob/f332669ddd5437d632338fb9dbcdcca606958703/lib/hexo/index.js#L59

The related line. This view.render() should be the exact final html rendering.

However, how to make after_render:html is only called here is still unknown... Maybe a parameter enableAfterRenderHtml?

jiangtj commented 4 years ago

可能我表述的有误,我说的渲染完成指的是单个html渲染完成,当它完成后我们可以对它操作 Maybe I said something wrong, I said that the rendering completion refers to the completion of a single html rendering, when it is completed we can operate on it

Looking at the results below, I think adding a filter here may be a good choice.

The name of the filter may be after_theme_render after_view_render after_html_render or others

image

image

jiangtj commented 4 years ago

image

image

加过滤器好简单的,就是测试用例真不会, @SukkaW 大佬加油,我溜了

SukkaW commented 4 years ago

@jiangtj I still prefer to patch after_render:html for better plugin compatibility.

jiangtj commented 4 years ago

@jiangtj I still prefer to patch after_render:html for better plugin compatibility.

I didn't say to remove after_render: html, just add a new filter because it should be executed after a single hrml render is complete

BTW, since head is in partial in the default theme, </head> occurs twice in the match, so using after_render:html is more dangerous

https://github.com/hexojs/hexo-theme-landscape/blob/26f81d9c876182d789975b23f07a1520edf72a12/layout/layout.ejs#L3

hexo.extend.filter.register('after_render:html', (data) => {
  return data.replace('</head>','<meta value="取代内容"></head>')
});

image

SukkaW commented 4 years ago

https://github.com/hexojs/hexo/issues/4048#issuecomment-570441268

@jiangtj

The test case could be:

  it('_generate() - after_route_render filter', () => {
    const hook = sinon.spy();
    hexo.extend.filter.register('after_xxx_render', hook);

    hexo.theme.setView('test.swig', '0');

    hexo.extend.generator.register('test', () => ({
      path: 'test',
      layout: 'test'
    }));

    return hexo._generate().then(() => {
      hook.called.should.be.true;
    });
  });
SukkaW commented 4 years ago

Here are some plugins that should use after_route_render filter after #4051 is merged Hexo 4.3.0 is released:

curbengh commented 4 years ago

https://github.com/hexojs/hexo/pull/4051 merged Need to update doc.

SukkaW commented 4 years ago

@curbengh Will be updated when Hexo 4.3.0 is ready to release.