From 7e1af7b89cb8ace5518da7869fd7174bab013031 Mon Sep 17 00:00:00 2001 From: Jan Nicklas Date: Fri, 9 Sep 2016 15:05:38 +0200 Subject: [PATCH] Add `__entry` and `__entryPath` to the global template variables --- index.js | 49 +++++++++++++++++++++----------- lib/compiler.js | 11 +++++-- package.json | 15 +++++----- spec/BasicSpec.js | 32 ++++++++++++++++++++- spec/fixtures/templateGlobals.js | 7 +++++ 5 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 spec/fixtures/templateGlobals.js diff --git a/index.js b/index.js index f59d91b..713cde8 100644 --- a/index.js +++ b/index.js @@ -204,6 +204,14 @@ HtmlWebpackPlugin.prototype.apply = function (compiler) { }); }; +/** + * Resolves a request to a real file path + */ +HtmlWebpackPlugin.prototype.getResolvedFilename = function (request, compiler) { + var requestWithoutLoaders = this.options.template.replace(/^.+!/, '').replace(/\?.+$/, ''); + return Promise.promisify(compiler.resolvers.normal.resolve)(compiler.context, requestWithoutLoaders); +}; + /** * Evaluates the child compilation result * Returns a promise @@ -212,23 +220,32 @@ HtmlWebpackPlugin.prototype.evaluateCompilationResult = function (compilation, s if (!source) { return Promise.reject('The child compilation didn\'t provide a result'); } + return this.getResolvedFilename(this.options.template, compilation.compiler) + .then(function (templatePath) { + // The LibraryTemplatePlugin stores the template result in a local variable. + // To extract the result during the evaluation this part has to be removed. + source = source.replace('var HTML_WEBPACK_PLUGIN_RESULT =', ''); - // The LibraryTemplatePlugin stores the template result in a local variable. - // To extract the result during the evaluation this part has to be removed. - source = source.replace('var HTML_WEBPACK_PLUGIN_RESULT =', ''); - var template = this.options.template.replace(/^.+!/, '').replace(/\?.+$/, ''); - var vmContext = vm.createContext(_.extend({HTML_WEBPACK_PLUGIN: true, require: require}, global)); - var vmScript = new vm.Script(source, {filename: template}); - // Evaluate code and cast to string - var newSource; - try { - newSource = vmScript.runInContext(vmContext); - } catch (e) { - return Promise.reject(e); - } - return typeof newSource === 'string' || typeof newSource === 'function' - ? Promise.resolve(newSource) - : Promise.reject('The loader "' + this.options.template + '" didn\'t return html.'); + var vmContext = vm.createContext(_.extend({ + HTML_WEBPACK_PLUGIN: true, + require: require, + __entry: templatePath, + __entryPath: path.dirname(templatePath) + }, global)); + + var vmScript = new vm.Script(source, {filename: path.basename(templatePath)}); + // Evaluate code and cast to string + var newSource; + try { + newSource = vmScript.runInContext(vmContext); + } catch (templateEvaluationError) { + return Promise.reject(templateEvaluationError); + } + // Verify that the template result is a template function or a template string + return typeof newSource === 'string' || typeof newSource === 'function' + ? Promise.resolve(newSource) + : Promise.reject('The loader "' + this.options.template + '" didn\'t return html.'); + }); }; /** diff --git a/lib/compiler.js b/lib/compiler.js index 9c8a224..b2a2c8d 100644 --- a/lib/compiler.js +++ b/lib/compiler.js @@ -13,6 +13,7 @@ var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin'); var LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin'); var LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin'); var SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); +var NodeStuffPlugin = require('webpack/lib/NodeStuffPlugin'); /** * Compiles the template into a nodejs factory, adds its to the compilation.assets @@ -46,11 +47,15 @@ module.exports.compileTemplate = function compileTemplate (template, context, ou var childCompiler = compilation.createChildCompiler(compilerName, outputOptions); childCompiler.context = context; childCompiler.apply( - new NodeTemplatePlugin(outputOptions), - new NodeTargetPlugin(), new LibraryTemplatePlugin('HTML_WEBPACK_PLUGIN_RESULT', 'var'), new SingleEntryPlugin(this.context, template), - new LoaderTargetPlugin('node') + new NodeTemplatePlugin(outputOptions), + new NodeTargetPlugin(), + new LoaderTargetPlugin('node'), + new NodeStuffPlugin({ + __dirname: false, + __filename: false + }) ); // Fix for "Uncaught TypeError: __webpack_require__(...) is not a function" diff --git a/package.json b/package.json index beaf268..1d30a0b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "prepublish": "npm run test", "pretest": "semistandard", "build-examples": "node examples/build-examples.js", - "test": "jasmine" + "test": "jasmine --verbose --captureExceptions" }, "repository": { "type": "git", @@ -37,28 +37,29 @@ }, "devDependencies": { "appcache-webpack-plugin": "^1.3.0", - "css-loader": "^0.23.1", - "dir-compare": "1.0.1", + "css-loader": "^0.25.0", + "dir-compare": "1.1.0", "es6-promise": "^3.2.1", "extract-text-webpack-plugin": "^1.0.1", "file-loader": "^0.9.0", "html-loader": "^0.4.3", "jade": "^1.11.0", "jade-loader": "^0.8.0", - "jasmine": "^2.4.1", + "jasmine": "^2.5.1", + "jasmine-console-reporter": "^1.2.7", "rimraf": "^2.5.4", "semistandard": "^8.0.0", "style-loader": "^0.13.1", "underscore-template-loader": "^0.7.3", "url-loader": "^0.5.7", - "webpack": "^1.13.1", + "webpack": "^1.13.2", "webpack-recompilation-simulator": "^1.3.0" }, "dependencies": { - "bluebird": "^3.4.1", + "bluebird": "^3.4.6", "html-minifier": "^3.0.2", "loader-utils": "^0.2.15", - "lodash": "^4.14.2", + "lodash": "^4.15.0", "pretty-error": "^2.0.0", "toposort": "^1.0.0" }, diff --git a/spec/BasicSpec.js b/spec/BasicSpec.js index 05ce988..2d0d3a2 100644 --- a/spec/BasicSpec.js +++ b/spec/BasicSpec.js @@ -21,6 +21,14 @@ var HtmlWebpackPlugin = require('../index.js'); var OUTPUT_DIR = path.join(__dirname, '../dist'); jasmine.getEnv().defaultTimeoutInterval = 30000; +var JasmineConsoleReporter = require('jasmine-console-reporter'); +jasmine.getEnv().addReporter(new JasmineConsoleReporter({ + colors: 1, + cleanStack: 1, + verbosity: 4, + listStyle: 'indent', + activity: false +})); function testHtmlPlugin (webpackConfig, expectedResults, outputFile, done, expectErrors, expectWarnings) { outputFile = outputFile || 'index.html'; @@ -1114,7 +1122,7 @@ describe('HtmlWebpackPlugin', function () { template: path.join(__dirname, 'fixtures/non-existing-template.html') }) ] - }, ['Child compilation failed:\n Entry module not found:'], null, done, true); + }, ['Error: Cannot resolve'], null, done, true); }); it('should sort the chunks in auto mode', function (done) { @@ -1240,6 +1248,28 @@ describe('HtmlWebpackPlugin', function () { }, ['templateParams.compilation exists: true'], null, done); }); + it('should provide globals to the template compilation', function (done) { + var template = path.resolve(__dirname, 'fixtures/templateGlobals.js'); + var templatePath = path.dirname(template); + testHtmlPlugin({ + entry: path.join(__dirname, 'fixtures/index.js'), + output: { + path: OUTPUT_DIR, + filename: 'index_bundle.js' + }, + plugins: [ + new HtmlWebpackPlugin({ + template: template, + inject: false + }) + ] + }, [ + '"__entry":"' + template + '"', + '"__entryPath":"' + templatePath + '"', + '"HTML_WEBPACK_PLUGIN":true' + ], null, done); + }); + it('should not treat templateContent set to an empty string as missing', function (done) { testHtmlPlugin({ entry: {app: path.join(__dirname, 'fixtures/index.js')}, diff --git a/spec/fixtures/templateGlobals.js b/spec/fixtures/templateGlobals.js new file mode 100644 index 0000000..dbf1bc3 --- /dev/null +++ b/spec/fixtures/templateGlobals.js @@ -0,0 +1,7 @@ +module.exports = function (templateParams) { + return JSON.stringify({ + __entry: global.__entry, + __entryPath: global.__entryPath, + HTML_WEBPACK_PLUGIN: global.HTML_WEBPACK_PLUGIN + }); +};