Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
2 tasks done
jiangtj opened this issue Jan 2, 2020 · 14 comments
Closed
2 tasks done

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

jiangtj opened this issue Jan 2, 2020 · 14 comments
Labels
enhancement New feature or request #perfmatters

Comments

@jiangtj
Copy link
Member

jiangtj commented Jan 2, 2020

Check List

Please check followings before submitting a new feature request.

  • I have already read Docs page
  • I have already searched existing issues

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

filter.register('after_render:html', require('./external_link'));
filter.register('after_render:html', require('./meta_generator'));

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

Others

@SukkaW
Copy link
Member

SukkaW commented Jan 2, 2020

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.

hexo/lib/hexo/render.js

Lines 83 to 89 in 0bebf60

}).then(result => {
const output = this.getOutput(ext) || ext;
return ctx.execFilter(`after_render:${output}`, result, {
context: ctx,
args: [data]
});
}).asCallback(callback);

hexo/lib/theme/view.js

Lines 116 to 126 in a9bbc42

function buildFilterArguments(result) {
const output = render.getOutput(ext) || ext;
return [
`after_render:${output}`,
result,
{
context: ctx,
args: [data]
}
];
}

@jiangtj
Copy link
Member Author

jiangtj commented Jan 2, 2020

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

@jiangtj jiangtj changed the title Provide a more precise after_render:* filter Provide another filter to handle the HTML(after all rendered) Jan 2, 2020
@SukkaW
Copy link
Member

SukkaW commented Jan 2, 2020

#4048 (comment)

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.

hexo/lib/hexo/render.js

Lines 83 to 89 in 0bebf60

}).then(result => {
const output = this.getOutput(ext) || ext;
return ctx.execFilter(`after_render:${output}`, result, {
context: ctx,
args: [data]
});
}).asCallback(callback);

layout will trigger filter execution during precompile:

hexo/lib/theme/view.js

Lines 116 to 126 in a9bbc42

function buildFilterArguments(result) {
const output = render.getOutput(ext) || ext;
return [
`after_render:${output}`,
result,
{
context: ctx,
args: [data]
}
];
}

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

result += ctx.render.renderSync({text: content, engine: 'markdown'});

const result = ctx.render.renderSync({text: content, engine: 'markdown'});

module.exports = ctx => function render(text, engine, options) {
return ctx.render.renderSync({
text,
engine
}, options);
};

@SukkaW
Copy link
Member

SukkaW commented Jan 2, 2020

@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
Copy link
Member Author

jiangtj commented Jan 2, 2020

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

image

log.debug(`Rendering HTML ${name}: ${magenta(path)}`);

This may be the starting point

@SukkaW SukkaW added #perfmatters enhancement New feature or request labels Jan 2, 2020
@SukkaW
Copy link
Member

SukkaW commented Jan 2, 2020

This may be the starting point

@jiangtj

return view.render(locals).tap(result => {

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
Copy link
Member Author

jiangtj commented Jan 3, 2020

可能我表述的有误,我说的渲染完成指的是单个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
Copy link
Member Author

jiangtj commented Jan 3, 2020

image

image

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

@SukkaW
Copy link
Member

SukkaW commented Jan 3, 2020

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

@jiangtj
Copy link
Member Author

jiangtj commented Jan 3, 2020

@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
Copy link
Member

SukkaW commented Jan 3, 2020

#4048 (comment)

@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
Copy link
Member

SukkaW commented Jan 4, 2020

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

@curbengh
Copy link
Contributor

#4051 merged
Need to update doc.

@SukkaW
Copy link
Member

SukkaW commented Jan 10, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request #perfmatters
Projects
None yet
Development

No branches or pull requests

3 participants