source: frontend/node_modules/webpack/lib/ModuleInfoHeaderPlugin.js

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

Fix frontend appearance

  • Property mode set to 100644
File size: 9.1 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { CachedSource, ConcatSource, RawSource } = require("webpack-sources");
9const { UsageState } = require("./ExportsInfo");
10const Template = require("./Template");
11const CssModulesPlugin = require("./css/CssModulesPlugin");
12const JavascriptModulesPlugin = require("./javascript/JavascriptModulesPlugin");
13
14/** @typedef {import("webpack-sources").Source} Source */
15/** @typedef {import("./Compiler")} Compiler */
16/** @typedef {import("./ExportsInfo")} ExportsInfo */
17/** @typedef {import("./ExportsInfo").ExportInfo} ExportInfo */
18/** @typedef {import("./Module")} Module */
19/** @typedef {import("./Module").BuildMeta} BuildMeta */
20/** @typedef {import("./ModuleGraph")} ModuleGraph */
21/** @typedef {import("./RequestShortener")} RequestShortener */
22
23/**
24 * Join iterable with comma.
25 * @template T
26 * @param {Iterable<T>} iterable iterable
27 * @returns {string} joined with comma
28 */
29const joinIterableWithComma = (iterable) => {
30 // This is more performant than Array.from().join(", ")
31 // as it doesn't create an array
32 let str = "";
33 let first = true;
34 for (const item of iterable) {
35 if (first) {
36 first = false;
37 } else {
38 str += ", ";
39 }
40 str += item;
41 }
42 return str;
43};
44
45/**
46 * Print exports info to source.
47 * @param {ConcatSource} source output
48 * @param {string} indent spacing
49 * @param {ExportsInfo} exportsInfo data
50 * @param {ModuleGraph} moduleGraph moduleGraph
51 * @param {RequestShortener} requestShortener requestShortener
52 * @param {Set<ExportInfo>} alreadyPrinted deduplication set
53 * @returns {void}
54 */
55const printExportsInfoToSource = (
56 source,
57 indent,
58 exportsInfo,
59 moduleGraph,
60 requestShortener,
61 alreadyPrinted = new Set()
62) => {
63 const otherExportsInfo = exportsInfo.otherExportsInfo;
64
65 let alreadyPrintedExports = 0;
66
67 // determine exports to print
68 /** @type {ExportInfo[]} */
69 const printedExports = [];
70 for (const exportInfo of exportsInfo.orderedExports) {
71 if (!alreadyPrinted.has(exportInfo)) {
72 alreadyPrinted.add(exportInfo);
73 printedExports.push(exportInfo);
74 } else {
75 alreadyPrintedExports++;
76 }
77 }
78 let showOtherExports = false;
79 if (!alreadyPrinted.has(otherExportsInfo)) {
80 alreadyPrinted.add(otherExportsInfo);
81 showOtherExports = true;
82 } else {
83 alreadyPrintedExports++;
84 }
85
86 // print the exports
87 for (const exportInfo of printedExports) {
88 const target = exportInfo.getTarget(moduleGraph);
89 source.add(
90 `${Template.toComment(
91 `${indent}export ${JSON.stringify(exportInfo.name).slice(
92 1,
93 -1
94 )} [${exportInfo.getProvidedInfo()}] [${exportInfo.getUsedInfo()}] [${exportInfo.getRenameInfo()}]${
95 target
96 ? ` -> ${target.module.readableIdentifier(requestShortener)}${
97 target.export
98 ? ` .${target.export
99 .map((e) => JSON.stringify(e).slice(1, -1))
100 .join(".")}`
101 : ""
102 }`
103 : ""
104 }`
105 )}\n`
106 );
107 if (exportInfo.exportsInfo) {
108 printExportsInfoToSource(
109 source,
110 `${indent} `,
111 exportInfo.exportsInfo,
112 moduleGraph,
113 requestShortener,
114 alreadyPrinted
115 );
116 }
117 }
118
119 if (alreadyPrintedExports) {
120 source.add(
121 `${Template.toComment(
122 `${indent}... (${alreadyPrintedExports} already listed exports)`
123 )}\n`
124 );
125 }
126
127 if (showOtherExports) {
128 const target = otherExportsInfo.getTarget(moduleGraph);
129 if (
130 target ||
131 otherExportsInfo.provided !== false ||
132 otherExportsInfo.getUsed(undefined) !== UsageState.Unused
133 ) {
134 const title =
135 printedExports.length > 0 || alreadyPrintedExports > 0
136 ? "other exports"
137 : "exports";
138 source.add(
139 `${Template.toComment(
140 `${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]${
141 target
142 ? ` -> ${target.module.readableIdentifier(requestShortener)}`
143 : ""
144 }`
145 )}\n`
146 );
147 }
148 }
149};
150
151/** @typedef {{ header: RawSource | undefined, full: WeakMap<Source, CachedSource> }} CacheEntry */
152/** @type {WeakMap<RequestShortener, WeakMap<Module, CacheEntry>>} */
153const caches = new WeakMap();
154
155const PLUGIN_NAME = "ModuleInfoHeaderPlugin";
156
157class ModuleInfoHeaderPlugin {
158 /**
159 * Creates an instance of ModuleInfoHeaderPlugin.
160 * @param {boolean=} verbose add more information like exports, runtime requirements and bailouts
161 */
162 constructor(verbose = true) {
163 /** @type {boolean} */
164 this._verbose = verbose;
165 }
166
167 /**
168 * Applies the plugin by registering its hooks on the compiler.
169 * @param {Compiler} compiler the compiler
170 * @returns {void}
171 */
172 apply(compiler) {
173 const { _verbose: verbose } = this;
174 compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
175 const javascriptHooks =
176 JavascriptModulesPlugin.getCompilationHooks(compilation);
177 javascriptHooks.renderModulePackage.tap(
178 PLUGIN_NAME,
179 (
180 moduleSource,
181 module,
182 { chunk, chunkGraph, moduleGraph, runtimeTemplate }
183 ) => {
184 const { requestShortener } = runtimeTemplate;
185 /** @type {undefined | CacheEntry} */
186 let cacheEntry;
187 let cache = caches.get(requestShortener);
188 if (cache === undefined) {
189 caches.set(requestShortener, (cache = new WeakMap()));
190 cache.set(
191 module,
192 (cacheEntry = { header: undefined, full: new WeakMap() })
193 );
194 } else {
195 cacheEntry = cache.get(module);
196 if (cacheEntry === undefined) {
197 cache.set(
198 module,
199 (cacheEntry = { header: undefined, full: new WeakMap() })
200 );
201 } else if (!verbose) {
202 const cachedSource = cacheEntry.full.get(moduleSource);
203 if (cachedSource !== undefined) return cachedSource;
204 }
205 }
206 const source = new ConcatSource();
207 let header = cacheEntry.header;
208 if (header === undefined) {
209 header = this.generateHeader(module, requestShortener);
210 cacheEntry.header = header;
211 }
212 source.add(header);
213 if (verbose) {
214 const exportsType = /** @type {BuildMeta} */ (module.buildMeta)
215 .exportsType;
216 source.add(
217 `${Template.toComment(
218 exportsType
219 ? `${exportsType} exports`
220 : "unknown exports (runtime-defined)"
221 )}\n`
222 );
223 if (exportsType) {
224 const exportsInfo = moduleGraph.getExportsInfo(module);
225 printExportsInfoToSource(
226 source,
227 "",
228 exportsInfo,
229 moduleGraph,
230 requestShortener
231 );
232 }
233 source.add(
234 `${Template.toComment(
235 `runtime requirements: ${joinIterableWithComma(
236 chunkGraph.getModuleRuntimeRequirements(module, chunk.runtime)
237 )}`
238 )}\n`
239 );
240 const optimizationBailout =
241 moduleGraph.getOptimizationBailout(module);
242 if (optimizationBailout) {
243 for (const text of optimizationBailout) {
244 const code =
245 typeof text === "function" ? text(requestShortener) : text;
246 source.add(`${Template.toComment(`${code}`)}\n`);
247 }
248 }
249 source.add(moduleSource);
250 return source;
251 }
252 source.add(moduleSource);
253 const cachedSource = new CachedSource(source);
254 cacheEntry.full.set(moduleSource, cachedSource);
255 return cachedSource;
256 }
257 );
258 javascriptHooks.chunkHash.tap(PLUGIN_NAME, (_chunk, hash) => {
259 hash.update(PLUGIN_NAME);
260 hash.update("1");
261 });
262 const cssHooks = CssModulesPlugin.getCompilationHooks(compilation);
263 cssHooks.renderModulePackage.tap(
264 PLUGIN_NAME,
265 (moduleSource, module, { runtimeTemplate }) => {
266 const { requestShortener } = runtimeTemplate;
267 /** @type {undefined | CacheEntry} */
268 let cacheEntry;
269 let cache = caches.get(requestShortener);
270 if (cache === undefined) {
271 caches.set(requestShortener, (cache = new WeakMap()));
272 cache.set(
273 module,
274 (cacheEntry = { header: undefined, full: new WeakMap() })
275 );
276 } else {
277 cacheEntry = cache.get(module);
278 if (cacheEntry === undefined) {
279 cache.set(
280 module,
281 (cacheEntry = { header: undefined, full: new WeakMap() })
282 );
283 } else if (!verbose) {
284 const cachedSource = cacheEntry.full.get(moduleSource);
285 if (cachedSource !== undefined) return cachedSource;
286 }
287 }
288 const source = new ConcatSource();
289 let header = cacheEntry.header;
290 if (header === undefined) {
291 header = this.generateHeader(module, requestShortener);
292 cacheEntry.header = header;
293 }
294 source.add(header);
295 source.add(moduleSource);
296 const cachedSource = new CachedSource(source);
297 cacheEntry.full.set(moduleSource, cachedSource);
298 return cachedSource;
299 }
300 );
301 cssHooks.chunkHash.tap(PLUGIN_NAME, (_chunk, hash) => {
302 hash.update(PLUGIN_NAME);
303 hash.update("1");
304 });
305 });
306 }
307
308 /**
309 * Returns the header.
310 * @param {Module} module the module
311 * @param {RequestShortener} requestShortener request shortener
312 * @returns {RawSource} the header
313 */
314 generateHeader(module, requestShortener) {
315 const req = module.readableIdentifier(requestShortener);
316 const reqStr = req.replace(/\*\//g, "*_/");
317 const reqStrStar = "*".repeat(reqStr.length);
318 const headerStr = `/*!****${reqStrStar}****!*\\\n !*** ${reqStr} ***!\n \\****${reqStrStar}****/\n`;
319 return new RawSource(headerStr);
320 }
321}
322
323module.exports = ModuleInfoHeaderPlugin;
Note: See TracBrowser for help on using the repository browser.