1 | 'use strict';
|
2 |
|
3 | const os = require('os');
|
4 | const mkdirp = require('mkdirp');
|
5 | const webpackSources = require('webpack-sources');
|
6 | const workerFarm = require('worker-farm');
|
7 | const pify = require('pify');
|
8 | const ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers');
|
9 |
|
10 | const SourceMapSource = webpackSources.SourceMapSource;
|
11 | const RawSource = webpackSources.RawSource;
|
12 | const cache = require('./cache');
|
13 | const tmpFile = require('./tmp-file');
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | function workerCount(options, assetCount) {
|
19 | if (options.workerCount) {
|
20 | return options.workerCount;
|
21 | }
|
22 | return Math.min(assetCount, Math.max(1, os.cpus().length - 1));
|
23 | }
|
24 |
|
25 | const usedCacheKeys = [];
|
26 |
|
27 | function processAssets(compilation, options) {
|
28 | const assetHash = compilation.assets;
|
29 | const useSourceMaps = options.sourceMap || false;
|
30 | if (options.cacheDir) {
|
31 | mkdirp.sync(options.cacheDir);
|
32 | }
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | const optionsWithoutCacheDir = Object.assign({}, options);
|
38 | optionsWithoutCacheDir.cacheDir = undefined;
|
39 |
|
40 |
|
41 | options.test = options.test || /\.js$/i;
|
42 | const assets = Object.keys(assetHash)
|
43 | .filter(ModuleFilenameHelpers.matchObject.bind(null, options));
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | const cacheKeysOnDisk = new Set(cache.getCacheKeysFromDisk(options.cacheDir));
|
49 | const uncachedAssets = [];
|
50 |
|
51 | assets.forEach((assetName) => {
|
52 |
|
53 |
|
54 | const source = assetHash[assetName].source();
|
55 | const cacheKey = cache.createCacheKey(source + useSourceMaps, optionsWithoutCacheDir);
|
56 | usedCacheKeys.push(cacheKey);
|
57 | if (cacheKeysOnDisk.has(cacheKey)) {
|
58 |
|
59 | const content = JSON.parse(cache.retrieveFromCache(cacheKey, options.cacheDir));
|
60 | if (content.map) {
|
61 | assetHash[assetName] = new SourceMapSource(content.source, assetName, content.map);
|
62 | } else {
|
63 | assetHash[assetName] = new RawSource(content.source);
|
64 | }
|
65 | } else {
|
66 |
|
67 | uncachedAssets.push(assetName);
|
68 | }
|
69 | });
|
70 |
|
71 | const farm = workerFarm({
|
72 | autoStart: true,
|
73 | maxConcurrentCallsPerWorker: 1,
|
74 | maxConcurrentWorkers: workerCount(options, uncachedAssets.length),
|
75 | maxRetries: 2,
|
76 | },
|
77 | require.resolve('./worker'),
|
78 | ['processMessage']
|
79 | );
|
80 |
|
81 | const minify = pify(farm.processMessage);
|
82 |
|
83 | const minificationPromises = uncachedAssets.map((assetName) => {
|
84 | const asset = assetHash[assetName];
|
85 | const tmpFileName = tmpFile.create(JSON.stringify({
|
86 | assetName,
|
87 | options: optionsWithoutCacheDir,
|
88 | source: asset.source(),
|
89 | map: useSourceMaps ? asset.map() : null,
|
90 | cacheDir: options.cacheDir,
|
91 | }));
|
92 |
|
93 | return minify(tmpFileName)
|
94 | .then(() => {
|
95 | const content = tmpFile.read(tmpFileName);
|
96 | const msg = JSON.parse(content);
|
97 | if (msg.map) {
|
98 | assetHash[assetName] = new SourceMapSource(msg.source, assetName, msg.map);
|
99 | } else {
|
100 | assetHash[assetName] = new RawSource(msg.source);
|
101 | }
|
102 | })
|
103 | .catch((e) => {
|
104 | const builtError = new Error(`Encountered an error while minifying ${assetName}:\n${e}`);
|
105 | compilation.errors.push(builtError);
|
106 | });
|
107 | });
|
108 |
|
109 | function endWorkers() {
|
110 | workerFarm.end(farm);
|
111 | }
|
112 |
|
113 | return Promise.all(minificationPromises)
|
114 | .then(endWorkers)
|
115 | .catch(endWorkers);
|
116 | }
|
117 |
|
118 | function pruneCache(options) {
|
119 | cache.pruneCache(usedCacheKeys, cache.getCacheKeysFromDisk(options.cacheDir), options.cacheDir);
|
120 | }
|
121 |
|
122 | module.exports = {
|
123 | processAssets,
|
124 | pruneCache,
|
125 | workerCount,
|
126 | };
|