diff --git a/index.js b/index.js index bf11ee19..eb74aeb1 100644 --- a/index.js +++ b/index.js @@ -123,12 +123,20 @@ class HtmlWebpackPlugin { return Promise.reject(new Error('The child compilation didn\'t provide a result')); } // The LibraryTemplatePlugin stores the template result in a local variable. - // To extract the result during the evaluation this part has to be removed. - if (source && source.indexOf('HTML_WEBPACK_PLUGIN_RESULT') >= 0) { + // By adding it to the end the value gets extracted during evaluation + if (source.indexOf('HTML_WEBPACK_PLUGIN_RESULT') >= 0) { source += ';\nHTML_WEBPACK_PLUGIN_RESULT'; } const templateWithoutLoaders = templateFilename.replace(/^.+!/, '').replace(/\?.+$/, ''); - const vmContext = vm.createContext({ HTML_WEBPACK_PLUGIN: true, require: require, htmlWebpackPluginPublicPath: publicPath, ...global }); + const vmContext = vm.createContext({ + ...global, + HTML_WEBPACK_PLUGIN: true, + require: require, + htmlWebpackPluginPublicPath: + publicPath, + URL: require('url').URL, + __filename: templateWithoutLoaders + }); const vmScript = new vm.Script(source, { filename: templateWithoutLoaders }); // Evaluate code and cast to string let newSource; @@ -147,7 +155,8 @@ class HtmlWebpackPlugin { } /** - * apply is called by the webpack main compiler during the start phase + * connect the html-webpack-plugin to the webpack compiler lifecycle hooks + * * @param {import('webpack').Compiler} compiler * @param {ProcessedHtmlWebpackOptions} options * @param {HtmlWebpackPlugin} plugin diff --git a/lib/child-compiler.js b/lib/child-compiler.js index 664e0068..ea899c05 100644 --- a/lib/child-compiler.js +++ b/lib/child-compiler.js @@ -75,6 +75,7 @@ class HtmlWebpackChildCompiler { const webpack = mainCompilation.compiler.webpack; const Compilation = webpack.Compilation; + const NodeTemplatePlugin = webpack.node.NodeTemplatePlugin; const NodeTargetPlugin = webpack.node.NodeTargetPlugin; const LoaderTargetPlugin = webpack.LoaderTargetPlugin; const EntryPlugin = webpack.EntryPlugin; @@ -103,6 +104,7 @@ class HtmlWebpackChildCompiler { const childCompiler = mainCompilation.createChildCompiler(compilerName, outputOptions, [ // Compile the template to nodejs javascript new NodeTargetPlugin(), + new NodeTemplatePlugin(), new LoaderTargetPlugin('node'), new webpack.library.EnableLibraryPlugin('var') ]); @@ -114,10 +116,18 @@ class HtmlWebpackChildCompiler { // Add all templates this.templates.forEach((template, index) => { - new EntryPlugin(childCompiler.context, 'data:text/javascript,__webpack_public_path__ = htmlWebpackPluginPublicPath;', `HtmlWebpackPlugin_${index}-${this.id}`).apply(childCompiler); + new EntryPlugin(childCompiler.context, 'data:text/javascript,__webpack_public_path__ = __webpack_base_uri__ = htmlWebpackPluginPublicPath;', `HtmlWebpackPlugin_${index}-${this.id}`).apply(childCompiler); new EntryPlugin(childCompiler.context, template, `HtmlWebpackPlugin_${index}-${this.id}`).apply(childCompiler); }); + // The templates are compiled and executed by NodeJS - similar to server side rendering + // Unfortunately this causes issues as some loaders require an absolute URL to support ES Modules + // The following config enables relative URL support for the child compiler + childCompiler.options.module = { ...childCompiler.options.module }; + childCompiler.options.module.parser = { ...childCompiler.options.module.parser }; + childCompiler.options.module.parser.javascript = { ...childCompiler.options.module.parser.javascript, + url: 'relative' }; + this.compilationStartedTimestamp = new Date().getTime(); this.compilationPromise = new Promise((resolve, reject) => { const extractedAssets = [];