first commit
This commit is contained in:
264
app_vue/node_modules/html-webpack-plugin/lib/child-compiler.js
generated
vendored
Normal file
264
app_vue/node_modules/html-webpack-plugin/lib/child-compiler.js
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
||||
// @ts-check
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file uses webpack to compile a template with a child compiler.
|
||||
*
|
||||
* [TEMPLATE] -> [JAVASCRIPT]
|
||||
*
|
||||
*/
|
||||
|
||||
/** @typedef {import("webpack").Chunk} Chunk */
|
||||
/** @typedef {import("webpack").sources.Source} Source */
|
||||
/** @typedef {{hash: string, entry: Chunk, content: string, assets: {[name: string]: { source: Source, info: import("webpack").AssetInfo }}}} ChildCompilationTemplateResult */
|
||||
|
||||
/**
|
||||
* The HtmlWebpackChildCompiler is a helper to allow reusing one childCompiler
|
||||
* for multiple HtmlWebpackPlugin instances to improve the compilation performance.
|
||||
*/
|
||||
class HtmlWebpackChildCompiler {
|
||||
/**
|
||||
*
|
||||
* @param {string[]} templates
|
||||
*/
|
||||
constructor(templates) {
|
||||
/**
|
||||
* @type {string[]} templateIds
|
||||
* The template array will allow us to keep track which input generated which output
|
||||
*/
|
||||
this.templates = templates;
|
||||
/** @type {Promise<{[templatePath: string]: ChildCompilationTemplateResult}>} */
|
||||
this.compilationPromise; // eslint-disable-line
|
||||
/** @type {number | undefined} */
|
||||
this.compilationStartedTimestamp; // eslint-disable-line
|
||||
/** @type {number | undefined} */
|
||||
this.compilationEndedTimestamp; // eslint-disable-line
|
||||
/**
|
||||
* All file dependencies of the child compiler
|
||||
* @type {{fileDependencies: string[], contextDependencies: string[], missingDependencies: string[]}}
|
||||
*/
|
||||
this.fileDependencies = {
|
||||
fileDependencies: [],
|
||||
contextDependencies: [],
|
||||
missingDependencies: [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the childCompiler is currently compiling
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isCompiling() {
|
||||
return !this.didCompile() && this.compilationStartedTimestamp !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the childCompiler is done compiling
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
didCompile() {
|
||||
return this.compilationEndedTimestamp !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will start the template compilation
|
||||
* once it is started no more templates can be added
|
||||
*
|
||||
* @param {import('webpack').Compilation} mainCompilation
|
||||
* @returns {Promise<{[templatePath: string]: ChildCompilationTemplateResult}>}
|
||||
*/
|
||||
compileTemplates(mainCompilation) {
|
||||
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;
|
||||
|
||||
// To prevent multiple compilations for the same template
|
||||
// the compilation is cached in a promise.
|
||||
// If it already exists return
|
||||
if (this.compilationPromise) {
|
||||
return this.compilationPromise;
|
||||
}
|
||||
|
||||
const outputOptions = {
|
||||
filename: "__child-[name]",
|
||||
publicPath: "",
|
||||
library: {
|
||||
type: "var",
|
||||
name: "HTML_WEBPACK_PLUGIN_RESULT",
|
||||
},
|
||||
scriptType: /** @type {'text/javascript'} */ ("text/javascript"),
|
||||
iife: true,
|
||||
};
|
||||
const compilerName = "HtmlWebpackCompiler";
|
||||
// Create an additional child compiler which takes the template
|
||||
// and turns it into an Node.JS html factory.
|
||||
// This allows us to use loaders during the compilation
|
||||
const childCompiler = mainCompilation.createChildCompiler(
|
||||
compilerName,
|
||||
outputOptions,
|
||||
[
|
||||
// Compile the template to nodejs javascript
|
||||
new NodeTargetPlugin(),
|
||||
new NodeTemplatePlugin(),
|
||||
new LoaderTargetPlugin("node"),
|
||||
new webpack.library.EnableLibraryPlugin("var"),
|
||||
],
|
||||
);
|
||||
// The file path context which webpack uses to resolve all relative files to
|
||||
childCompiler.context = mainCompilation.compiler.context;
|
||||
|
||||
// Generate output file names
|
||||
const temporaryTemplateNames = this.templates.map(
|
||||
(template, index) => `__child-HtmlWebpackPlugin_${index}-${template}`,
|
||||
);
|
||||
|
||||
// Add all templates
|
||||
this.templates.forEach((template, index) => {
|
||||
new EntryPlugin(
|
||||
childCompiler.context,
|
||||
"data:text/javascript,__webpack_public_path__ = __webpack_base_uri__ = htmlWebpackPluginPublicPath;",
|
||||
`HtmlWebpackPlugin_${index}-${template}`,
|
||||
).apply(childCompiler);
|
||||
new EntryPlugin(
|
||||
childCompiler.context,
|
||||
template,
|
||||
`HtmlWebpackPlugin_${index}-${template}`,
|
||||
).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();
|
||||
/** @type {Promise<{[templatePath: string]: ChildCompilationTemplateResult}>} */
|
||||
this.compilationPromise = new Promise((resolve, reject) => {
|
||||
/** @type {Source[]} */
|
||||
const extractedAssets = [];
|
||||
|
||||
childCompiler.hooks.thisCompilation.tap(
|
||||
"HtmlWebpackPlugin",
|
||||
(compilation) => {
|
||||
compilation.hooks.processAssets.tap(
|
||||
{
|
||||
name: "HtmlWebpackPlugin",
|
||||
stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
|
||||
},
|
||||
(assets) => {
|
||||
temporaryTemplateNames.forEach((temporaryTemplateName) => {
|
||||
if (assets[temporaryTemplateName]) {
|
||||
extractedAssets.push(assets[temporaryTemplateName]);
|
||||
|
||||
compilation.deleteAsset(temporaryTemplateName);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
childCompiler.runAsChild((err, entries, childCompilation) => {
|
||||
// Extract templates
|
||||
// TODO fine a better way to store entries and results, to avoid duplicate chunks and assets
|
||||
const compiledTemplates = entries
|
||||
? extractedAssets.map((asset) => asset.source())
|
||||
: [];
|
||||
|
||||
// Extract file dependencies
|
||||
if (entries && childCompilation) {
|
||||
this.fileDependencies = {
|
||||
fileDependencies: Array.from(childCompilation.fileDependencies),
|
||||
contextDependencies: Array.from(
|
||||
childCompilation.contextDependencies,
|
||||
),
|
||||
missingDependencies: Array.from(
|
||||
childCompilation.missingDependencies,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// Reject the promise if the childCompilation contains error
|
||||
if (
|
||||
childCompilation &&
|
||||
childCompilation.errors &&
|
||||
childCompilation.errors.length
|
||||
) {
|
||||
const errorDetailsArray = [];
|
||||
for (const error of childCompilation.errors) {
|
||||
let message = error.message;
|
||||
if (error.stack) {
|
||||
message += "\n" + error.stack;
|
||||
}
|
||||
errorDetailsArray.push(message);
|
||||
}
|
||||
const errorDetails = errorDetailsArray.join("\n");
|
||||
|
||||
reject(new Error("Child compilation failed:\n" + errorDetails));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Reject if the error object contains errors
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!childCompilation || !entries) {
|
||||
reject(new Error("Empty child compilation"));
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {{[templatePath: string]: ChildCompilationTemplateResult}}
|
||||
*/
|
||||
const result = {};
|
||||
|
||||
/** @type {{[name: string]: { source: Source, info: import("webpack").AssetInfo }}} */
|
||||
const assets = {};
|
||||
|
||||
for (const asset of childCompilation.getAssets()) {
|
||||
assets[asset.name] = { source: asset.source, info: asset.info };
|
||||
}
|
||||
|
||||
compiledTemplates.forEach((templateSource, entryIndex) => {
|
||||
// The compiledTemplates are generated from the entries added in
|
||||
// the addTemplate function.
|
||||
// Therefore, the array index of this.templates should be the as entryIndex.
|
||||
result[this.templates[entryIndex]] = {
|
||||
// TODO, can we have Buffer here?
|
||||
content: /** @type {string} */ (templateSource),
|
||||
hash: childCompilation.hash || "XXXX",
|
||||
entry: entries[entryIndex],
|
||||
assets,
|
||||
};
|
||||
});
|
||||
|
||||
this.compilationEndedTimestamp = new Date().getTime();
|
||||
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
|
||||
return this.compilationPromise;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
HtmlWebpackChildCompiler,
|
||||
};
|
Reference in New Issue
Block a user