hexojs/hexo-renderer-pandoc

只注册了异步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 %}

得到
image

经阅读 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.

收到

@huangy10 我已将更新发表至 NPM,现版本号 0.3.0

请阅读 README.md 文档中 新增的章节。由于这一次更新改动略大,请在详细测试并确认功能正确前不要将该版本用于生产。若有什么问题希望您能反馈给我。

0.2.8 版本中有重大错误,我将在 NPM 上将其标记为 deprecated.