1 |
|
2 |
|
3 |
|
4 |
|
5 | 'use strict';
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | 'use strict';
|
14 |
|
15 | let instanceId = 0;
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | class HtmlWebpackChildCompiler {
|
21 | |
22 |
|
23 |
|
24 |
|
25 | constructor (templates) {
|
26 |
|
27 | this.id = instanceId++;
|
28 | |
29 |
|
30 |
|
31 |
|
32 | this.templates = templates;
|
33 | |
34 |
|
35 |
|
36 | this.compilationPromise;
|
37 | |
38 |
|
39 |
|
40 | this.compilationStartedTimestamp;
|
41 | |
42 |
|
43 |
|
44 | this.compilationEndedTimestamp;
|
45 | |
46 |
|
47 |
|
48 |
|
49 | this.fileDependencies = { fileDependencies: [], contextDependencies: [], missingDependencies: [] };
|
50 | }
|
51 |
|
52 | |
53 |
|
54 |
|
55 |
|
56 | isCompiling () {
|
57 | return !this.didCompile() && this.compilationStartedTimestamp !== undefined;
|
58 | }
|
59 |
|
60 | |
61 |
|
62 |
|
63 | didCompile () {
|
64 | return this.compilationEndedTimestamp !== undefined;
|
65 | }
|
66 |
|
67 | |
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | compileTemplates (mainCompilation) {
|
75 | const webpack = mainCompilation.compiler.webpack;
|
76 | const Compilation = webpack.Compilation;
|
77 |
|
78 | const NodeTemplatePlugin = webpack.node.NodeTemplatePlugin;
|
79 | const NodeTargetPlugin = webpack.node.NodeTargetPlugin;
|
80 | const LoaderTargetPlugin = webpack.LoaderTargetPlugin;
|
81 | const EntryPlugin = webpack.EntryPlugin;
|
82 |
|
83 |
|
84 |
|
85 |
|
86 | if (this.compilationPromise) {
|
87 | return this.compilationPromise;
|
88 | }
|
89 |
|
90 | const outputOptions = {
|
91 | filename: '__child-[name]',
|
92 | publicPath: '',
|
93 | library: {
|
94 | type: 'var',
|
95 | name: 'HTML_WEBPACK_PLUGIN_RESULT'
|
96 | },
|
97 | scriptType: ('text/javascript'),
|
98 | iife: true
|
99 | };
|
100 | const compilerName = 'HtmlWebpackCompiler';
|
101 |
|
102 |
|
103 |
|
104 | const childCompiler = mainCompilation.createChildCompiler(compilerName, outputOptions, [
|
105 |
|
106 | new NodeTargetPlugin(),
|
107 | new NodeTemplatePlugin(),
|
108 | new LoaderTargetPlugin('node'),
|
109 | new webpack.library.EnableLibraryPlugin('var')
|
110 | ]);
|
111 |
|
112 | childCompiler.context = mainCompilation.compiler.context;
|
113 |
|
114 |
|
115 | const temporaryTemplateNames = this.templates.map((template, index) => `__child-HtmlWebpackPlugin_${index}-${this.id}`);
|
116 |
|
117 |
|
118 | this.templates.forEach((template, index) => {
|
119 | new EntryPlugin(childCompiler.context, 'data:text/javascript,__webpack_public_path__ = __webpack_base_uri__ = htmlWebpackPluginPublicPath;', `HtmlWebpackPlugin_${index}-${this.id}`).apply(childCompiler);
|
120 | new EntryPlugin(childCompiler.context, template, `HtmlWebpackPlugin_${index}-${this.id}`).apply(childCompiler);
|
121 | });
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | childCompiler.options.module = { ...childCompiler.options.module };
|
127 | childCompiler.options.module.parser = { ...childCompiler.options.module.parser };
|
128 | childCompiler.options.module.parser.javascript = { ...childCompiler.options.module.parser.javascript,
|
129 | url: 'relative' };
|
130 |
|
131 | this.compilationStartedTimestamp = new Date().getTime();
|
132 | this.compilationPromise = new Promise((resolve, reject) => {
|
133 | const extractedAssets = [];
|
134 | childCompiler.hooks.thisCompilation.tap('HtmlWebpackPlugin', (compilation) => {
|
135 | compilation.hooks.processAssets.tap(
|
136 | {
|
137 | name: 'HtmlWebpackPlugin',
|
138 | stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
139 | },
|
140 | (assets) => {
|
141 | temporaryTemplateNames.forEach((temporaryTemplateName) => {
|
142 | if (assets[temporaryTemplateName]) {
|
143 | extractedAssets.push(assets[temporaryTemplateName]);
|
144 | compilation.deleteAsset(temporaryTemplateName);
|
145 | }
|
146 | });
|
147 | }
|
148 | );
|
149 | });
|
150 |
|
151 | childCompiler.runAsChild((err, entries, childCompilation) => {
|
152 |
|
153 | const compiledTemplates = entries
|
154 | ? extractedAssets.map((asset) => asset.source())
|
155 | : [];
|
156 |
|
157 | if (entries && childCompilation) {
|
158 | this.fileDependencies = { fileDependencies: Array.from(childCompilation.fileDependencies), contextDependencies: Array.from(childCompilation.contextDependencies), missingDependencies: Array.from(childCompilation.missingDependencies) };
|
159 | }
|
160 |
|
161 | if (childCompilation && childCompilation.errors && childCompilation.errors.length) {
|
162 | const errorDetails = childCompilation.errors.map(error => {
|
163 | let message = error.message;
|
164 | if (error.stack) {
|
165 | message += '\n' + error.stack;
|
166 | }
|
167 | return message;
|
168 | }).join('\n');
|
169 | reject(new Error('Child compilation failed:\n' + errorDetails));
|
170 | return;
|
171 | }
|
172 |
|
173 | if (err) {
|
174 | reject(err);
|
175 | return;
|
176 | }
|
177 | if (!childCompilation || !entries) {
|
178 | reject(new Error('Empty child compilation'));
|
179 | return;
|
180 | }
|
181 | |
182 |
|
183 |
|
184 | const result = {};
|
185 | compiledTemplates.forEach((templateSource, entryIndex) => {
|
186 |
|
187 |
|
188 |
|
189 | result[this.templates[entryIndex]] = {
|
190 | content: templateSource,
|
191 | hash: childCompilation.hash || 'XXXX',
|
192 | entry: entries[entryIndex]
|
193 | };
|
194 | });
|
195 | this.compilationEndedTimestamp = new Date().getTime();
|
196 | resolve(result);
|
197 | });
|
198 | });
|
199 |
|
200 | return this.compilationPromise;
|
201 | }
|
202 | }
|
203 |
|
204 | module.exports = {
|
205 | HtmlWebpackChildCompiler
|
206 | };
|