只注册了异步renderer,没有注册同步renderer会导致Hexo的Tag系统渲染出现问题
huangy10 opened this issue · 11 comments
Hexo的Tag系统在渲染Tag内部内容时,一般都是选择hexo.render.renderSync
来渲染内部内容。而hexo-renderer-pandoc
在注册renderer时,只注册了异步renderer,因此会导致Tag内的内容无法渲染,输出Markdown源码。
例如,NexT主题中的note Tag的渲染代码为:
function postNote(args, content) {
return `<div class="note ${args.join(' ')}">
${hexo.render.renderSync({text: content, engine: 'markdown'}).split('\n').join('')}
</div>`;
}
通过修改Tag的实现代码改成异步渲染可以临时解决这个问题,但是这意味着要修改所有的Tag实现,因此还是希望能够修改一下render的代码,同时注册一下同步渲染。
临时的解决办法是修改问题Tag的实现,从调用同步渲染接口修改调用异步渲染接口,详情参见:
https://www.codewoody.com/posts/62502/
我这边复现的结果:
使用NexT.Muse 主题,hexo-renderer-pandoc@0.2.5 及以上渲染以下文件
{% blockquote David Levithan, Wide Awake %}
Do not just seek happiness for yourself. Seek happiness for all. Through kindness. **Through mercy.**
{% endblockquote %}
{% tabs First unique name %}
<!-- tab -->
**This is Tab 1.**
<!-- endtab -->
<!-- tab -->
**This is Tab 2.**
<!-- endtab -->
<!-- tab -->
**This is Tab 3.**
<!-- endtab -->
{% endtabs %}
{% note %}
note **content**
{% endnote %}
经阅读 NexT 源代码后发现 tabs tag 由 NexT 主题自定义于 themes\next\scripts\tags\tabs.js
中:hexo.extend.tag.register('tabs', postTabs, {ends: true})
,其以同步方式调用本插件。
本 issue 汇报的 note tag 同理。
而 NexT 并未定义上述 blockquote tag,其定义于 Hexo lib/plugins/tag/blockquote.js
内,Hexo 同样使用同步方法调用本插件。
注意 blockquote 中正文部分 markdown 未正确渲染。引文作者部分被加粗系 Hexo 硬编码的逻辑,此处并没有调用 markdown renderer.
由于本插件仅注册为异步 renderer,在以同步方式调用时,根据 Hexo 中lib/hexo/render.js
文件的逻辑,若格式未注册为同步渲染,Hexo 直接返回输入文本:https://github.com/hexojs/hexo/blob/a6dc0ea28dddad1b5f1bad7c6f86f1e0627b564a/lib/hexo/render.js#L98
另外我考察了所有在 Hexo 官网有登记的 Markdown Renderer:
hexo-renderer-kramed
hexo-renderer-markdown
hexo-renderer-markdown-it
hexo-renderer-markdown-it-plus
hexo-renderer-marked
上述所有皆以同步方式注册。尤其 hexo-renderer-marked
实际上是 Hexo 官方开发的插件,因此应该能反映 Hexo 对于以同步方式注册 renderer 的态度。
因此我决定将本插件以同步方式注册。
@huangy10 我已将更新发表至 NPM,现版本号 0.2.8
似乎是 GitHub 识别了我的 commit message 并自动关闭了本 issue。如果你的问题没有解决,欢迎重新 open 本 issue。谢谢。
我试了一下0.2.8版本,只修改注册时候的sync参数会有问题。以同步方式注册的renderer只接收两个参数,不会传入callback,导致
TypeError: callback is not a function
在Hexo源码中,同步方式注册的函数是用Promise.method
封装的,而异步方式调用时时用Promise.promisify
封装的,参见https://github.com/hexojs/hexo/blob/a6dc0ea28dddad1b5f1bad7c6f86f1e0627b564a/lib/extend/renderer.js#L49
就是pandocRenderer
这个函数里面调用callback
的时候就会出错,因为同步的renderer不会传入callback参数的,这个参数会是undefined
我自己尝试改了一下下面的代码,可以work:
var pandocRendererSync = function(data, options){
// ...
// 前面的代码和 pandocRenderer里的一样,改为调用同步版的spawn
var src = data.text.toString();
// var pandoc = spawn('pandoc', args);
var res = spawnSync('pandoc', args, {
cwd: process.cwd(),
env: process.env,
encoding: "utf8",
input: src
})
if (res.status == 0) {
return res.stdout
} else {
console.log(res.stderr)
return ""
}
}
hexo.extend.renderer.register('markdown', 'html', pandocRendererSync, true);
供参考
有道理。我的疏忽。
由于每种输入格式只能注册一个renderer,即不能同时注册同步和异步两个版本,故我希望保留 pandocRenderer
函数的名称,而非改名为 pandocRendererSync
.
您是否希望提交一份 PR?亦或是由我代劳并给你署名?
通过Hexo的源码来看,在注册同步版本的时候,Hexo会把同步渲染函数通过Promise.method方法把同步方法封装成异步方法同时进行注册。所以注册同步方法的时候,同步渲染和异步渲染都会生成。如果希望同步和异步方法注册不同的函数,只需要先注册同步方法,后注册异步方法就可以了。Hexo的相关注册代码如下:
// https://github.com/hexojs/hexo/blob/a6dc0ea28dddad1b5f1bad7c6f86f1e0627b564a/lib/extend/renderer.js#L49
if (sync) {
this.storeSync[name] = fn;
this.storeSync[name].output = output;
this.store[name] = Promise.method(fn);
} else {
if (fn.length > 2) fn = Promise.promisify(fn);
this.store[name] = fn;
}
其中this.store
里存储的异步渲染方法,this.storeSync
里面存储的是同步渲染方法。
代码渲染您代劳一下吧,我得赶ddl去了Orz.
收到