source: frontend/node_modules/css-minimizer-webpack-plugin/dist/utils.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: 9.9 KB
Line 
1"use strict";
2
3/** @typedef {import("./index.js").Input} Input */
4
5/** @typedef {import("source-map").RawSourceMap} RawSourceMap */
6
7/** @typedef {import("source-map").SourceMapGenerator} SourceMapGenerator */
8
9/** @typedef {import("./index.js").MinimizedResult} MinimizedResult */
10
11/** @typedef {import("./index.js").CustomOptions} CustomOptions */
12
13/** @typedef {import("postcss").ProcessOptions} ProcessOptions */
14
15/** @typedef {import("postcss").Postcss} Postcss */
16const notSettled = Symbol(`not-settled`);
17/**
18 * @template T
19 * @typedef {() => Promise<T>} Task
20 */
21
22/**
23 * Run tasks with limited concurency.
24 * @template T
25 * @param {number} limit - Limit of tasks that run at once.
26 * @param {Task<T>[]} tasks - List of tasks to run.
27 * @returns {Promise<T[]>} A promise that fulfills to an array of the results
28 */
29
30function throttleAll(limit, tasks) {
31 if (!Number.isInteger(limit) || limit < 1) {
32 throw new TypeError(`Expected \`limit\` to be a finite number > 0, got \`${limit}\` (${typeof limit})`);
33 }
34
35 if (!Array.isArray(tasks) || !tasks.every(task => typeof task === `function`)) {
36 throw new TypeError(`Expected \`tasks\` to be a list of functions returning a promise`);
37 }
38
39 return new Promise((resolve, reject) => {
40 const result = Array(tasks.length).fill(notSettled);
41 const entries = tasks.entries();
42
43 const next = () => {
44 const {
45 done,
46 value
47 } = entries.next();
48
49 if (done) {
50 const isLast = !result.includes(notSettled);
51 if (isLast) resolve(result);
52 return;
53 }
54
55 const [index, task] = value;
56 /**
57 * @param {T} x
58 */
59
60 const onFulfilled = x => {
61 result[index] = x;
62 next();
63 };
64
65 task().then(onFulfilled, reject);
66 };
67
68 Array(limit).fill(0).forEach(next);
69 });
70}
71/* istanbul ignore next */
72
73/**
74 * @param {Input} input
75 * @param {RawSourceMap | undefined} sourceMap
76 * @param {CustomOptions} minimizerOptions
77 * @return {Promise<MinimizedResult>}
78 */
79
80
81async function cssnanoMinify(input, sourceMap, minimizerOptions = {
82 preset: "default"
83}) {
84 /**
85 * @template T
86 * @param {string} module
87 * @returns {Promise<T>}
88 */
89 const load = async module => {
90 let exports;
91
92 try {
93 // eslint-disable-next-line import/no-dynamic-require, global-require
94 exports = require(module);
95 return exports;
96 } catch (requireError) {
97 let importESM;
98
99 try {
100 // eslint-disable-next-line no-new-func
101 importESM = new Function("id", "return import(id);");
102 } catch (e) {
103 importESM = null;
104 }
105
106 if (
107 /** @type {Error & {code: string}} */
108 requireError.code === "ERR_REQUIRE_ESM" && importESM) {
109 exports = await importESM(module);
110 return exports.default;
111 }
112
113 throw requireError;
114 }
115 };
116
117 const [[name, code]] = Object.entries(input);
118 /** @type {ProcessOptions} */
119
120 const postcssOptions = {
121 from: name,
122 ...minimizerOptions.processorOptions
123 };
124
125 if (typeof postcssOptions.parser === "string") {
126 try {
127 postcssOptions.parser = await load(postcssOptions.parser);
128 } catch (error) {
129 throw new Error(`Loading PostCSS "${postcssOptions.parser}" parser failed: ${
130 /** @type {Error} */
131 error.message}\n\n(@${name})`);
132 }
133 }
134
135 if (typeof postcssOptions.stringifier === "string") {
136 try {
137 postcssOptions.stringifier = await load(postcssOptions.stringifier);
138 } catch (error) {
139 throw new Error(`Loading PostCSS "${postcssOptions.stringifier}" stringifier failed: ${
140 /** @type {Error} */
141 error.message}\n\n(@${name})`);
142 }
143 }
144
145 if (typeof postcssOptions.syntax === "string") {
146 try {
147 postcssOptions.syntax = await load(postcssOptions.syntax);
148 } catch (error) {
149 throw new Error(`Loading PostCSS "${postcssOptions.syntax}" syntax failed: ${
150 /** @type {Error} */
151 error.message}\n\n(@${name})`);
152 }
153 }
154
155 if (sourceMap) {
156 postcssOptions.map = {
157 annotation: false
158 };
159 }
160 /** @type {Postcss} */
161 // eslint-disable-next-line global-require
162
163
164 const postcss = require("postcss").default; // @ts-ignore
165 // eslint-disable-next-line global-require
166
167
168 const cssnano = require("cssnano"); // @ts-ignore
169 // Types are broken
170
171
172 const result = await postcss([cssnano(minimizerOptions)]).process(code, postcssOptions);
173 return {
174 code: result.css,
175 map: result.map ? result.map.toJSON() : // eslint-disable-next-line no-undefined
176 undefined,
177 warnings: result.warnings().map(String)
178 };
179}
180/* istanbul ignore next */
181
182/**
183 * @param {Input} input
184 * @param {RawSourceMap | undefined} sourceMap
185 * @param {CustomOptions} minimizerOptions
186 * @return {Promise<MinimizedResult>}
187 */
188
189
190async function cssoMinify(input, sourceMap, minimizerOptions) {
191 // eslint-disable-next-line global-require,import/no-extraneous-dependencies
192 const csso = require("csso");
193
194 const [[filename, code]] = Object.entries(input);
195 const result = csso.minify(code, {
196 filename,
197 sourceMap: Boolean(sourceMap),
198 ...minimizerOptions
199 });
200 return {
201 code: result.css,
202 map: result.map ?
203 /** @type {SourceMapGenerator & { toJSON(): RawSourceMap }} */
204 result.map.toJSON() : // eslint-disable-next-line no-undefined
205 undefined
206 };
207}
208/* istanbul ignore next */
209
210/**
211 * @param {Input} input
212 * @param {RawSourceMap | undefined} sourceMap
213 * @param {CustomOptions} minimizerOptions
214 * @return {Promise<MinimizedResult>}
215 */
216
217
218async function cleanCssMinify(input, sourceMap, minimizerOptions) {
219 // eslint-disable-next-line global-require,import/no-extraneous-dependencies
220 const CleanCSS = require("clean-css");
221
222 const [[name, code]] = Object.entries(input);
223 const result = await new CleanCSS({
224 sourceMap: Boolean(sourceMap),
225 ...minimizerOptions,
226 returnPromise: true
227 }).minify({
228 [name]: {
229 styles: code
230 }
231 });
232 const generatedSourceMap = result.sourceMap &&
233 /** @type {SourceMapGenerator & { toJSON(): RawSourceMap }} */
234 result.sourceMap.toJSON(); // workaround for source maps on windows
235
236 if (generatedSourceMap) {
237 // eslint-disable-next-line global-require
238 const isWindowsPathSep = require("path").sep === "\\";
239 generatedSourceMap.sources = generatedSourceMap.sources.map(
240 /**
241 * @param {string} item
242 * @returns {string}
243 */
244 item => isWindowsPathSep ? item.replace(/\\/g, "/") : item);
245 }
246
247 return {
248 code: result.styles,
249 map: generatedSourceMap,
250 warnings: result.warnings
251 };
252}
253/* istanbul ignore next */
254
255/**
256 * @param {Input} input
257 * @param {RawSourceMap | undefined} sourceMap
258 * @param {CustomOptions} minimizerOptions
259 * @return {Promise<MinimizedResult>}
260 */
261
262
263async function esbuildMinify(input, sourceMap, minimizerOptions) {
264 /**
265 * @param {import("esbuild").TransformOptions} [esbuildOptions={}]
266 * @returns {import("esbuild").TransformOptions}
267 */
268 const buildEsbuildOptions = (esbuildOptions = {}) => {
269 // Need deep copy objects to avoid https://github.com/terser/terser/issues/366
270 return {
271 loader: "css",
272 minify: true,
273 legalComments: "inline",
274 ...esbuildOptions,
275 sourcemap: false
276 };
277 }; // eslint-disable-next-line import/no-extraneous-dependencies, global-require
278
279
280 const esbuild = require("esbuild"); // Copy `esbuild` options
281
282
283 const esbuildOptions = buildEsbuildOptions(minimizerOptions); // Let `esbuild` generate a SourceMap
284
285 if (sourceMap) {
286 esbuildOptions.sourcemap = true;
287 esbuildOptions.sourcesContent = false;
288 }
289
290 const [[filename, code]] = Object.entries(input);
291 esbuildOptions.sourcefile = filename;
292 const result = await esbuild.transform(code, esbuildOptions);
293 return {
294 code: result.code,
295 // eslint-disable-next-line no-undefined
296 map: result.map ? JSON.parse(result.map) : undefined,
297 warnings: result.warnings.length > 0 ? result.warnings.map(item => {
298 return {
299 source: item.location && item.location.file,
300 // eslint-disable-next-line no-undefined
301 line: item.location && item.location.line ? item.location.line : undefined,
302 // eslint-disable-next-line no-undefined
303 column: item.location && item.location.column ? item.location.column : undefined,
304 plugin: item.pluginName,
305 message: `${item.text}${item.detail ? `\nDetails:\n${item.detail}` : ""}${item.notes.length > 0 ? `\n\nNotes:\n${item.notes.map(note => `${note.location ? `[${note.location.file}:${note.location.line}:${note.location.column}] ` : ""}${note.text}${note.location ? `\nSuggestion: ${note.location.suggestion}` : ""}${note.location ? `\nLine text:\n${note.location.lineText}\n` : ""}`).join("\n")}` : ""}`
306 };
307 }) : []
308 };
309}
310/* istanbul ignore next */
311
312/**
313 * @param {Input} input
314 * @param {RawSourceMap | undefined} sourceMap
315 * @param {CustomOptions} minimizerOptions
316 * @return {Promise<MinimizedResult>}
317 */
318
319
320async function parcelCssMinify(input, sourceMap, minimizerOptions) {
321 const [[filename, code]] = Object.entries(input);
322 /**
323 * @param {Partial<import("@parcel/css").TransformOptions>} [parcelCssOptions={}]
324 * @returns {import("@parcel/css").TransformOptions}
325 */
326
327 const buildParcelCssOptions = (parcelCssOptions = {}) => {
328 // Need deep copy objects to avoid https://github.com/terser/terser/issues/366
329 return {
330 minify: true,
331 ...parcelCssOptions,
332 sourceMap: false,
333 filename,
334 code: Buffer.from(code)
335 };
336 }; // eslint-disable-next-line import/no-extraneous-dependencies, global-require
337
338
339 const parcelCss = require("@parcel/css"); // Copy `esbuild` options
340
341
342 const parcelCssOptions = buildParcelCssOptions(minimizerOptions); // Let `esbuild` generate a SourceMap
343
344 if (sourceMap) {
345 parcelCssOptions.sourceMap = true;
346 }
347
348 const result = await parcelCss.transform(parcelCssOptions);
349 return {
350 code: result.code.toString(),
351 // eslint-disable-next-line no-undefined
352 map: result.map ? JSON.parse(result.map.toString()) : undefined
353 };
354}
355
356module.exports = {
357 throttleAll,
358 cssnanoMinify,
359 cssoMinify,
360 cleanCssMinify,
361 esbuildMinify,
362 parcelCssMinify
363};
Note: See TracBrowser for help on using the repository browser.