source: frontend/node_modules/webpack/lib/asset/AssetModulesPlugin.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Yuta Hiroto @hiroppy
4*/
5
6"use strict";
7
8const {
9 ASSET_MODULE_TYPE,
10 ASSET_MODULE_TYPE_BYTES,
11 ASSET_MODULE_TYPE_INLINE,
12 ASSET_MODULE_TYPE_RESOURCE,
13 ASSET_MODULE_TYPE_SOURCE
14} = require("../ModuleTypeConstants");
15const { compareModulesByFullName } = require("../util/comparators");
16const memoize = require("../util/memoize");
17
18/** @typedef {import("webpack-sources").Source} Source */
19/** @typedef {import("schema-utils").Schema} Schema */
20/** @typedef {import("../../declarations/WebpackOptions").AssetGeneratorDataUrl} AssetGeneratorDataUrl */
21/** @typedef {import("../../declarations/WebpackOptions").AssetModuleOutputPath} AssetModuleOutputPath */
22/** @typedef {import("../../declarations/WebpackOptions").RawPublicPath} RawPublicPath */
23/** @typedef {import("../../declarations/WebpackOptions").AssetModuleFilename} AssetModuleFilename */
24/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
25/** @typedef {import("../Compiler")} Compiler */
26/** @typedef {import("../Module").BuildInfo} BuildInfo */
27/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
28/** @typedef {import("../NormalModule")} NormalModule */
29
30/**
31 * Returns definition.
32 * @param {string} name name of definitions
33 * @returns {Schema} definition
34 */
35const getSchema = (name) => {
36 const { definitions } =
37 /** @type {EXPECTED_ANY} */
38 (require("../../schemas/WebpackOptions.json"));
39
40 return {
41 definitions,
42 oneOf: [{ $ref: `#/definitions/${name}` }]
43 };
44};
45
46const generatorValidationOptions = {
47 name: "Asset Modules Plugin",
48 baseDataPath: "generator"
49};
50
51const getAssetGenerator = memoize(() => require("./AssetGenerator"));
52const getAssetParser = memoize(() => require("./AssetParser"));
53const getAssetSourceParser = memoize(() => require("./AssetSourceParser"));
54const getAssetBytesParser = memoize(() => require("./AssetBytesParser"));
55const getAssetSourceGenerator = memoize(() =>
56 require("./AssetSourceGenerator")
57);
58const getAssetBytesGenerator = memoize(() => require("./AssetBytesGenerator"));
59const getNormalModule = memoize(() => require("../NormalModule"));
60
61const type = ASSET_MODULE_TYPE;
62const PLUGIN_NAME = "AssetModulesPlugin";
63
64/**
65 * Represents the asset modules plugin runtime component.
66 * @typedef {object} AssetModulesPluginOptions
67 * @property {boolean=} sideEffectFree
68 */
69
70class AssetModulesPlugin {
71 /**
72 * Creates an instance of AssetModulesPlugin.
73 * @param {AssetModulesPluginOptions} options options
74 */
75 constructor(options) {
76 this.options = options;
77 }
78
79 /**
80 * Applies the plugin by registering its hooks on the compiler.
81 * @param {Compiler} compiler the compiler instance
82 * @returns {void}
83 */
84 apply(compiler) {
85 compiler.hooks.compilation.tap(
86 PLUGIN_NAME,
87 (compilation, { normalModuleFactory }) => {
88 const NormalModule = getNormalModule();
89 for (const type of [
90 ASSET_MODULE_TYPE,
91 ASSET_MODULE_TYPE_BYTES,
92 ASSET_MODULE_TYPE_INLINE,
93 ASSET_MODULE_TYPE_RESOURCE,
94 ASSET_MODULE_TYPE_SOURCE
95 ]) {
96 normalModuleFactory.hooks.createModuleClass
97 .for(type)
98 .tap(PLUGIN_NAME, (createData, _resolveData) => {
99 // TODO create the module via new AssetModule with its own properties
100 const module = new NormalModule(createData);
101 if (this.options.sideEffectFree) {
102 module.factoryMeta = { sideEffectFree: true };
103 }
104
105 return module;
106 });
107 }
108
109 normalModuleFactory.hooks.createParser
110 .for(ASSET_MODULE_TYPE)
111 .tap(PLUGIN_NAME, (parserOptions) => {
112 compiler.validate(
113 () => getSchema("AssetParserOptions"),
114 parserOptions,
115 {
116 name: "Asset Modules Plugin",
117 baseDataPath: "parser"
118 },
119 (options) =>
120 require("../../schemas/plugins/asset/AssetParserOptions.check")(
121 options
122 )
123 );
124
125 let dataUrlCondition = parserOptions.dataUrlCondition;
126 if (!dataUrlCondition || typeof dataUrlCondition === "object") {
127 dataUrlCondition = {
128 maxSize: 8096,
129 ...dataUrlCondition
130 };
131 }
132
133 const AssetParser = getAssetParser();
134
135 return new AssetParser(dataUrlCondition);
136 });
137 normalModuleFactory.hooks.createParser
138 .for(ASSET_MODULE_TYPE_INLINE)
139 .tap(PLUGIN_NAME, (_parserOptions) => {
140 const AssetParser = getAssetParser();
141
142 return new AssetParser(true);
143 });
144 normalModuleFactory.hooks.createParser
145 .for(ASSET_MODULE_TYPE_RESOURCE)
146 .tap(PLUGIN_NAME, (_parserOptions) => {
147 const AssetParser = getAssetParser();
148
149 return new AssetParser(false);
150 });
151 normalModuleFactory.hooks.createParser
152 .for(ASSET_MODULE_TYPE_SOURCE)
153 .tap(PLUGIN_NAME, (_parserOptions) => {
154 const AssetSourceParser = getAssetSourceParser();
155
156 return new AssetSourceParser();
157 });
158 normalModuleFactory.hooks.createParser
159 .for(ASSET_MODULE_TYPE_BYTES)
160 .tap(PLUGIN_NAME, (_parserOptions) => {
161 const AssetBytesParser = getAssetBytesParser();
162
163 return new AssetBytesParser();
164 });
165
166 for (const type of [
167 ASSET_MODULE_TYPE,
168 ASSET_MODULE_TYPE_INLINE,
169 ASSET_MODULE_TYPE_RESOURCE
170 ]) {
171 normalModuleFactory.hooks.createGenerator
172 .for(type)
173 .tap(PLUGIN_NAME, (generatorOptions) => {
174 switch (type) {
175 case ASSET_MODULE_TYPE: {
176 compiler.validate(
177 () => getSchema("AssetGeneratorOptions"),
178 generatorOptions,
179 generatorValidationOptions,
180 (options) =>
181 require("../../schemas/plugins/asset/AssetGeneratorOptions.check")(
182 options
183 )
184 );
185 break;
186 }
187 case ASSET_MODULE_TYPE_RESOURCE: {
188 compiler.validate(
189 () => getSchema("AssetResourceGeneratorOptions"),
190 generatorOptions,
191 generatorValidationOptions,
192 (options) =>
193 require("../../schemas/plugins/asset/AssetResourceGeneratorOptions.check")(
194 options
195 )
196 );
197 break;
198 }
199 case ASSET_MODULE_TYPE_INLINE: {
200 compiler.validate(
201 () => getSchema("AssetInlineGeneratorOptions"),
202 generatorOptions,
203 generatorValidationOptions,
204 (options) =>
205 require("../../schemas/plugins/asset/AssetInlineGeneratorOptions.check")(
206 options
207 )
208 );
209 break;
210 }
211 }
212
213 /** @type {undefined | AssetGeneratorDataUrl} */
214 let dataUrl;
215 if (type !== ASSET_MODULE_TYPE_RESOURCE) {
216 dataUrl = generatorOptions.dataUrl;
217 if (!dataUrl || typeof dataUrl === "object") {
218 dataUrl = {
219 encoding: undefined,
220 mimetype: undefined,
221 ...dataUrl
222 };
223 }
224 }
225
226 /** @type {undefined | AssetModuleFilename} */
227 let filename;
228 /** @type {undefined | RawPublicPath} */
229 let publicPath;
230 /** @type {undefined | AssetModuleOutputPath} */
231 let outputPath;
232 if (type !== ASSET_MODULE_TYPE_INLINE) {
233 filename = generatorOptions.filename;
234 publicPath = generatorOptions.publicPath;
235 outputPath = generatorOptions.outputPath;
236 }
237
238 const AssetGenerator = getAssetGenerator();
239
240 return new AssetGenerator(
241 compilation.moduleGraph,
242 dataUrl,
243 filename,
244 publicPath,
245 outputPath,
246 generatorOptions.emit !== false
247 );
248 });
249 }
250 normalModuleFactory.hooks.createGenerator
251 .for(ASSET_MODULE_TYPE_SOURCE)
252 .tap(PLUGIN_NAME, () => {
253 const AssetSourceGenerator = getAssetSourceGenerator();
254
255 return new AssetSourceGenerator(compilation.moduleGraph);
256 });
257
258 normalModuleFactory.hooks.createGenerator
259 .for(ASSET_MODULE_TYPE_BYTES)
260 .tap(PLUGIN_NAME, () => {
261 const AssetBytesGenerator = getAssetBytesGenerator();
262
263 return new AssetBytesGenerator(compilation.moduleGraph);
264 });
265
266 compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
267 const { chunkGraph } = compilation;
268 const { chunk, codeGenerationResults, runtimeTemplate } = options;
269
270 const modules = chunkGraph.getOrderedChunkModulesIterableBySourceType(
271 chunk,
272 ASSET_MODULE_TYPE,
273 compareModulesByFullName(compilation.compiler)
274 );
275 if (modules) {
276 for (const module of modules) {
277 try {
278 const codeGenResult = codeGenerationResults.get(
279 module,
280 chunk.runtime
281 );
282 const buildInfo = /** @type {BuildInfo} */ (module.buildInfo);
283 const data =
284 /** @type {NonNullable<CodeGenerationResult["data"]>} */
285 (codeGenResult.data);
286 const errored = module.getNumberOfErrors() > 0;
287
288 /** @type {string} */
289 let entryFilename;
290 /** @type {AssetInfo} */
291 let entryInfo;
292 /** @type {string} */
293 let entryHash;
294
295 if (errored) {
296 const erroredModule = /** @type {NormalModule} */ (module);
297 const AssetGenerator = getAssetGenerator();
298 const [fullContentHash, contentHash] =
299 AssetGenerator.getFullContentHash(
300 erroredModule,
301 runtimeTemplate
302 );
303 const { filename, assetInfo } =
304 AssetGenerator.getFilenameWithInfo(
305 erroredModule,
306 {
307 filename:
308 erroredModule.generatorOptions &&
309 erroredModule.generatorOptions.filename,
310 outputPath:
311 erroredModule.generatorOptions &&
312 erroredModule.generatorOptions.outputPath
313 },
314 {
315 runtime: chunk.runtime,
316 runtimeTemplate,
317 chunkGraph
318 },
319 contentHash
320 );
321 entryFilename = filename;
322 entryInfo = assetInfo;
323 entryHash = fullContentHash;
324 } else {
325 entryFilename =
326 /** @type {string} */
327 (buildInfo.filename || data.get("filename"));
328 entryInfo =
329 /** @type {AssetInfo} */
330 (buildInfo.assetInfo || data.get("assetInfo"));
331 entryHash =
332 /** @type {string} */
333 (buildInfo.fullContentHash || data.get("fullContentHash"));
334 }
335
336 result.push({
337 render: () =>
338 /** @type {Source} */ (codeGenResult.sources.get(type)),
339 filename: entryFilename,
340 info: entryInfo,
341 auxiliary: true,
342 identifier: `assetModule${chunkGraph.getModuleId(module)}`,
343 hash: entryHash
344 });
345 } catch (err) {
346 /** @type {Error} */ (err).message +=
347 `\nduring rendering of asset ${module.identifier()}`;
348 throw err;
349 }
350 }
351 }
352
353 return result;
354 });
355
356 compilation.hooks.prepareModuleExecution.tap(
357 PLUGIN_NAME,
358 (options, context) => {
359 const { codeGenerationResult } = options;
360 const source = codeGenerationResult.sources.get(ASSET_MODULE_TYPE);
361 if (source === undefined) return;
362 const data =
363 /** @type {NonNullable<CodeGenerationResult["data"]>} */
364 (codeGenerationResult.data);
365 context.assets.set(
366 /** @type {string} */
367 (data.get("filename")),
368 {
369 source,
370 info: data.get("assetInfo")
371 }
372 );
373 }
374 );
375 }
376 );
377 }
378}
379
380module.exports = AssetModulesPlugin;
Note: See TracBrowser for help on using the repository browser.