Skip to content

Commit

Permalink
perf(tag): rendering optimization (#4418)
Browse files Browse the repository at this point in the history
* perf(post): escape tag once
* perf(tag): simplify the regexp
* refactor/perf(tag): use escape instead of reserve
* perf(post): refactor swig escape regexp
* perf(tags): use match instead of test
* perf(post): merge swig regexp
  • Loading branch information
SukkaW authored Jul 24, 2020
1 parent f1eb90c commit 12c3536
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 41 deletions.
36 changes: 20 additions & 16 deletions lib/extend/tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ const { stripIndent } = require('hexo-util');
const { cyan, magenta, red } = require('chalk');
const { Environment } = require('nunjucks');
const Promise = require('bluebird');
const placeholder = '\uFFFC';
const rPlaceholder = /(?:<|&lt;)!--\uFFFC(\d+)--(?:>|&gt;)/g;
const rSwigRawFullBlock = /{% *raw *%}/;
const rCodeTag = /<code[^<>]*>[\s\S]+?<\/code>/g;
const escapeSwigTag = str => str.replace(/{/g, '&#123;').replace(/}/g, '&#125;');

class NunjucksTag {
constructor(name, fn) {
Expand Down Expand Up @@ -134,9 +135,9 @@ const getContext = (lines, errLine, location, type) => {
cyan(' === (line number probably different from source) ===')
];

Array.prototype.push.apply(message,
message.push(
// get LINES_OF_CONTEXT lines surrounding `errLine`
getContextLineNums(1, lines.length, errLine, LINES_OF_CONTEXT)
...getContextLineNums(1, lines.length, errLine, LINES_OF_CONTEXT)
.map(lnNum => {
const line = ' ' + lnNum + ' | ' + lines[lnNum - 1];
if (lnNum === errLine) {
Expand Down Expand Up @@ -188,7 +189,7 @@ class Tag {
if (typeof fn !== 'function') throw new TypeError('fn must be a function');

if (options == null || typeof options === 'boolean') {
options = {ends: options};
options = { ends: options };
}

let tag;
Expand Down Expand Up @@ -229,17 +230,20 @@ class Tag {
}

// Get path of post from source
const source = options.source || '';

const cache = [];

const escapeContent = str => `<!--${placeholder}${cache.push(str) - 1}-->`;

str = str.replace(/<pre><code.*?>[\s\S]*?<\/code><\/pre>/gm, escapeContent);

return Promise.fromCallback(cb => { this.env.renderString(str, options, cb); })
.catch(err => Promise.reject(formatNunjucksError(err, str, source)))
.then(result => result.replace(rPlaceholder, (_, index) => cache[index]))
const { source = '' } = options;

return Promise.fromCallback(cb => {
this.env.renderString(
str.replace(rCodeTag, s => {
// https://hexo.io/docs/tag-plugins#Raw
// https://mozilla.github.io/nunjucks/templating.html#raw
// Only escape code block when there is no raw tag included
return s.match(rSwigRawFullBlock) ? s : escapeSwigTag(s);
}),
options,
cb
);
}).catch(err => Promise.reject(formatNunjucksError(err, str, source)))
.asCallback(callback);
}
}
Expand Down
31 changes: 9 additions & 22 deletions lib/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,14 @@ const { slugize, escapeRegExp } = require('hexo-util');
const { copyDir, exists, listDir, mkdirs, readFile, rmdir, unlink, writeFile } = require('hexo-fs');
const yfm = require('hexo-front-matter');

const replaceSwigTag = str => str.replace(/{/g, '\uFFFCleft\uFFFC').replace(/}/g, '\uFFFCright\uFFFC');
const restoreReplacesSwigTag = str => str.replace(/\uFFFCleft\uFFFC/g, '&#123;').replace(/\uFFFCright\uFFFC/g, '&#125;');

const preservedKeys = ['title', 'slug', 'path', 'layout', 'date', 'content'];

const rPlaceholder = /(?:<|&lt;)!--\uFFFC(\d+)--(?:>|&gt;)/g;
const rSwigVar = /\{\{[\s\S]*?\}\}/g;
const rSwigComment = /\{#[\s\S]*?#\}/g;
const rSwigBlock = /\{%[\s\S]*?%\}/g;
const rSwigFullBlock = /\{% *(.+?)(?: *| +.*?)%\}[\s\S]+?\{% *end\1 *%\}/g;
const rSwigRawFullBlock = /{% *raw *%\}[\s\S]+?\{% *endraw *%\}/g;
const rSwigTagInsideInlineCode = /`.*?{.*?}.*?`/g;

const _escapeContent = (cache, str) => {
const placeholder = '\uFFFC';
return `<!--${placeholder}${cache.push(str) - 1}-->`;
};
const rSwigVarAndComment = /{[{#][\s\S]+?[}#]}/g;
const rSwigFullBlock = /{% *(\S+?)(?: *| +.+?)%}[\s\S]+?{% *end\1 *%}/g;
const rSwigBlock = /{%[\s\S]+?%}/g;

const _escapeContent = (cache, str) => `<!--\uFFFC${cache.push(str) - 1}-->`;

class PostRenderCache {
constructor() {
Expand All @@ -50,12 +41,9 @@ class PostRenderCache {

escapeAllSwigTags(str) {
const escape = _str => _escapeContent(this.cache, _str);
return str.replace(rSwigRawFullBlock, escape) // Escape {% raw %} first
.replace(rSwigTagInsideInlineCode, replaceSwigTag) // Avoid double escaped by marked renderer
.replace(rSwigFullBlock, escape)
.replace(rSwigBlock, escape)
.replace(rSwigComment, '')
.replace(rSwigVar, escape);
return str.replace(rSwigVarAndComment, escape) // Remove swig comment first to reduce string size being matched next
.replace(rSwigFullBlock, escape) // swig full block must escaped before swig block to avoid confliction
.replace(rSwigBlock, escape);
}
}

Expand Down Expand Up @@ -277,7 +265,7 @@ class Post {
toString: true,
onRenderEnd(content) {
// Replace cache data with real contents
data.content = cacheObj.loadContent(restoreReplacesSwigTag(content));
data.content = cacheObj.loadContent(content);

// Return content after replace the placeholders
if (disableNunjucks) return data.content;
Expand All @@ -287,7 +275,6 @@ class Post {
}
}, options);
}).then(content => {
// restore { and } inside inline code
data.content = content;

// Run "after_post_render" filters
Expand Down
6 changes: 3 additions & 3 deletions test/scripts/hexo/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -1016,7 +1016,7 @@ describe('Post', () => {
engine: 'markdown'
});

data.content.trim().should.eql(`<p>In Go’s templates, blocks look like this: <code>${escapeSwigTag(escapeHTML('{{block "template name" .}} (content) {{end}}'))}</code>.</p>`);
data.content.trim().should.eql(`<p>In Go’s templates, blocks look like this: <code>${escapeSwigTag('{{block "template name" .}} (content) {{end}}')}</code>.</p>`);
});

// test for https://github.com/hexojs/hexo/issues/3346#issuecomment-595497849
Expand Down Expand Up @@ -1137,13 +1137,13 @@ describe('Post', () => {
});

// indented pullquote
data.content.trim().should.contains('<pre><code>{% pullquote %}foo foo foo{% endpullquote %}</code></pre>');
data.content.trim().should.contains(`<pre><code>${escapeSwigTag('{% pullquote %}foo foo foo{% endpullquote %}')}</code></pre>`);
data.content.trim().should.contains('<p>test001</p>');
// pullquote tag
data.content.trim().should.contains('<blockquote class="pullquote"><p>bar bar bar</p>\n</blockquote>');
data.content.trim().should.contains('<p>test002</p>');
// indented youtube tag
data.content.trim().should.contains('<pre><code>{% youtube https://example.com/demo.mp4 %}</code></pre>');
data.content.trim().should.contains(`<pre><code>${escapeSwigTag('{% youtube https://example.com/demo.mp4 %}')}</code></pre>`);
// youtube tag
data.content.trim().should.contains('<div class="video-container"><iframe src="https://www.youtube.com/embed/https://example.com/sample.mp4" frameborder="0" loading="lazy" allowfullscreen></iframe></div>');
});
Expand Down

0 comments on commit 12c3536

Please sign in to comment.