html-webpack-plugin 3.1.0 → 4.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +113 -36
- package/default_index.ejs +1 -1
- package/index.js +618 -397
- package/lib/chunksorter.js +19 -116
- package/lib/compiler.js +359 -101
- package/lib/errors.js +2 -1
- package/lib/hooks.js +116 -0
- package/lib/html-tags.js +73 -0
- package/lib/loader.js +16 -34
- package/package.json +34 -15
package/lib/chunksorter.js
CHANGED
|
@@ -1,99 +1,12 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
/** @typedef {import("webpack/lib/Compilation.js")} WebpackCompilation */
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
|
-
const toposort = require('toposort');
|
|
4
|
-
const _ = require('lodash');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
Sorts dependencies between chunks by their "parents" attribute.
|
|
8
|
-
|
|
9
|
-
This function sorts chunks based on their dependencies with each other.
|
|
10
|
-
The parent relation between chunks as generated by Webpack for each chunk
|
|
11
|
-
is used to define a directed (and hopefully acyclic) graph, which is then
|
|
12
|
-
topologically sorted in order to retrieve the correct order in which
|
|
13
|
-
chunks need to be embedded into HTML. A directed edge in this graph is
|
|
14
|
-
describing a "is parent of" relationship from a chunk to another (distinct)
|
|
15
|
-
chunk. Thus topological sorting orders chunks from bottom-layer chunks to
|
|
16
|
-
highest level chunks that use the lower-level chunks.
|
|
17
|
-
|
|
18
|
-
@param {Array} chunks an array of chunks as generated by the html-webpack-plugin.
|
|
19
|
-
- For webpack < 4, It is assumed that each entry contains at least the properties
|
|
20
|
-
"id" (containing the chunk id) and "parents" (array containing the ids of the
|
|
21
|
-
parent chunks).
|
|
22
|
-
- For webpack 4+ the see the chunkGroups param for parent-child relationships
|
|
23
|
-
|
|
24
|
-
@param {Array} chunks an array of ChunkGroups that has a getParents method.
|
|
25
|
-
Each ChunkGroup contains a list of chunks in order.
|
|
26
|
-
|
|
27
|
-
@return {Array} A topologically sorted version of the input chunks
|
|
28
|
-
*/
|
|
29
|
-
module.exports.dependency = (chunks, chunkGroups) => {
|
|
30
|
-
if (!chunks) {
|
|
31
|
-
return chunks;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// We build a map (chunk-id -> chunk) for faster access during graph building.
|
|
35
|
-
const nodeMap = {};
|
|
36
|
-
|
|
37
|
-
chunks.forEach(chunk => {
|
|
38
|
-
nodeMap[chunk.id] = chunk;
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// Next, we add an edge for each parent relationship into the graph
|
|
42
|
-
let edges = [];
|
|
43
|
-
|
|
44
|
-
if (chunkGroups) {
|
|
45
|
-
// Add an edge for each parent (parent -> child)
|
|
46
|
-
edges = chunkGroups.reduce((result, chunkGroup) => result.concat(
|
|
47
|
-
Array.from(chunkGroup.parentsIterable, parentGroup => [parentGroup, chunkGroup])
|
|
48
|
-
), []);
|
|
49
|
-
const sortedGroups = toposort.array(chunkGroups, edges);
|
|
50
|
-
// flatten chunkGroup into chunks
|
|
51
|
-
const sortedChunks = sortedGroups
|
|
52
|
-
.reduce((result, chunkGroup) => result.concat(chunkGroup.chunks), [])
|
|
53
|
-
.map(chunk => // use the chunk from the list passed in, since it may be a filtered list
|
|
54
|
-
nodeMap[chunk.id])
|
|
55
|
-
.filter((chunk, index, self) => {
|
|
56
|
-
// make sure exists (ie excluded chunks not in nodeMap)
|
|
57
|
-
const exists = !!chunk;
|
|
58
|
-
// make sure we have a unique list
|
|
59
|
-
const unique = self.indexOf(chunk) === index;
|
|
60
|
-
return exists && unique;
|
|
61
|
-
});
|
|
62
|
-
return sortedChunks;
|
|
63
|
-
} else {
|
|
64
|
-
// before webpack 4 there was no chunkGroups
|
|
65
|
-
chunks.forEach(chunk => {
|
|
66
|
-
if (chunk.parents) {
|
|
67
|
-
// Add an edge for each parent (parent -> child)
|
|
68
|
-
chunk.parents.forEach(parentId => {
|
|
69
|
-
// webpack2 chunk.parents are chunks instead of string id(s)
|
|
70
|
-
const parentChunk = _.isObject(parentId) ? parentId : nodeMap[parentId];
|
|
71
|
-
// If the parent chunk does not exist (e.g. because of an excluded chunk)
|
|
72
|
-
// we ignore that parent
|
|
73
|
-
if (parentChunk) {
|
|
74
|
-
edges.push([parentChunk, chunk]);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
// We now perform a topological sorting on the input chunks and built edges
|
|
80
|
-
return toposort.array(chunks, edges);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
5
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* @param {Array} chunks the list of chunks to sort
|
|
88
|
-
* @return {Array} The sorted list of chunks
|
|
6
|
+
* @type {{[sortmode: string] : (entryPointNames: Array<string>, compilation, htmlWebpackPluginOptions) => Array<string> }}
|
|
7
|
+
* This file contains different sort methods for the entry chunks names
|
|
89
8
|
*/
|
|
90
|
-
module.exports
|
|
91
|
-
if (a.entry !== b.entry) {
|
|
92
|
-
return b.entry ? 1 : -1;
|
|
93
|
-
} else {
|
|
94
|
-
return b.id - a.id;
|
|
95
|
-
}
|
|
96
|
-
});
|
|
9
|
+
module.exports = {};
|
|
97
10
|
|
|
98
11
|
/**
|
|
99
12
|
* Performs identity mapping (no-sort).
|
|
@@ -104,34 +17,24 @@ module.exports.none = chunks => chunks;
|
|
|
104
17
|
|
|
105
18
|
/**
|
|
106
19
|
* Sort manually by the chunks
|
|
107
|
-
* @param {
|
|
108
|
-
* @
|
|
20
|
+
* @param {string[]} entryPointNames the chunks to sort
|
|
21
|
+
* @param {WebpackCompilation} compilation the webpack compilation
|
|
22
|
+
* @param htmlWebpackPluginOptions the plugin options
|
|
23
|
+
* @return {string[]} The sorted chunks
|
|
109
24
|
*/
|
|
110
|
-
module.exports.manual = (
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
for (var i = 0; i < specifyChunks.length; i++) {
|
|
115
|
-
filterResult = chunks.filter(chunk => {
|
|
116
|
-
if (chunk.names[0] && chunk.names[0] === specifyChunks[i]) {
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
return false;
|
|
120
|
-
});
|
|
121
|
-
filterResult.length > 0 && chunksResult.push(filterResult[0]);
|
|
122
|
-
}
|
|
25
|
+
module.exports.manual = (entryPointNames, compilation, htmlWebpackPluginOptions) => {
|
|
26
|
+
const chunks = htmlWebpackPluginOptions.chunks;
|
|
27
|
+
if (!Array.isArray(chunks)) {
|
|
28
|
+
return entryPointNames;
|
|
123
29
|
}
|
|
124
|
-
|
|
30
|
+
// Remove none existing entries from
|
|
31
|
+
// htmlWebpackPluginOptions.chunks
|
|
32
|
+
return chunks.filter((entryPointName) => {
|
|
33
|
+
return compilation.entrypoints.has(entryPointName);
|
|
34
|
+
});
|
|
125
35
|
};
|
|
126
36
|
|
|
127
37
|
/**
|
|
128
38
|
* Defines the default sorter.
|
|
129
39
|
*/
|
|
130
|
-
module.exports.auto = module.exports.
|
|
131
|
-
|
|
132
|
-
// In webpack 2 the ids have been flipped.
|
|
133
|
-
// Therefore the id sort doesn't work the same way as it did for webpack 1
|
|
134
|
-
// Luckily the dependency sort is working as expected
|
|
135
|
-
if (Number(require('webpack/package.json').version.split('.')[0]) > 1) {
|
|
136
|
-
module.exports.auto = module.exports.dependency;
|
|
137
|
-
}
|
|
40
|
+
module.exports.auto = module.exports.none;
|
package/lib/compiler.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
// @ts-check
|
|
2
|
+
/** @typedef {import("webpack/lib/Compilation.js")} WebpackCompilation */
|
|
3
|
+
/** @typedef {import("webpack/lib/Compiler.js")} WebpackCompiler */
|
|
4
|
+
/** @typedef {import("webpack/lib/Chunk.js")} WebpackChunk */
|
|
5
|
+
'use strict';
|
|
6
|
+
/**
|
|
7
|
+
* @file
|
|
2
8
|
* This file uses webpack to compile a template with a child compiler.
|
|
3
9
|
*
|
|
4
10
|
* [TEMPLATE] -> [JAVASCRIPT]
|
|
5
11
|
*
|
|
6
12
|
*/
|
|
7
13
|
'use strict';
|
|
8
|
-
const path = require('path');
|
|
9
14
|
const NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');
|
|
10
15
|
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
|
|
11
16
|
const LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin');
|
|
@@ -13,113 +18,366 @@ const LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin');
|
|
|
13
18
|
const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* @param template relative path to the template file
|
|
20
|
-
* @param context path context
|
|
21
|
-
* @param outputFilename the file name
|
|
22
|
-
* @param compilation The webpack compilation object
|
|
23
|
-
*
|
|
24
|
-
* Returns an object:
|
|
25
|
-
* {
|
|
26
|
-
* hash: {String} - Base64 hash of the file
|
|
27
|
-
* content: {String} - Javascript executable code of the template
|
|
28
|
-
* }
|
|
29
|
-
*
|
|
21
|
+
* The HtmlWebpackChildCompiler is a helper to allow resusing one childCompiler
|
|
22
|
+
* for multile HtmlWebpackPlugin instances to improve the compilation performance.
|
|
30
23
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
compilation.cache = compilation.cache[compilerName];
|
|
24
|
+
class HtmlWebpackChildCompiler {
|
|
25
|
+
constructor () {
|
|
26
|
+
/**
|
|
27
|
+
* @type {string[]} templateIds
|
|
28
|
+
* The template array will allow us to keep track which input generated which output
|
|
29
|
+
*/
|
|
30
|
+
this.templates = [];
|
|
31
|
+
/**
|
|
32
|
+
* @type {Promise<{[templatePath: string]: { content: string, hash: string, entry: WebpackChunk }}>}
|
|
33
|
+
*/
|
|
34
|
+
this.compilationPromise;
|
|
35
|
+
/**
|
|
36
|
+
* @type {number}
|
|
37
|
+
*/
|
|
38
|
+
this.compilationStartedTimestamp;
|
|
39
|
+
/**
|
|
40
|
+
* @type {number}
|
|
41
|
+
*/
|
|
42
|
+
this.compilationEndedTimestamp;
|
|
43
|
+
/**
|
|
44
|
+
* All file dependencies of the child compiler
|
|
45
|
+
* @type {string[]}
|
|
46
|
+
*/
|
|
47
|
+
this.fileDependencies = [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Add a templatePath to the child compiler
|
|
52
|
+
* The given template will be compiled by `compileTemplates`
|
|
53
|
+
* @param {string} template - The webpack path to the template e.g. `'!!html-loader!index.html'`
|
|
54
|
+
* @returns {boolean} true if the template is new
|
|
55
|
+
*/
|
|
56
|
+
addTemplate (template) {
|
|
57
|
+
const templateId = this.templates.indexOf(template);
|
|
58
|
+
// Don't add the template to the compiler if a similar template was already added
|
|
59
|
+
if (templateId !== -1) {
|
|
60
|
+
return false;
|
|
70
61
|
}
|
|
71
|
-
|
|
62
|
+
// A child compiler can compile only once
|
|
63
|
+
// throw an error if a new template is added after the compilation started
|
|
64
|
+
if (this.isCompiling()) {
|
|
65
|
+
throw new Error('New templates can only be added before `compileTemplates` was called.');
|
|
66
|
+
}
|
|
67
|
+
// Add the template to the childCompiler
|
|
68
|
+
this.templates.push(template);
|
|
69
|
+
// Mark the cache invalid
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Returns true if the childCompiler is currently compiling
|
|
75
|
+
* @retuns {boolean}
|
|
76
|
+
*/
|
|
77
|
+
isCompiling () {
|
|
78
|
+
return !this.didCompile() && this.compilationStartedTimestamp !== undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Returns true if the childCOmpiler is done compiling
|
|
83
|
+
*/
|
|
84
|
+
didCompile () {
|
|
85
|
+
return this.compilationEndedTimestamp !== undefined;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* This function will start the template compilation
|
|
90
|
+
* once it is started no more templates can be added
|
|
91
|
+
*
|
|
92
|
+
* @param {WebpackCompilation} mainCompilation
|
|
93
|
+
* @returns {Promise<{[templatePath: string]: { content: string, hash: string, entry: WebpackChunk }}>}
|
|
94
|
+
*/
|
|
95
|
+
compileTemplates (mainCompilation) {
|
|
96
|
+
// To prevent multiple compilations for the same template
|
|
97
|
+
// the compilation is cached in a promise.
|
|
98
|
+
// If it already exists return
|
|
99
|
+
if (this.compilationPromise) {
|
|
100
|
+
return this.compilationPromise;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// The entry file is just an empty helper as the dynamic template
|
|
104
|
+
// require is added in "loader.js"
|
|
105
|
+
const outputOptions = {
|
|
106
|
+
filename: '__child-[name]',
|
|
107
|
+
publicPath: mainCompilation.outputOptions.publicPath
|
|
108
|
+
};
|
|
109
|
+
const compilerName = 'HtmlWebpackCompiler';
|
|
110
|
+
// Create an additional child compiler which takes the template
|
|
111
|
+
// and turns it into an Node.JS html factory.
|
|
112
|
+
// This allows us to use loaders during the compilation
|
|
113
|
+
const childCompiler = mainCompilation.createChildCompiler(compilerName, outputOptions);
|
|
114
|
+
// The file path context which webpack uses to resolve all relative files to
|
|
115
|
+
childCompiler.context = mainCompilation.compiler.context;
|
|
116
|
+
// Compile the template to nodejs javascript
|
|
117
|
+
new NodeTemplatePlugin(outputOptions).apply(childCompiler);
|
|
118
|
+
new NodeTargetPlugin().apply(childCompiler);
|
|
119
|
+
new LibraryTemplatePlugin('HTML_WEBPACK_PLUGIN_RESULT', 'var').apply(childCompiler);
|
|
120
|
+
new LoaderTargetPlugin('node').apply(childCompiler);
|
|
121
|
+
|
|
122
|
+
// Fix for "Uncaught TypeError: __webpack_require__(...) is not a function"
|
|
123
|
+
// Hot module replacement requires that every child compiler has its own
|
|
124
|
+
// cache. @see https://github.com/ampedandwired/html-webpack-plugin/pull/179
|
|
125
|
+
childCompiler.hooks.compilation.tap('HtmlWebpackPlugin', compilation => {
|
|
126
|
+
if (compilation.cache) {
|
|
127
|
+
if (!compilation.cache[compilerName]) {
|
|
128
|
+
compilation.cache[compilerName] = {};
|
|
104
129
|
}
|
|
105
|
-
|
|
106
|
-
// Hash of the template entry point
|
|
107
|
-
hash: entries[0].hash,
|
|
108
|
-
// Output name
|
|
109
|
-
outputName: outputName,
|
|
110
|
-
// Compiled code
|
|
111
|
-
content: childCompilation.assets[outputName].source()
|
|
112
|
-
});
|
|
130
|
+
compilation.cache = compilation.cache[compilerName];
|
|
113
131
|
}
|
|
114
132
|
});
|
|
133
|
+
|
|
134
|
+
// Add all templates
|
|
135
|
+
this.templates.forEach((template, index) => {
|
|
136
|
+
new SingleEntryPlugin(childCompiler.context, template, `HtmlWebpackPlugin_${index}`).apply(childCompiler);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
this.compilationStartedTimestamp = new Date().getTime();
|
|
140
|
+
this.compilationPromise = new Promise((resolve, reject) => {
|
|
141
|
+
childCompiler.runAsChild((err, entries, childCompilation) => {
|
|
142
|
+
// Extract templates
|
|
143
|
+
const compiledTemplates = entries
|
|
144
|
+
? extractHelperFilesFromCompilation(mainCompilation, childCompilation, outputOptions.filename, entries)
|
|
145
|
+
: [];
|
|
146
|
+
// Extract file dependencies
|
|
147
|
+
if (entries) {
|
|
148
|
+
this.fileDependencies = extractFileDependenciesFilesFromCompilation(entries);
|
|
149
|
+
}
|
|
150
|
+
// Reject the promise if the childCompilation contains error
|
|
151
|
+
if (childCompilation && childCompilation.errors && childCompilation.errors.length) {
|
|
152
|
+
const errorDetails = childCompilation.errors.map(error => error.message + (error.error ? ':\n' + error.error : '')).join('\n');
|
|
153
|
+
reject(new Error('Child compilation failed:\n' + errorDetails));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// Reject if the error object contains errors
|
|
157
|
+
if (err) {
|
|
158
|
+
reject(err);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* @type {{[templatePath: string]: { content: string, hash: string, entry: WebpackChunk }}}
|
|
163
|
+
*/
|
|
164
|
+
const result = {};
|
|
165
|
+
compiledTemplates.forEach((templateSource, entryIndex) => {
|
|
166
|
+
// The compiledTemplates are generated from the entries added in
|
|
167
|
+
// the addTemplate function.
|
|
168
|
+
// Therefore the array index of this.templates should be the as entryIndex.
|
|
169
|
+
result[this.templates[entryIndex]] = {
|
|
170
|
+
content: templateSource,
|
|
171
|
+
hash: childCompilation.hash,
|
|
172
|
+
entry: entries[entryIndex]
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
this.compilationEndedTimestamp = new Date().getTime();
|
|
176
|
+
resolve(result);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
return this.compilationPromise;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The webpack child compilation will create files as a side effect.
|
|
186
|
+
* This function will extract them and clean them up so they won't be written to disk.
|
|
187
|
+
*
|
|
188
|
+
* Returns the source code of the compiled templates as string
|
|
189
|
+
*
|
|
190
|
+
* @returns Array<string>
|
|
191
|
+
*/
|
|
192
|
+
function extractHelperFilesFromCompilation (mainCompilation, childCompilation, filename, childEntryChunks) {
|
|
193
|
+
const helperAssetNames = childEntryChunks.map((entryChunk, index) => {
|
|
194
|
+
return mainCompilation.mainTemplate.hooks.assetPath.call(filename, {
|
|
195
|
+
hash: childCompilation.hash,
|
|
196
|
+
chunk: entryChunk,
|
|
197
|
+
name: `HtmlWebpackPlugin_${index}`
|
|
198
|
+
});
|
|
115
199
|
});
|
|
116
|
-
|
|
200
|
+
|
|
201
|
+
helperAssetNames.forEach((helperFileName) => {
|
|
202
|
+
delete mainCompilation.assets[helperFileName];
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const helperContents = helperAssetNames.map((helperFileName) => {
|
|
206
|
+
return childCompilation.assets[helperFileName].source();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return helperContents;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Return all file dependencies from the given set of entries.
|
|
214
|
+
* @param {WebpackChunk[]} entries
|
|
215
|
+
* @returns {string[]}
|
|
216
|
+
*/
|
|
217
|
+
function extractFileDependenciesFilesFromCompilation (entries) {
|
|
218
|
+
const fileDependencies = new Map();
|
|
219
|
+
entries.forEach((entry) => {
|
|
220
|
+
entry.entryModule.buildInfo.fileDependencies.forEach((fileDependency) => {
|
|
221
|
+
fileDependencies.set(fileDependency, true);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
return Array.from(fileDependencies.keys());
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* @type {WeakMap<WebpackCompiler, HtmlWebpackChildCompiler>}}
|
|
229
|
+
*/
|
|
230
|
+
const childCompilerCache = new WeakMap();
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get child compiler from cache or a new child compiler for the given mainCompilation
|
|
234
|
+
*
|
|
235
|
+
* @param {WebpackCompiler} mainCompiler
|
|
236
|
+
*/
|
|
237
|
+
function getChildCompiler (mainCompiler) {
|
|
238
|
+
const cachedChildCompiler = childCompilerCache.get(mainCompiler);
|
|
239
|
+
if (cachedChildCompiler) {
|
|
240
|
+
return cachedChildCompiler;
|
|
241
|
+
}
|
|
242
|
+
const newCompiler = new HtmlWebpackChildCompiler();
|
|
243
|
+
childCompilerCache.set(mainCompiler, newCompiler);
|
|
244
|
+
return newCompiler;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Remove the childCompiler from the cache
|
|
249
|
+
*
|
|
250
|
+
* @param {WebpackCompiler} mainCompiler
|
|
251
|
+
*/
|
|
252
|
+
function clearCache (mainCompiler) {
|
|
253
|
+
const childCompiler = getChildCompiler(mainCompiler);
|
|
254
|
+
// If this childCompiler was already used
|
|
255
|
+
// remove the entire childCompiler from the cache
|
|
256
|
+
if (childCompiler.isCompiling() || childCompiler.didCompile()) {
|
|
257
|
+
childCompilerCache.delete(mainCompiler);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Register a template for the current main compiler
|
|
263
|
+
* @param {WebpackCompiler} mainCompiler
|
|
264
|
+
* @param {string} templatePath
|
|
265
|
+
*/
|
|
266
|
+
function addTemplateToCompiler (mainCompiler, templatePath) {
|
|
267
|
+
const childCompiler = getChildCompiler(mainCompiler);
|
|
268
|
+
const isNew = childCompiler.addTemplate(templatePath);
|
|
269
|
+
if (isNew) {
|
|
270
|
+
clearCache(mainCompiler);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Starts the compilation for all templates.
|
|
276
|
+
* This has to be called once all templates where added.
|
|
277
|
+
*
|
|
278
|
+
* If this function is called multiple times it will use a cache inside
|
|
279
|
+
* the childCompiler
|
|
280
|
+
*
|
|
281
|
+
* @param {string} templatePath
|
|
282
|
+
* @param {string} outputFilename
|
|
283
|
+
* @param {WebpackCompilation} mainCompilation
|
|
284
|
+
*/
|
|
285
|
+
function compileTemplate (templatePath, outputFilename, mainCompilation) {
|
|
286
|
+
const childCompiler = getChildCompiler(mainCompilation.compiler);
|
|
287
|
+
return childCompiler.compileTemplates(mainCompilation).then((compiledTemplates) => {
|
|
288
|
+
if (!compiledTemplates[templatePath]) console.log(Object.keys(compiledTemplates), templatePath);
|
|
289
|
+
const compiledTemplate = compiledTemplates[templatePath];
|
|
290
|
+
// Replace [hash] placeholders in filename
|
|
291
|
+
const outputName = mainCompilation.mainTemplate.hooks.assetPath.call(outputFilename, {
|
|
292
|
+
hash: compiledTemplate.hash,
|
|
293
|
+
chunk: compiledTemplate.entry
|
|
294
|
+
});
|
|
295
|
+
return {
|
|
296
|
+
// Hash of the template entry point
|
|
297
|
+
hash: compiledTemplate.hash,
|
|
298
|
+
// Output name
|
|
299
|
+
outputName: outputName,
|
|
300
|
+
// Compiled code
|
|
301
|
+
content: compiledTemplate.content
|
|
302
|
+
};
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Return all file dependencies of the last child compilation
|
|
308
|
+
*
|
|
309
|
+
* @param {WebpackCompiler} compiler
|
|
310
|
+
* @returns {Array<string>}
|
|
311
|
+
*/
|
|
312
|
+
function getFileDependencies (compiler) {
|
|
313
|
+
const childCompiler = getChildCompiler(compiler);
|
|
314
|
+
return childCompiler.fileDependencies;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* @type {WeakMap<WebpackCompilation, WeakMap<HtmlWebpackChildCompiler, boolean>>}}
|
|
319
|
+
*/
|
|
320
|
+
const hasOutdatedCompilationDependenciesMap = new WeakMap();
|
|
321
|
+
/**
|
|
322
|
+
* Returns `true` if the file dependencies of the current childCompiler
|
|
323
|
+
* for the given mainCompilation are outdated.
|
|
324
|
+
*
|
|
325
|
+
* Uses the `hasOutdatedCompilationDependenciesMap` cache if possible.
|
|
326
|
+
*
|
|
327
|
+
* @param {WebpackCompilation} mainCompilation
|
|
328
|
+
* @returns {boolean}
|
|
329
|
+
*/
|
|
330
|
+
function hasOutDatedTemplateCache (mainCompilation) {
|
|
331
|
+
const childCompiler = getChildCompiler(mainCompilation.compiler);
|
|
332
|
+
/**
|
|
333
|
+
* @type {WeakMap<HtmlWebpackChildCompiler, boolean>|undefined}
|
|
334
|
+
*/
|
|
335
|
+
let hasOutdatedChildCompilerDependenciesMap = hasOutdatedCompilationDependenciesMap.get(mainCompilation);
|
|
336
|
+
// Create map for childCompiler if none exist
|
|
337
|
+
if (!hasOutdatedChildCompilerDependenciesMap) {
|
|
338
|
+
hasOutdatedChildCompilerDependenciesMap = new WeakMap();
|
|
339
|
+
hasOutdatedCompilationDependenciesMap.set(mainCompilation, hasOutdatedChildCompilerDependenciesMap);
|
|
340
|
+
}
|
|
341
|
+
// Try to get the `checkChildCompilerCache` result from cache
|
|
342
|
+
let isOutdated = hasOutdatedChildCompilerDependenciesMap.get(childCompiler);
|
|
343
|
+
if (isOutdated !== undefined) {
|
|
344
|
+
return isOutdated;
|
|
345
|
+
}
|
|
346
|
+
// If `checkChildCompilerCache` has never been called for the given
|
|
347
|
+
// `mainCompilation` and `childCompiler` combination call it:
|
|
348
|
+
isOutdated = isChildCompilerCacheOutdated(mainCompilation, childCompiler);
|
|
349
|
+
hasOutdatedChildCompilerDependenciesMap.set(childCompiler, isOutdated);
|
|
350
|
+
return isOutdated;
|
|
351
|
+
}
|
|
117
352
|
|
|
118
353
|
/**
|
|
119
|
-
* Returns the
|
|
354
|
+
* Returns `true` if the file dependencies of the given childCompiler are outdated.
|
|
355
|
+
*
|
|
356
|
+
* @param {WebpackCompilation} mainCompilation
|
|
357
|
+
* @param {HtmlWebpackChildCompiler} childCompiler
|
|
358
|
+
* @returns {boolean}
|
|
120
359
|
*/
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
360
|
+
function isChildCompilerCacheOutdated (mainCompilation, childCompiler) {
|
|
361
|
+
// If the compilation was never run there is no invalid cache
|
|
362
|
+
if (!childCompiler.compilationStartedTimestamp) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
// Check if any dependent file was changed after the last compilation
|
|
366
|
+
const fileTimestamps = mainCompilation.fileTimestamps;
|
|
367
|
+
const isCacheOutOfDate = childCompiler.fileDependencies.some((fileDependency) => {
|
|
368
|
+
const timestamp = fileTimestamps.get(fileDependency);
|
|
369
|
+
// If the timestamp is not known the file is new
|
|
370
|
+
// If the timestamp is larger then the file has changed
|
|
371
|
+
// Otherwise the file is still the same
|
|
372
|
+
return !timestamp || timestamp > childCompiler.compilationStartedTimestamp;
|
|
373
|
+
});
|
|
374
|
+
return isCacheOutOfDate;
|
|
125
375
|
}
|
|
376
|
+
|
|
377
|
+
module.exports = {
|
|
378
|
+
addTemplateToCompiler,
|
|
379
|
+
compileTemplate,
|
|
380
|
+
hasOutDatedTemplateCache,
|
|
381
|
+
clearCache,
|
|
382
|
+
getFileDependencies
|
|
383
|
+
};
|
package/lib/errors.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
'use strict';
|
|
2
3
|
const PrettyError = require('pretty-error');
|
|
3
4
|
const prettyError = new PrettyError();
|
|
4
5
|
prettyError.withoutColors();
|
|
5
|
-
prettyError.skipPackage(
|
|
6
|
+
prettyError.skipPackage('html-plugin-evaluation');
|
|
6
7
|
prettyError.skipNodeFiles();
|
|
7
8
|
prettyError.skip(function (traceLine) {
|
|
8
9
|
return traceLine.path === 'html-plugin-evaluation';
|