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

Injector does not bind function to hexo object #4446

Closed
curbengh opened this issue Jul 27, 2020 · 7 comments · Fixed by hexojs/site#1484
Closed

Injector does not bind function to hexo object #4446

curbengh opened this issue Jul 27, 2020 · 7 comments · Fixed by hexojs/site#1484
Assignees

Comments

@curbengh
Copy link
Contributor

curbengh commented Jul 27, 2020

Noticed in hexojs/hexo-math#130

In filter, the function is automatically binded to hexo,

hexo.extend.filter.register('after_post_render', require('./lib/filter'))
function filterFn(str, data) {
  // this works
  const mathCfg = this.config.math
  return str
}

However, that style doesn't work in injector,

hexo.extend.injector.register('head_end', require('./lib/inject'))
function injectFn() {
  // doesn't work
  const mathCfg = this.config.math
  return `<lorem>${mathCfg.css}</lorem>`
}

I need to manually bind it,

hexo.extend.injector.register('head_end', require('./lib/inject').bind(hexo))
@stevenjoezhang
Copy link
Member

stevenjoezhang commented Jul 27, 2020

Tags are not bound either. Most of them use a function as return value, e.g.

module.exports = ctx => {
const PostAsset = ctx.model('PostAsset');
return function assetImgTag(args) {

hexo/lib/theme/view.js

Lines 83 to 92 in 1489074

_bindHelpers(locals) {
const helpers = this._helper.list();
const keys = Object.keys(helpers);
for (const key of keys) {
locals[key] = helpers[key].bind(locals);
}
return locals;
}

@curbengh curbengh changed the title Injector not binded to hexo Injector does not bind function to hexo object Jul 27, 2020
@curbengh
Copy link
Contributor Author

probably most tags don't need to access the config; meanwhile injector inserts to all pages by default and may need to inserts some config value, especially for inserting to <head>.

@curbengh curbengh mentioned this issue Jul 27, 2020
22 tasks
@SukkaW
Copy link
Member

SukkaW commented Jul 27, 2020

In filter, the function is automatically binded to hexo,

It is not binding. Filter is using Reflect.apply to force the code run in hexo context.

@curbengh
Copy link
Contributor Author

curbengh commented Jul 27, 2020

The original proposal #4047 mentioned the injector is designed as a convenient wrapper around after_render:html

Currently the only option is to used hexo.extend.filter.register('after_render:html', (str, data) and (/<\/body>/gi.test(htmlContent)) or s.replace(/<\/head>/, htmlContent + '</head>') to inject custom HTML snippet.

If Injector is suitable for that use case, a dev might replace existing filter with injector without String.replace(). If existing filter has this.config, the new code doesn't work without binding. indeed, the docs can mention Injector needs binding, but since Injector is seen as a replacement (for that use case), it feels strange Filter doesn't need binding, while Injector needs it.

Filter is using Reflect.apply to force the code run in hexo context.

why not run Injector in hexo context?

Probably not. Injector is designed to insert "static" HTML only.

config is static.

@SukkaW
Copy link
Member

SukkaW commented Jul 27, 2020

why not run Injector in hexo context?

Injector is designed to insert code snippet that is not depended on current HTML content (that's why meta_generator remains a filter) and won't change across pages (it requires binding locals). Injector is suitable for:

  • Insert Analytics SDK
  • Insert dependencies for plugins (video/player players, third-party syntax highlighting)

In short, Injector serves as a replacement for deprecated hexo-inject.

@SukkaW
Copy link
Member

SukkaW commented Jul 27, 2020

However, that style doesn't work in injector,

Here is a possible workaround.

// index.js
hexo.extend.injector.register('head_end', require('./lib/inject')(hexo))

// lib/inject.js
module.exports = (hexo) => () => {
  const mathCfg = hexo.config.math
  return `<lorem>${mathCfg.css}</lorem>`
}

/*
module.exports = function(ctx) {
  return function() {
    // Stuff that can access ctx
  }
}

It is an idea from functional programing. A function being "exports" will return another function to be called.
*/

@stevenjoezhang
Copy link
Member

stevenjoezhang commented Jul 27, 2020

It is an idea from functional programing. A function that "exports" will return another function to be called.

This is exactly how Hexo handles tags. Can be traced back to this commit in 2014

3323364

I can't tell which one is better - bind this or lambda calculus & currying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants