From 4889a0486dd68d2d3d808497a2d0a9f1c36dea13 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Mon, 10 Feb 2020 03:32:56 -0800 Subject: [PATCH] tests: Compile Handlebars templates with source maps. This allows us to collect coverage for Handlebars templates, and also improves the readability of Handlebars-related stack traces. Signed-off-by: Anders Kaseorg --- frontend_tests/zjsunit/handlebars.js | 88 +++++++++++++++------------- tools/test-js-with-node | 2 +- 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/frontend_tests/zjsunit/handlebars.js b/frontend_tests/zjsunit/handlebars.js index 75ea98ef6b..209babfaf7 100644 --- a/frontend_tests/zjsunit/handlebars.js +++ b/frontend_tests/zjsunit/handlebars.js @@ -1,52 +1,58 @@ const fs = require("fs"); +const Handlebars = require("handlebars/dist/cjs/handlebars.js"); const path = require("path"); +const { SourceMapConsumer, SourceNode } = require("source-map"); const templates_path = path.resolve(__dirname, "../../static/templates"); -let render; -exports.make_handlebars = () => { - // Create a new Handlebars instance. - const Handlebars = require("handlebars/dist/cjs/handlebars.js"); - const hb = Handlebars.create(); - - const compiled = new Set(); - const compileFile = filename => { - const name = "$" + path.relative(templates_path, filename); - if (!compiled.has(name)) { - compiled.add(name); - hb.registerPartial( - name, - hb.compile(fs.readFileSync(filename, "utf-8"), { preventIndent: true, zjsFilename: filename }) - ); - } - return name; - }; - - class ZJavaScriptCompiler extends hb.JavaScriptCompiler { - nameLookup(parent, name, type) { - // Auto-register partials with relative paths, like handlebars-loader. - if (type === "partial" && name !== "@partial-block") { - name = compileFile(path.resolve(path.dirname(this.options.zjsFilename), name + ".hbs")); - } - return super.nameLookup(parent, name, type); - } - } - - ZJavaScriptCompiler.prototype.compiler = ZJavaScriptCompiler; - hb.JavaScriptCompiler = ZJavaScriptCompiler; - - render = (filename, ...args) => hb.partials[compileFile(filename)](...args); - - return hb; -}; +exports.make_handlebars = () => Handlebars.create(); exports.stub_templates = stub => { - render = (filename, ...args) => { - const name = path.relative(templates_path, filename).slice(0, -".hbs".length); - return stub(name, ...args); - }; + window.template_stub = stub; }; +const hb = Handlebars.create(); + +class ZJavaScriptCompiler extends hb.JavaScriptCompiler { + nameLookup(parent, name, type) { + // Auto-register partials with relative paths, like handlebars-loader. + if (type === "partial" && name !== "@partial-block") { + const filename = path.resolve(path.dirname(this.options.srcName), name + ".hbs"); + return ["require(", JSON.stringify(filename), ")"]; + } + return super.nameLookup(parent, name, type); + } +} + +ZJavaScriptCompiler.prototype.compiler = ZJavaScriptCompiler; +hb.JavaScriptCompiler = ZJavaScriptCompiler; + require.extensions[".hbs"] = (module, filename) => { - module.exports = (...args) => render(filename, ...args); + const code = fs.readFileSync(filename, "utf-8"); + const name = path.relative(templates_path, filename).slice(0, -".hbs".length); + const pc = hb.precompile(code, { preventIndent: true, srcName: filename }); + const node = new SourceNode(); + node.add([ + "let hb, template;\n", + "module.exports = (...args) => {\n", + " if (window.template_stub !== undefined) {\n", + " return window.template_stub(", + JSON.stringify(name), + ", ...args);\n", + " }\n", + " if (hb !== Handlebars) {\n", + " template = (hb = Handlebars).template(", + SourceNode.fromStringWithSourceMap(pc.code, new SourceMapConsumer(pc.map)), + ");\n", + " }\n", + " return template(...args);\n", + "};\n", + ]); + const out = node.toStringWithSourceMap(); + module._compile( + out.code + + "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + + Buffer.from(out.map.toString()).toString("base64"), + filename + ); }; diff --git a/tools/test-js-with-node b/tools/test-js-with-node index 5d87002e4c..cc19743f54 100755 --- a/tools/test-js-with-node +++ b/tools/test-js-with-node @@ -202,7 +202,7 @@ def run_tests_via_node_js() -> int: coverage_lcov_file = os.path.join(coverage_dir, 'lcov.info') nyc = os.path.join(ROOT_DIR, 'node_modules/.bin/nyc') - command = [nyc, '--extension', '.ts'] + command = [nyc, '--extension', '.hbs', '--extension', '.ts'] command += ['--report-dir', coverage_dir] command += ['--temp-directory', coverage_dir, '-r=text-summary'] command += node_tests_cmd