1 | "use strict";
|
---|
2 |
|
---|
3 | Object.defineProperty(exports, "__esModule", {
|
---|
4 | value: true
|
---|
5 | });
|
---|
6 | exports.default = void 0;
|
---|
7 |
|
---|
8 | var os = _interopRequireWildcard(require("os"));
|
---|
9 |
|
---|
10 | var _sourceMap = require("source-map");
|
---|
11 |
|
---|
12 | var _schemaUtils = require("schema-utils");
|
---|
13 |
|
---|
14 | var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
|
---|
15 |
|
---|
16 | var _pLimit = _interopRequireDefault(require("p-limit"));
|
---|
17 |
|
---|
18 | var _jestWorker = require("jest-worker");
|
---|
19 |
|
---|
20 | var _utils = require("./utils");
|
---|
21 |
|
---|
22 | var schema = _interopRequireWildcard(require("./options.json"));
|
---|
23 |
|
---|
24 | var _minify = require("./minify");
|
---|
25 |
|
---|
26 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
---|
27 |
|
---|
28 | function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
---|
29 |
|
---|
30 | function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
---|
31 |
|
---|
32 | const warningRegex = /\s.+:+([0-9]+):+([0-9]+)/;
|
---|
33 |
|
---|
34 | class CssMinimizerPlugin {
|
---|
35 | constructor(options = {}) {
|
---|
36 | (0, _schemaUtils.validate)(schema, options, {
|
---|
37 | name: 'Css Minimizer Plugin',
|
---|
38 | baseDataPath: 'options'
|
---|
39 | });
|
---|
40 | const {
|
---|
41 | minify = _utils.cssnanoMinify,
|
---|
42 | minimizerOptions,
|
---|
43 | test = /\.css(\?.*)?$/i,
|
---|
44 | warningsFilter = () => true,
|
---|
45 | parallel = true,
|
---|
46 | include,
|
---|
47 | exclude
|
---|
48 | } = options;
|
---|
49 | this.options = {
|
---|
50 | test,
|
---|
51 | warningsFilter,
|
---|
52 | parallel,
|
---|
53 | include,
|
---|
54 | exclude,
|
---|
55 | minify,
|
---|
56 | minimizerOptions
|
---|
57 | };
|
---|
58 | }
|
---|
59 |
|
---|
60 | static isSourceMap(input) {
|
---|
61 | // All required options for `new SourceMapConsumer(...options)`
|
---|
62 | // https://github.com/mozilla/source-map#new-sourcemapconsumerrawsourcemap
|
---|
63 | return Boolean(input && input.version && input.sources && Array.isArray(input.sources) && typeof input.mappings === 'string');
|
---|
64 | }
|
---|
65 |
|
---|
66 | static buildError(error, name, requestShortener, sourceMap) {
|
---|
67 | let builtError;
|
---|
68 |
|
---|
69 | if (error.line) {
|
---|
70 | const original = sourceMap && sourceMap.originalPositionFor({
|
---|
71 | line: error.line,
|
---|
72 | column: error.column
|
---|
73 | });
|
---|
74 |
|
---|
75 | if (original && original.source && requestShortener) {
|
---|
76 | builtError = new Error(`${name} from Css Minimizer Webpack Plugin\n${error.message} [${requestShortener.shorten(original.source)}:${original.line},${original.column}][${name}:${error.line},${error.column}]${error.stack ? `\n${error.stack.split('\n').slice(1).join('\n')}` : ''}`);
|
---|
77 | builtError.file = name;
|
---|
78 | return builtError;
|
---|
79 | }
|
---|
80 |
|
---|
81 | builtError = new Error(`${name} from Css Minimizer \n${error.message} [${name}:${error.line},${error.column}]${error.stack ? `\n${error.stack.split('\n').slice(1).join('\n')}` : ''}`);
|
---|
82 | builtError.file = name;
|
---|
83 | return builtError;
|
---|
84 | }
|
---|
85 |
|
---|
86 | if (error.stack) {
|
---|
87 | builtError = new Error(`${name} from Css Minimizer\n${error.stack}`);
|
---|
88 | builtError.file = name;
|
---|
89 | return builtError;
|
---|
90 | }
|
---|
91 |
|
---|
92 | builtError = new Error(`${name} from Css Minimizer\n${error.message}`);
|
---|
93 | builtError.file = name;
|
---|
94 | return builtError;
|
---|
95 | }
|
---|
96 |
|
---|
97 | static buildWarning(warning, file, sourceMap, requestShortener, warningsFilter) {
|
---|
98 | let warningMessage = warning;
|
---|
99 | let locationMessage = '';
|
---|
100 | let source;
|
---|
101 |
|
---|
102 | if (sourceMap) {
|
---|
103 | const match = warningRegex.exec(warning);
|
---|
104 |
|
---|
105 | if (match) {
|
---|
106 | const line = +match[1];
|
---|
107 | const column = +match[2];
|
---|
108 | const original = sourceMap.originalPositionFor({
|
---|
109 | line,
|
---|
110 | column
|
---|
111 | });
|
---|
112 |
|
---|
113 | if (original && original.source && original.source !== file && requestShortener) {
|
---|
114 | ({
|
---|
115 | source
|
---|
116 | } = original);
|
---|
117 | warningMessage = `${warningMessage.replace(warningRegex, '')}`;
|
---|
118 | locationMessage = `${requestShortener.shorten(original.source)}:${original.line}:${original.column}`;
|
---|
119 | }
|
---|
120 | }
|
---|
121 | }
|
---|
122 |
|
---|
123 | if (warningsFilter && !warningsFilter(warning, file, source)) {
|
---|
124 | return null;
|
---|
125 | }
|
---|
126 |
|
---|
127 | return `Css Minimizer Plugin: ${warningMessage} ${locationMessage}`;
|
---|
128 | }
|
---|
129 |
|
---|
130 | static getAvailableNumberOfCores(parallel) {
|
---|
131 | // In some cases cpus() returns undefined
|
---|
132 | // https://github.com/nodejs/node/issues/19022
|
---|
133 | const cpus = os.cpus() || {
|
---|
134 | length: 1
|
---|
135 | };
|
---|
136 | return parallel === true ? cpus.length - 1 : Math.min(Number(parallel) || 0, cpus.length - 1);
|
---|
137 | }
|
---|
138 |
|
---|
139 | async optimize(compiler, compilation, assets, optimizeOptions) {
|
---|
140 | const cache = compilation.getCache('CssMinimizerWebpackPlugin');
|
---|
141 | let numberOfAssetsForMinify = 0;
|
---|
142 | const assetsForMinify = await Promise.all(Object.keys(typeof assets === 'undefined' ? compilation.assets : assets).filter(name => {
|
---|
143 | const {
|
---|
144 | info
|
---|
145 | } = compilation.getAsset(name);
|
---|
146 |
|
---|
147 | if ( // Skip double minimize assets from child compilation
|
---|
148 | info.minimized) {
|
---|
149 | return false;
|
---|
150 | }
|
---|
151 |
|
---|
152 | if (!compiler.webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
|
---|
153 | undefined, this.options)(name)) {
|
---|
154 | return false;
|
---|
155 | }
|
---|
156 |
|
---|
157 | return true;
|
---|
158 | }).map(async name => {
|
---|
159 | const {
|
---|
160 | info,
|
---|
161 | source
|
---|
162 | } = compilation.getAsset(name);
|
---|
163 | const eTag = cache.getLazyHashedEtag(source);
|
---|
164 | const cacheItem = cache.getItemCache(name, eTag);
|
---|
165 | const output = await cacheItem.getPromise();
|
---|
166 |
|
---|
167 | if (!output) {
|
---|
168 | numberOfAssetsForMinify += 1;
|
---|
169 | }
|
---|
170 |
|
---|
171 | return {
|
---|
172 | name,
|
---|
173 | info,
|
---|
174 | inputSource: source,
|
---|
175 | output,
|
---|
176 | cacheItem
|
---|
177 | };
|
---|
178 | }));
|
---|
179 | let getWorker;
|
---|
180 | let initializedWorker;
|
---|
181 | let numberOfWorkers;
|
---|
182 |
|
---|
183 | if (optimizeOptions.availableNumberOfCores > 0) {
|
---|
184 | // Do not create unnecessary workers when the number of files is less than the available cores, it saves memory
|
---|
185 | numberOfWorkers = Math.min(numberOfAssetsForMinify, optimizeOptions.availableNumberOfCores);
|
---|
186 |
|
---|
187 | getWorker = () => {
|
---|
188 | if (initializedWorker) {
|
---|
189 | return initializedWorker;
|
---|
190 | }
|
---|
191 |
|
---|
192 | initializedWorker = new _jestWorker.Worker(require.resolve('./minify'), {
|
---|
193 | numWorkers: numberOfWorkers,
|
---|
194 | enableWorkerThreads: true
|
---|
195 | }); // https://github.com/facebook/jest/issues/8872#issuecomment-524822081
|
---|
196 |
|
---|
197 | const workerStdout = initializedWorker.getStdout();
|
---|
198 |
|
---|
199 | if (workerStdout) {
|
---|
200 | workerStdout.on('data', chunk => process.stdout.write(chunk));
|
---|
201 | }
|
---|
202 |
|
---|
203 | const workerStderr = initializedWorker.getStderr();
|
---|
204 |
|
---|
205 | if (workerStderr) {
|
---|
206 | workerStderr.on('data', chunk => process.stderr.write(chunk));
|
---|
207 | }
|
---|
208 |
|
---|
209 | return initializedWorker;
|
---|
210 | };
|
---|
211 | }
|
---|
212 |
|
---|
213 | const limit = (0, _pLimit.default)(getWorker && numberOfAssetsForMinify > 0 ? numberOfWorkers : Infinity);
|
---|
214 | const {
|
---|
215 | SourceMapSource,
|
---|
216 | RawSource
|
---|
217 | } = compiler.webpack.sources;
|
---|
218 | const scheduledTasks = [];
|
---|
219 |
|
---|
220 | for (const asset of assetsForMinify) {
|
---|
221 | scheduledTasks.push(limit(async () => {
|
---|
222 | const {
|
---|
223 | name,
|
---|
224 | inputSource,
|
---|
225 | cacheItem
|
---|
226 | } = asset;
|
---|
227 | let {
|
---|
228 | output
|
---|
229 | } = asset;
|
---|
230 |
|
---|
231 | if (!output) {
|
---|
232 | let input;
|
---|
233 | let inputSourceMap;
|
---|
234 | const {
|
---|
235 | source: sourceFromInputSource,
|
---|
236 | map
|
---|
237 | } = inputSource.sourceAndMap();
|
---|
238 | input = sourceFromInputSource;
|
---|
239 |
|
---|
240 | if (map) {
|
---|
241 | if (CssMinimizerPlugin.isSourceMap(map)) {
|
---|
242 | inputSourceMap = map;
|
---|
243 | } else {
|
---|
244 | inputSourceMap = map;
|
---|
245 | compilation.warnings.push(new Error(`${name} contains invalid source map`));
|
---|
246 | }
|
---|
247 | }
|
---|
248 |
|
---|
249 | if (Buffer.isBuffer(input)) {
|
---|
250 | input = input.toString();
|
---|
251 | }
|
---|
252 |
|
---|
253 | const options = {
|
---|
254 | name,
|
---|
255 | input,
|
---|
256 | inputSourceMap,
|
---|
257 | minify: this.options.minify,
|
---|
258 | minifyOptions: this.options.minimizerOptions
|
---|
259 | };
|
---|
260 |
|
---|
261 | try {
|
---|
262 | output = await (getWorker ? getWorker().transform((0, _serializeJavascript.default)(options)) : (0, _minify.minify)(options));
|
---|
263 | } catch (error) {
|
---|
264 | compilation.errors.push(CssMinimizerPlugin.buildError(error, name, compilation.requestShortener, inputSourceMap && CssMinimizerPlugin.isSourceMap(inputSourceMap) ? new _sourceMap.SourceMapConsumer(inputSourceMap) : null));
|
---|
265 | return;
|
---|
266 | }
|
---|
267 |
|
---|
268 | if (output.map) {
|
---|
269 | output.source = new SourceMapSource(output.code, name, output.map, input, inputSourceMap, true);
|
---|
270 | } else {
|
---|
271 | output.source = new RawSource(output.code);
|
---|
272 | }
|
---|
273 |
|
---|
274 | if (output.warnings && output.warnings.length > 0) {
|
---|
275 | output.warnings = output.warnings.map(warning => CssMinimizerPlugin.buildWarning(warning, name, inputSourceMap && CssMinimizerPlugin.isSourceMap(inputSourceMap) ? new _sourceMap.SourceMapConsumer(inputSourceMap) : null, compilation.requestShortener, this.options.warningsFilter)).filter(Boolean);
|
---|
276 | }
|
---|
277 |
|
---|
278 | await cacheItem.storePromise({
|
---|
279 | source: output.source,
|
---|
280 | warnings: output.warnings
|
---|
281 | });
|
---|
282 | }
|
---|
283 |
|
---|
284 | if (output.warnings && output.warnings.length > 0) {
|
---|
285 | output.warnings.forEach(warning => {
|
---|
286 | const Warning = class Warning extends Error {
|
---|
287 | constructor(message) {
|
---|
288 | super(message);
|
---|
289 | this.name = 'Warning';
|
---|
290 | this.hideStack = true;
|
---|
291 | this.file = name;
|
---|
292 | }
|
---|
293 |
|
---|
294 | };
|
---|
295 | compilation.warnings.push(new Warning(warning));
|
---|
296 | });
|
---|
297 | }
|
---|
298 |
|
---|
299 | const newInfo = {
|
---|
300 | minimized: true
|
---|
301 | };
|
---|
302 | const {
|
---|
303 | source
|
---|
304 | } = output;
|
---|
305 | compilation.updateAsset(name, source, newInfo);
|
---|
306 | }));
|
---|
307 | }
|
---|
308 |
|
---|
309 | const result = await Promise.all(scheduledTasks);
|
---|
310 |
|
---|
311 | if (initializedWorker) {
|
---|
312 | await initializedWorker.end();
|
---|
313 | }
|
---|
314 |
|
---|
315 | return result;
|
---|
316 | }
|
---|
317 |
|
---|
318 | apply(compiler) {
|
---|
319 | const pluginName = this.constructor.name;
|
---|
320 | const availableNumberOfCores = CssMinimizerPlugin.getAvailableNumberOfCores(this.options.parallel);
|
---|
321 | compiler.hooks.compilation.tap(pluginName, compilation => {
|
---|
322 | compilation.hooks.processAssets.tapPromise({
|
---|
323 | name: pluginName,
|
---|
324 | stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
|
---|
325 | additionalAssets: true
|
---|
326 | }, assets => this.optimize(compiler, compilation, assets, {
|
---|
327 | availableNumberOfCores
|
---|
328 | }));
|
---|
329 | compilation.hooks.statsPrinter.tap(pluginName, stats => {
|
---|
330 | stats.hooks.print.for('asset.info.minimized').tap('css-minimizer-webpack-plugin', (minimized, {
|
---|
331 | green,
|
---|
332 | formatFlag
|
---|
333 | }) => // eslint-disable-next-line no-undefined
|
---|
334 | minimized ? green(formatFlag('minimized')) : '');
|
---|
335 | });
|
---|
336 | });
|
---|
337 | }
|
---|
338 |
|
---|
339 | }
|
---|
340 |
|
---|
341 | CssMinimizerPlugin.cssnanoMinify = _utils.cssnanoMinify;
|
---|
342 | CssMinimizerPlugin.cssoMinify = _utils.cssoMinify;
|
---|
343 | CssMinimizerPlugin.cleanCssMinify = _utils.cleanCssMinify;
|
---|
344 | var _default = CssMinimizerPlugin;
|
---|
345 | exports.default = _default; |
---|