diff --git a/lib/hexo/post.js b/lib/hexo/post.js index 7f0db61bbe..817173041b 100644 --- a/lib/hexo/post.js +++ b/lib/hexo/post.js @@ -2,6 +2,7 @@ const assert = require('assert'); const moment = require('moment'); +const parse5 = require('parse5'); const Promise = require('bluebird'); const { join, extname, basename } = require('path'); const { magenta } = require('picocolors'); @@ -414,18 +415,21 @@ class Post { text: data.content, path: source, engine: data.engine, - toString: true, - onRenderEnd(content) { - // Replace cache data with real contents - data.content = cacheObj.restoreAllSwigTags(content); - - // Return content after replace the placeholders - if (disableNunjucks) return data.content; - - // Render with Nunjucks - return tag.render(data.content, data); - } + toString: true }, options); + }).then(content => { + const doc = parse5.parseFragment(content); + // Indepedently render the tags in each top-level node + // asynchronously. This can significantly speed up rendering of slow tags + const results = doc.childNodes.map(async node => { + // Replace cache data with real contents + const content = cacheObj.restoreAllSwigTags(parse5.serializeOuter(node)); + // If disabled, return content after replacing the placeholders + if (disableNunjucks) return content; + // Render with Nunjucks + return await tag.render(content, data); + }); + return Promise.all(results).then(x => x.join('')); }).then(content => { data.content = cacheObj.restoreCodeBlocks(content); diff --git a/package.json b/package.json index 2bbc370f3f..2aad7905d7 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "moment": "^2.29.1", "moment-timezone": "^0.5.34", "nunjucks": "^3.2.3", + "parse5": "^7.0.0", "picocolors": "^1.0.0", "pretty-hrtime": "^1.0.3", "resolve": "^1.22.0", diff --git a/test/scripts/hexo/post.js b/test/scripts/hexo/post.js index ccedb78a82..247204539d 100644 --- a/test/scripts/hexo/post.js +++ b/test/scripts/hexo/post.js @@ -3,7 +3,7 @@ const { join } = require('path'); const moment = require('moment'); const { readFile, mkdirs, unlink, rmdir, writeFile, exists, stat, listDir } = require('hexo-fs'); -const { highlight, escapeHTML } = require('hexo-util'); +const { highlight } = require('hexo-util'); const { spy, useFakeTimers } = require('sinon'); const { parse: yfm } = require('hexo-front-matter'); const fixture = require('../../fixtures/post_render'); @@ -1215,7 +1215,7 @@ describe('Post', () => { engine: 'markdown' }); - data.content.trim().should.contains(`
${escapeHTML('echo "Hi"')}\n
`); + data.content.trim().should.contains('
echo "Hi"\n
'); data.content.trim().should.contains(''); data.content.trim().should.contains(''); });