source: imaps-frontend/node_modules/webpack/lib/runtime/GetChunkFilenameRuntimeModule.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 9.1 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3*/
4
5"use strict";
6
7const RuntimeGlobals = require("../RuntimeGlobals");
8const RuntimeModule = require("../RuntimeModule");
9const Template = require("../Template");
10const { first } = require("../util/SetHelpers");
11
12/** @typedef {import("../Chunk")} Chunk */
13/** @typedef {import("../ChunkGraph")} ChunkGraph */
14/** @typedef {import("../Compilation")} Compilation */
15/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
16/** @typedef {import("../TemplatedPathPlugin").TemplatePath} TemplatePath */
17
18class GetChunkFilenameRuntimeModule extends RuntimeModule {
19 /**
20 * @param {string} contentType the contentType to use the content hash for
21 * @param {string} name kind of filename
22 * @param {string} global function name to be assigned
23 * @param {function(Chunk): TemplatePath | false} getFilenameForChunk functor to get the filename or function
24 * @param {boolean} allChunks when false, only async chunks are included
25 */
26 constructor(contentType, name, global, getFilenameForChunk, allChunks) {
27 super(`get ${name} chunk filename`);
28 this.contentType = contentType;
29 this.global = global;
30 this.getFilenameForChunk = getFilenameForChunk;
31 this.allChunks = allChunks;
32 this.dependentHash = true;
33 }
34
35 /**
36 * @returns {string | null} runtime code
37 */
38 generate() {
39 const { global, contentType, getFilenameForChunk, allChunks } = this;
40 const compilation = /** @type {Compilation} */ (this.compilation);
41 const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
42 const chunk = /** @type {Chunk} */ (this.chunk);
43 const { runtimeTemplate } = compilation;
44
45 /** @type {Map<string | TemplatePath, Set<Chunk>>} */
46 const chunkFilenames = new Map();
47 let maxChunks = 0;
48 /** @type {string | undefined} */
49 let dynamicFilename;
50
51 /**
52 * @param {Chunk} c the chunk
53 * @returns {void}
54 */
55 const addChunk = c => {
56 const chunkFilename = getFilenameForChunk(c);
57 if (chunkFilename) {
58 let set = chunkFilenames.get(chunkFilename);
59 if (set === undefined) {
60 chunkFilenames.set(chunkFilename, (set = new Set()));
61 }
62 set.add(c);
63 if (typeof chunkFilename === "string") {
64 if (set.size < maxChunks) return;
65 if (set.size === maxChunks) {
66 if (
67 chunkFilename.length <
68 /** @type {string} */ (dynamicFilename).length
69 ) {
70 return;
71 }
72
73 if (
74 chunkFilename.length ===
75 /** @type {string} */ (dynamicFilename).length &&
76 chunkFilename < /** @type {string} */ (dynamicFilename)
77 ) {
78 return;
79 }
80 }
81 maxChunks = set.size;
82 dynamicFilename = chunkFilename;
83 }
84 }
85 };
86
87 /** @type {string[]} */
88 const includedChunksMessages = [];
89 if (allChunks) {
90 includedChunksMessages.push("all chunks");
91 for (const c of chunk.getAllReferencedChunks()) {
92 addChunk(c);
93 }
94 } else {
95 includedChunksMessages.push("async chunks");
96 for (const c of chunk.getAllAsyncChunks()) {
97 addChunk(c);
98 }
99 const includeEntries = chunkGraph
100 .getTreeRuntimeRequirements(chunk)
101 .has(RuntimeGlobals.ensureChunkIncludeEntries);
102 if (includeEntries) {
103 includedChunksMessages.push("sibling chunks for the entrypoint");
104 for (const c of chunkGraph.getChunkEntryDependentChunksIterable(
105 chunk
106 )) {
107 addChunk(c);
108 }
109 }
110 }
111 for (const entrypoint of chunk.getAllReferencedAsyncEntrypoints()) {
112 addChunk(entrypoint.chunks[entrypoint.chunks.length - 1]);
113 }
114
115 /** @type {Map<string, Set<string | number | null>>} */
116 const staticUrls = new Map();
117 /** @type {Set<Chunk>} */
118 const dynamicUrlChunks = new Set();
119
120 /**
121 * @param {Chunk} c the chunk
122 * @param {string | TemplatePath} chunkFilename the filename template for the chunk
123 * @returns {void}
124 */
125 const addStaticUrl = (c, chunkFilename) => {
126 /**
127 * @param {string | number} value a value
128 * @returns {string} string to put in quotes
129 */
130 const unquotedStringify = value => {
131 const str = `${value}`;
132 if (str.length >= 5 && str === `${c.id}`) {
133 // This is shorter and generates the same result
134 return '" + chunkId + "';
135 }
136 const s = JSON.stringify(str);
137 return s.slice(1, -1);
138 };
139 /**
140 * @param {string} value string
141 * @returns {function(number): string} string to put in quotes with length
142 */
143 const unquotedStringifyWithLength = value => length =>
144 unquotedStringify(`${value}`.slice(0, length));
145 const chunkFilenameValue =
146 typeof chunkFilename === "function"
147 ? JSON.stringify(
148 chunkFilename({
149 chunk: c,
150 contentHashType: contentType
151 })
152 )
153 : JSON.stringify(chunkFilename);
154 const staticChunkFilename = compilation.getPath(chunkFilenameValue, {
155 hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
156 hashWithLength: length =>
157 `" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
158 chunk: {
159 id: unquotedStringify(/** @type {number | string} */ (c.id)),
160 hash: unquotedStringify(/** @type {string} */ (c.renderedHash)),
161 hashWithLength: unquotedStringifyWithLength(
162 /** @type {string} */ (c.renderedHash)
163 ),
164 name: unquotedStringify(
165 c.name || /** @type {number | string} */ (c.id)
166 ),
167 contentHash: {
168 [contentType]: unquotedStringify(c.contentHash[contentType])
169 },
170 contentHashWithLength: {
171 [contentType]: unquotedStringifyWithLength(
172 c.contentHash[contentType]
173 )
174 }
175 },
176 contentHashType: contentType
177 });
178 let set = staticUrls.get(staticChunkFilename);
179 if (set === undefined) {
180 staticUrls.set(staticChunkFilename, (set = new Set()));
181 }
182 set.add(c.id);
183 };
184
185 for (const [filename, chunks] of chunkFilenames) {
186 if (filename !== dynamicFilename) {
187 for (const c of chunks) addStaticUrl(c, filename);
188 } else {
189 for (const c of chunks) dynamicUrlChunks.add(c);
190 }
191 }
192
193 /**
194 * @param {function(Chunk): string | number} fn function from chunk to value
195 * @returns {string} code with static mapping of results of fn
196 */
197 const createMap = fn => {
198 /** @type {Record<number | string, number | string>} */
199 const obj = {};
200 let useId = false;
201 /** @type {number | string | undefined} */
202 let lastKey;
203 let entries = 0;
204 for (const c of dynamicUrlChunks) {
205 const value = fn(c);
206 if (value === c.id) {
207 useId = true;
208 } else {
209 obj[/** @type {number | string} */ (c.id)] = value;
210 lastKey = /** @type {number | string} */ (c.id);
211 entries++;
212 }
213 }
214 if (entries === 0) return "chunkId";
215 if (entries === 1) {
216 return useId
217 ? `(chunkId === ${JSON.stringify(lastKey)} ? ${JSON.stringify(
218 obj[/** @type {number | string} */ (lastKey)]
219 )} : chunkId)`
220 : JSON.stringify(obj[/** @type {number | string} */ (lastKey)]);
221 }
222 return useId
223 ? `(${JSON.stringify(obj)}[chunkId] || chunkId)`
224 : `${JSON.stringify(obj)}[chunkId]`;
225 };
226
227 /**
228 * @param {function(Chunk): string | number} fn function from chunk to value
229 * @returns {string} code with static mapping of results of fn for including in quoted string
230 */
231 const mapExpr = fn => `" + ${createMap(fn)} + "`;
232
233 /**
234 * @param {function(Chunk): string | number} fn function from chunk to value
235 * @returns {function(number): string} function which generates code with static mapping of results of fn for including in quoted string for specific length
236 */
237 const mapExprWithLength = fn => length =>
238 `" + ${createMap(c => `${fn(c)}`.slice(0, length))} + "`;
239
240 const url =
241 dynamicFilename &&
242 compilation.getPath(JSON.stringify(dynamicFilename), {
243 hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
244 hashWithLength: length =>
245 `" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
246 chunk: {
247 id: '" + chunkId + "',
248 hash: mapExpr(c => /** @type {string} */ (c.renderedHash)),
249 hashWithLength: mapExprWithLength(
250 c => /** @type {string} */ (c.renderedHash)
251 ),
252 name: mapExpr(c => c.name || /** @type {number | string} */ (c.id)),
253 contentHash: {
254 [contentType]: mapExpr(c => c.contentHash[contentType])
255 },
256 contentHashWithLength: {
257 [contentType]: mapExprWithLength(c => c.contentHash[contentType])
258 }
259 },
260 contentHashType: contentType
261 });
262
263 return Template.asString([
264 `// This function allow to reference ${includedChunksMessages.join(
265 " and "
266 )}`,
267 `${global} = ${runtimeTemplate.basicFunction(
268 "chunkId",
269
270 staticUrls.size > 0
271 ? [
272 "// return url for filenames not based on template",
273 // it minimizes to `x===1?"...":x===2?"...":"..."`
274 Template.asString(
275 Array.from(staticUrls, ([url, ids]) => {
276 const condition =
277 ids.size === 1
278 ? `chunkId === ${JSON.stringify(first(ids))}`
279 : `{${Array.from(
280 ids,
281 id => `${JSON.stringify(id)}:1`
282 ).join(",")}}[chunkId]`;
283 return `if (${condition}) return ${url};`;
284 })
285 ),
286 "// return url for filenames based on template",
287 `return ${url};`
288 ]
289 : ["// return url for filenames based on template", `return ${url};`]
290 )};`
291 ]);
292 }
293}
294
295module.exports = GetChunkFilenameRuntimeModule;
Note: See TracBrowser for help on using the repository browser.