source: frontend/node_modules/mini-css-extract-plugin/dist/loader.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: 14.7 KB
Line 
1"use strict";
2
3const path = require("path");
4const schema = require("./loader-options.json");
5const {
6 ABSOLUTE_PUBLIC_PATH,
7 AUTO_PUBLIC_PATH,
8 BASE_URI,
9 SINGLE_DOT_PATH_SEGMENT,
10 evalModuleCode,
11 findModuleById,
12 stringifyLocal,
13 stringifyRequest
14} = require("./utils");
15const MiniCssExtractPlugin = require("./index");
16
17/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
18/** @typedef {import("webpack").Compiler} Compiler */
19/** @typedef {import("webpack").Compilation} Compilation */
20/** @typedef {import("webpack").Chunk} Chunk */
21/** @typedef {import("webpack").Module} Module */
22/** @typedef {import("webpack").sources.Source} Source */
23/** @typedef {import("webpack").AssetInfo} AssetInfo */
24/** @typedef {import("webpack").NormalModule} NormalModule */
25/** @typedef {import("./index.js").LoaderOptions} LoaderOptions */
26
27// eslint-disable-next-line jsdoc/reject-function-type
28/** @typedef {{ [key: string]: string | Function }} Locals */
29
30// eslint-disable-next-line jsdoc/reject-any-type
31/** @typedef {any} EXPECTED_ANY */
32
33/**
34 * @typedef {object} Dependency
35 * @property {string} identifier identifier
36 * @property {string | null} context context
37 * @property {Buffer} content content
38 * @property {string=} media media
39 * @property {string=} supports supports
40 * @property {string=} layer layer
41 * @property {Buffer=} sourceMap source map
42 */
43
44/**
45 * @param {string} code code
46 * @param {{ loaderContext: import("webpack").LoaderContext<LoaderOptions>, options: LoaderOptions, locals: Locals | undefined }} context context
47 * @returns {string} code and HMR code
48 */
49function hotLoader(code, context) {
50 const localsJsonString = JSON.stringify(JSON.stringify(context.locals));
51 return `${code}
52 if(module.hot) {
53 (function() {
54 var localsJsonString = ${localsJsonString};
55 // ${Date.now()}
56 var cssReload = require(${stringifyRequest(context.loaderContext, path.join(__dirname, "hmr/hotModuleReplacement.js"))})(module.id, ${JSON.stringify(context.options)});
57 // only invalidate when locals change
58 if (
59 module.hot.data &&
60 module.hot.data.value &&
61 module.hot.data.value !== localsJsonString
62 ) {
63 module.hot.invalidate();
64 } else {
65 module.hot.accept();
66 }
67 module.hot.dispose(function(data) {
68 data.value = localsJsonString;
69 cssReload();
70 });
71 })();
72 }
73 `;
74}
75
76/**
77 * @this {import("webpack").LoaderContext<LoaderOptions>}
78 * @param {string} request request
79 */
80function pitch(request) {
81 if (this._compiler && this._compiler.options && this._compiler.options.experiments && this._compiler.options.experiments.css && this._module && (this._module.type === "css" || this._module.type === "css/auto" || this._module.type === "css/global" || this._module.type === "css/module")) {
82 this.emitWarning(new Error('You can\'t use `experiments.css` (`experiments.futureDefaults` enable built-in CSS support by default) and `mini-css-extract-plugin` together, please set `experiments.css` to `false` or set `{ type: "javascript/auto" }` for rules with `mini-css-extract-plugin` in your webpack config (now `mini-css-extract-plugin` does nothing).'));
83 return;
84 }
85 const options = this.getOptions(/** @type {Schema} */schema);
86 const emit = typeof options.emit !== "undefined" ? options.emit : true;
87 const callback = this.async();
88 const optionsFromPlugin =
89 // @ts-expect-error
90 this[MiniCssExtractPlugin.pluginSymbol];
91 if (!optionsFromPlugin) {
92 callback(new Error("You forgot to add 'mini-css-extract-plugin' plugin (i.e. `{ plugins: [new MiniCssExtractPlugin()] }`), please read https://github.com/webpack/mini-css-extract-plugin#getting-started"));
93 return;
94 }
95 const {
96 webpack
97 } = /** @type {Compiler} */this._compiler;
98
99 /**
100 * @param {EXPECTED_ANY} originalExports original exports
101 * @param {Compilation=} compilation compilation
102 * @param {{ [name: string]: Source }=} assets assets
103 * @param {Map<string, AssetInfo>=} assetsInfo assets info
104 * @returns {void}
105 */
106 const handleExports = (originalExports, compilation, assets, assetsInfo) => {
107 /** @type {Locals | undefined} */
108 let locals;
109 let namedExport;
110 const esModule = typeof options.esModule !== "undefined" ? options.esModule : true;
111
112 /**
113 * @param {Dependency[] | [null, object][]} dependencies dependencies
114 */
115 const addDependencies = dependencies => {
116 // eslint-disable-next-line no-eq-null, eqeqeq
117 if (!Array.isArray(dependencies) && dependencies != null) {
118 throw new Error(`Exported value was not extracted as an array: ${JSON.stringify(dependencies)}`);
119 }
120 const identifierCountMap = new Map();
121 let lastDep;
122 for (const dependency of dependencies) {
123 if (!(/** @type {Dependency} */dependency.identifier) || !emit) {
124 continue;
125 }
126 const count = identifierCountMap.get(/** @type {Dependency} */dependency.identifier) || 0;
127 const CssDependency = MiniCssExtractPlugin.getCssDependency(webpack);
128
129 /** @type {NormalModule} */
130 this._module.addDependency(lastDep = new CssDependency(/** @type {Dependency} */
131 dependency, /** @type {Dependency} */
132 dependency.context, count));
133 identifierCountMap.set(/** @type {Dependency} */
134 dependency.identifier, count + 1);
135 }
136 if (lastDep && assets) {
137 lastDep.assets = assets;
138 lastDep.assetsInfo = assetsInfo;
139 }
140 };
141 try {
142 const exports = originalExports.__esModule ? originalExports.default : originalExports;
143 namedExport = originalExports.__esModule && (!originalExports.default || !("locals" in originalExports.default));
144 if (namedExport) {
145 for (const key of Object.keys(originalExports)) {
146 if (key !== "default") {
147 if (!locals) {
148 locals = {};
149 }
150
151 /** @type {Locals} */
152 locals[key] = originalExports[key];
153 }
154 }
155 } else {
156 locals = exports && exports.locals;
157 }
158
159 /** @type {Dependency[] | [null, Record<string, string>][]} */
160 let dependencies;
161 if (!Array.isArray(exports)) {
162 dependencies = [[null, exports]];
163 } else {
164 dependencies = exports.map(([id, content, media, sourceMap, supports, layer]) => {
165 let identifier = id;
166 let context;
167 if (compilation) {
168 const module = /** @type {Module} */
169 findModuleById(compilation, id);
170 identifier = module.identifier();
171 ({
172 context
173 } = module);
174 } else {
175 // TODO check if this context is used somewhere
176 context = this.rootContext;
177 }
178 return {
179 identifier,
180 context,
181 content: Buffer.from(content),
182 media,
183 supports,
184 layer,
185 sourceMap: sourceMap ? Buffer.from(JSON.stringify(sourceMap)) : undefined
186 };
187 });
188 }
189 addDependencies(dependencies);
190 } catch (err) {
191 callback(/** @type {Error} */err);
192 return;
193 }
194 const result = function makeResult() {
195 const defaultExport = typeof options.defaultExport !== "undefined" ? options.defaultExport : false;
196 if (locals) {
197 if (namedExport) {
198 const identifiers = [...function* generateIdentifiers() {
199 let identifierId = 0;
200 for (const key of Object.keys(locals)) {
201 identifierId += 1;
202 yield [`_${identifierId.toString(16)}`, key];
203 }
204 }()];
205 const localsString = identifiers.map(([id, key]) => `\nvar ${id} = ${stringifyLocal(/** @type {Locals} */locals[key])};`).join("");
206 const exportsString = `export { ${identifiers.map(([id, key]) => `${id} as ${JSON.stringify(key)}`).join(", ")} }`;
207 return defaultExport ? `${localsString}\n${exportsString}\nexport default { ${identifiers.map(([id, key]) => `${JSON.stringify(key)}: ${id}`).join(", ")} }\n` : `${localsString}\n${exportsString}\n`;
208 }
209 return `\n${esModule ? "export default" : "module.exports = "} ${JSON.stringify(locals)};`;
210 } else if (esModule) {
211 return defaultExport ? "\nexport {};export default {};" : "\nexport {};";
212 }
213 return "";
214 }();
215 let resultSource = `// extracted by ${MiniCssExtractPlugin.pluginName}`;
216
217 // only attempt hotreloading if the css is actually used for something other than hash values
218 resultSource += this.hot && emit ? hotLoader(result, {
219 loaderContext: this,
220 options,
221 locals
222 }) : result;
223 callback(null, resultSource);
224 };
225 let {
226 publicPath
227 } = /** @type {Compilation} */
228 this._compilation.outputOptions;
229 if (typeof options.publicPath === "string") {
230 publicPath = options.publicPath;
231 } else if (typeof options.publicPath === "function") {
232 publicPath = options.publicPath(this.resourcePath, this.rootContext);
233 }
234 if (publicPath === "auto") {
235 publicPath = AUTO_PUBLIC_PATH;
236 }
237 if (typeof optionsFromPlugin.experimentalUseImportModule === "undefined" && typeof this.importModule === "function" || optionsFromPlugin.experimentalUseImportModule) {
238 if (!this.importModule) {
239 callback(new Error("You are using 'experimentalUseImportModule' but 'this.importModule' is not available in loader context. You need to have at least webpack 5.33.2."));
240 return;
241 }
242 let publicPathForExtract;
243 if (typeof publicPath === "string") {
244 const isAbsolutePublicPath = /^[a-zA-Z][a-zA-Z\d+\-.]*?:/.test(publicPath);
245 publicPathForExtract = isAbsolutePublicPath ? publicPath : `${ABSOLUTE_PUBLIC_PATH}${publicPath.replace(/\./g, SINGLE_DOT_PATH_SEGMENT)}`;
246 } else {
247 publicPathForExtract = publicPath;
248 }
249 this.importModule(`${this._module && this._module.matchResource ? this._module.matchResource : this.resourcePath}.webpack[javascript/auto]!=!!!${request}`, {
250 layer: options.layer,
251 publicPath: (/** @type {string} */publicPathForExtract),
252 baseUri: `${BASE_URI}/`
253 },
254 /**
255 * @param {Error | null | undefined} error error
256 * @param {object} exports exports
257 */
258 (error, exports) => {
259 if (error) {
260 callback(error);
261 return;
262 }
263 handleExports(exports);
264 });
265 return;
266 }
267 const loaders = this.loaders.slice(this.loaderIndex + 1);
268 this.addDependency(this.resourcePath);
269 const childFilename = "*";
270 const outputOptions = {
271 filename: childFilename,
272 publicPath
273 };
274 const childCompiler = /** @type {Compilation} */
275 this._compilation.createChildCompiler(`${MiniCssExtractPlugin.pluginName} ${request}`, outputOptions);
276
277 // The templates are compiled and executed by NodeJS - similar to server side rendering
278 // Unfortunately this causes issues as some loaders require an absolute URL to support ES Modules
279 // The following config enables relative URL support for the child compiler
280 childCompiler.options.module = {
281 ...childCompiler.options.module
282 };
283 childCompiler.options.module.parser = {
284 ...childCompiler.options.module.parser
285 };
286 childCompiler.options.module.parser.javascript = {
287 ...childCompiler.options.module.parser.javascript,
288 url: "relative"
289 };
290 const {
291 NodeTemplatePlugin
292 } = webpack.node;
293 const {
294 NodeTargetPlugin
295 } = webpack.node;
296 new NodeTemplatePlugin().apply(childCompiler);
297 new NodeTargetPlugin().apply(childCompiler);
298 const {
299 EntryOptionPlugin
300 } = webpack;
301 const {
302 library: {
303 EnableLibraryPlugin
304 }
305 } = webpack;
306 new EnableLibraryPlugin("commonjs2").apply(childCompiler);
307 EntryOptionPlugin.applyEntryOption(childCompiler, this.context, {
308 child: {
309 library: {
310 type: "commonjs2"
311 },
312 import: [`!!${request}`]
313 }
314 });
315 const {
316 LimitChunkCountPlugin
317 } = webpack.optimize;
318 new LimitChunkCountPlugin({
319 maxChunks: 1
320 }).apply(childCompiler);
321 const {
322 NormalModule
323 } = webpack;
324 childCompiler.hooks.thisCompilation.tap(`${MiniCssExtractPlugin.pluginName} loader`,
325 /**
326 * @param {Compilation} compilation compilation
327 */
328 compilation => {
329 const normalModuleHook = NormalModule.getCompilationHooks(compilation).loader;
330 normalModuleHook.tap(`${MiniCssExtractPlugin.pluginName} loader`, (loaderContext, module) => {
331 if (module.request === request) {
332 module.loaders = loaders.map(loader => ({
333 type: null,
334 loader: loader.path,
335 options: loader.options,
336 ident: loader.ident
337 }));
338 }
339 });
340 });
341
342 /** @type {string | Buffer} */
343 let source;
344 childCompiler.hooks.compilation.tap(MiniCssExtractPlugin.pluginName,
345 /**
346 * @param {Compilation} compilation compilation
347 */
348 compilation => {
349 compilation.hooks.processAssets.tap(MiniCssExtractPlugin.pluginName, () => {
350 source = compilation.assets[childFilename] && compilation.assets[childFilename].source();
351
352 // Remove all chunk assets
353 for (const chunk of compilation.chunks) {
354 for (const file of chunk.files) {
355 compilation.deleteAsset(file);
356 }
357 }
358 });
359 });
360 childCompiler.runAsChild((error, entries, compilation_) => {
361 if (error) {
362 callback(error);
363 return;
364 }
365 const compilation = /** @type {Compilation} */compilation_;
366 if (compilation.errors.length > 0) {
367 callback(compilation.errors[0]);
368 return;
369 }
370
371 /** @type {{ [name: string]: Source }} */
372 const assets = Object.create(null);
373 /** @type {Map<string, AssetInfo>} */
374 const assetsInfo = new Map();
375 for (const asset of compilation.getAssets()) {
376 assets[asset.name] = asset.source;
377 assetsInfo.set(asset.name, asset.info);
378 }
379 for (const dep of compilation.fileDependencies) {
380 this.addDependency(dep);
381 }
382 for (const dep of compilation.contextDependencies) {
383 this.addContextDependency(dep);
384 }
385 if (!source) {
386 callback(new Error("Didn't get a result from child compiler"));
387 return;
388 }
389 let originalExports;
390 try {
391 originalExports = evalModuleCode(this, source, request);
392 } catch (err) {
393 callback(/** @type {Error} */err);
394 return;
395 }
396 handleExports(originalExports, compilation, assets, assetsInfo);
397 });
398}
399
400/**
401 * @this {import("webpack").LoaderContext<LoaderOptions>}
402 * @param {string} content content
403 * @returns {string | undefined} the original content
404 */
405function loader(content) {
406 if (this._compiler && this._compiler.options && this._compiler.options.experiments && this._compiler.options.experiments.css && this._module && (this._module.type === "css" || this._module.type === "css/auto" || this._module.type === "css/global" || this._module.type === "css/module")) {
407 return content;
408 }
409}
410module.exports = loader;
411module.exports.hotLoader = hotLoader;
412module.exports.pitch = pitch;
Note: See TracBrowser for help on using the repository browser.