source: frontend/node_modules/webpack/lib/ManifestPlugin.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: 6.8 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Haijie Xie @hai-x
4*/
5
6"use strict";
7
8const { RawSource } = require("webpack-sources");
9const Compilation = require("./Compilation");
10const HotUpdateChunk = require("./HotUpdateChunk");
11
12/** @typedef {import("./Compiler")} Compiler */
13/** @typedef {import("./Chunk")} Chunk */
14/** @typedef {import("./Chunk").ChunkName} ChunkName */
15/** @typedef {import("./Chunk").ChunkId} ChunkId */
16/** @typedef {import("./Compilation").Asset} Asset */
17/** @typedef {import("./Compilation").AssetInfo} AssetInfo */
18
19/** @typedef {import("../declarations/plugins/ManifestPlugin").ManifestPluginOptions} ManifestPluginOptions */
20/** @typedef {import("../declarations/plugins/ManifestPlugin").ManifestObject} ManifestObject */
21/** @typedef {import("../declarations/plugins/ManifestPlugin").ManifestEntrypoint} ManifestEntrypoint */
22/** @typedef {import("../declarations/plugins/ManifestPlugin").ManifestItem} ManifestItem */
23
24/** @typedef {(item: ManifestItem) => boolean} Filter */
25/** @typedef {(manifest: ManifestObject) => ManifestObject} Generate */
26/** @typedef {(manifest: ManifestObject) => string} Serialize */
27
28const PLUGIN_NAME = "ManifestPlugin";
29
30/**
31 * Returns extname.
32 * @param {string} filename filename
33 * @returns {string} extname
34 */
35const extname = (filename) => {
36 const replaced = filename.replace(/\?.*/, "");
37 const split = replaced.split(".");
38 const last = split.pop();
39 if (!last) return "";
40 return last && /^(?:gz|br|map)$/i.test(last)
41 ? `${split.pop()}.${last}`
42 : last;
43};
44
45const DEFAULT_PREFIX = "[publicpath]";
46const DEFAULT_FILENAME = "manifest.json";
47
48class ManifestPlugin {
49 /**
50 * Creates an instance of ManifestPlugin.
51 * @param {ManifestPluginOptions} options options
52 */
53 constructor(options = {}) {
54 /** @type {ManifestPluginOptions} */
55 this.options = options;
56 }
57
58 /**
59 * Applies the plugin by registering its hooks on the compiler.
60 * @param {Compiler} compiler the compiler instance
61 * @returns {void}
62 */
63 apply(compiler) {
64 compiler.hooks.validate.tap(PLUGIN_NAME, () => {
65 compiler.validate(
66 () => require("../schemas/plugins/ManifestPlugin.json"),
67 this.options,
68 {
69 name: "ManifestPlugin",
70 baseDataPath: "options"
71 },
72 (options) => require("../schemas/plugins/ManifestPlugin.check")(options)
73 );
74 });
75
76 const entrypoints =
77 this.options.entrypoints !== undefined ? this.options.entrypoints : true;
78 const serialize =
79 this.options.serialize ||
80 ((manifest) => JSON.stringify(manifest, null, 2));
81
82 compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
83 compilation.hooks.processAssets.tap(
84 {
85 name: PLUGIN_NAME,
86 stage: Compilation.PROCESS_ASSETS_STAGE_SUMMARIZE
87 },
88 () => {
89 const hashDigestLength = compilation.outputOptions.hashDigestLength;
90 const publicPath = compilation.getPath(
91 compilation.outputOptions.publicPath
92 );
93
94 /**
95 * Creates a hash reg exp.
96 * @param {string | string[]} value value
97 * @returns {RegExp} regexp to remove hash
98 */
99 const createHashRegExp = (value) =>
100 new RegExp(
101 `(?:\\.${Array.isArray(value) ? `(${value.join("|")})` : value})(?=\\.)`,
102 "gi"
103 );
104
105 /**
106 * Removes the provided name from the manifest plugin.
107 * @param {string} name name
108 * @param {AssetInfo | null} info asset info
109 * @returns {string} hash removed name
110 */
111 const removeHash = (name, info) => {
112 // Handles hashes that match configured `hashDigestLength`
113 // i.e. index.XXXX.html -> index.html (html-webpack-plugin)
114 if (hashDigestLength <= 0) return name;
115 const reg = createHashRegExp(`[a-f0-9]{${hashDigestLength},32}`);
116 return name.replace(reg, "");
117 };
118
119 /**
120 * Returns chunk name or chunk id.
121 * @param {Chunk} chunk chunk
122 * @returns {ChunkName | ChunkId} chunk name or chunk id
123 */
124 const getName = (chunk) => {
125 if (chunk.name) return chunk.name;
126
127 return chunk.id;
128 };
129
130 /** @type {ManifestObject} */
131 let manifest = {};
132
133 if (entrypoints) {
134 /** @type {ManifestObject["entrypoints"]} */
135 const entrypoints = {};
136
137 for (const [name, entrypoint] of compilation.entrypoints) {
138 /** @type {string[]} */
139 const imports = [];
140
141 for (const chunk of entrypoint.chunks) {
142 for (const file of chunk.files) {
143 const name = getName(chunk);
144
145 imports.push(name ? `${name}.${extname(file)}` : file);
146 }
147 }
148
149 /** @type {ManifestEntrypoint} */
150 const item = { imports };
151 const parents = entrypoint
152 .getParents()
153 .map((item) => /** @type {string} */ (item.name));
154
155 if (parents.length > 0) {
156 item.parents = parents;
157 }
158
159 entrypoints[name] = item;
160 }
161
162 manifest.entrypoints = entrypoints;
163 }
164
165 /** @type {ManifestObject["assets"]} */
166 const assets = {};
167
168 /** @type {Set<string>} */
169 const added = new Set();
170
171 /**
172 * Processes the provided file.
173 * @param {string} file file
174 * @param {string=} usedName usedName
175 * @returns {void}
176 */
177 const handleFile = (file, usedName) => {
178 if (added.has(file)) return;
179 added.add(file);
180
181 const asset = compilation.getAsset(file);
182 if (!asset) return;
183 const sourceFilename = asset.info.sourceFilename;
184 const name =
185 usedName ||
186 sourceFilename ||
187 // Fallback for unofficial plugins, just remove hash from filename
188 removeHash(file, asset.info);
189
190 const prefix = (this.options.prefix || DEFAULT_PREFIX).replace(
191 /\[publicpath\]/gi,
192 () => (publicPath === "auto" ? "/" : publicPath)
193 );
194 /** @type {ManifestItem} */
195 const item = { file: prefix + file };
196
197 if (sourceFilename) {
198 item.src = sourceFilename;
199 }
200
201 if (this.options.filter) {
202 const needKeep = this.options.filter(item);
203
204 if (!needKeep) {
205 return;
206 }
207 }
208
209 assets[name] = item;
210 };
211
212 for (const chunk of compilation.chunks) {
213 if (chunk instanceof HotUpdateChunk) continue;
214
215 for (const auxiliaryFile of chunk.auxiliaryFiles) {
216 handleFile(auxiliaryFile);
217 }
218
219 const name = getName(chunk);
220
221 for (const file of chunk.files) {
222 handleFile(file, name ? `${name}.${extname(file)}` : file);
223 }
224 }
225
226 for (const asset of compilation.getAssets()) {
227 if (asset.info.hotModuleReplacement) {
228 continue;
229 }
230
231 handleFile(asset.name);
232 }
233
234 manifest.assets = assets;
235
236 if (this.options.generate) {
237 manifest = this.options.generate(manifest);
238 }
239
240 compilation.emitAsset(
241 this.options.filename || DEFAULT_FILENAME,
242 new RawSource(serialize(manifest)),
243 { manifest: true }
244 );
245 }
246 );
247 });
248 }
249}
250
251module.exports = ManifestPlugin;
Note: See TracBrowser for help on using the repository browser.