forked from ember-cli/broccoli-terser-sourcemap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
123 lines (101 loc) · 4.04 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
'use strict';
const walkSync = require('walk-sync');
const Plugin = require('broccoli-plugin');
const path = require('path');
const defaults = require('lodash.defaultsdeep');
const symlinkOrCopy = require('symlink-or-copy');
const mkdirp = require('mkdirp');
const MatcherCollection = require('matcher-collection');
const debug = require('debug')('broccoli-uglify-sourcemap');
const queue = require('async-promise-queue');
const workerpool = require('workerpool');
const processFile = require('./lib/process-file');
module.exports = UglifyWriter;
UglifyWriter.prototype = Object.create(Plugin.prototype);
UglifyWriter.prototype.constructor = UglifyWriter;
const silent = process.argv.indexOf('--silent') !== -1;
const worker = queue.async.asyncify(doWork => doWork());
const MatchNothing = {
match() {
return false;
},
};
function UglifyWriter(inputNodes, options) {
if (!(this instanceof UglifyWriter)) {
return new UglifyWriter(inputNodes, options);
}
inputNodes = Array.isArray(inputNodes) ? inputNodes : [inputNodes];
Plugin.call(this, inputNodes, options);
this.options = defaults(options, {
uglify: {
sourceMap: {},
},
});
// consumers of this plugin can opt-in to async and concurrent behavior
this.async = (this.options.async === true);
this.concurrency = Number(process.env.JOBS) || this.options.concurrency || Math.max(require('os').cpus().length - 1, 1);
// create a worker pool using an external worker script
this.pool = workerpool.pool(path.join(__dirname, 'lib', 'worker.js'), { maxWorkers: this.concurrency });
this.inputNodes = inputNodes;
let exclude = this.options.exclude;
if (Array.isArray(exclude)) {
this.excludes = new MatcherCollection(exclude);
} else {
this.excludes = MatchNothing;
}
}
UglifyWriter.prototype.build = function() {
let writer = this;
// when options.async === true, allow processFile() operations to complete asynchronously
let pendingWork = [];
this.inputPaths.forEach(inputPath => {
walkSync(inputPath).forEach(relativePath => {
if (relativePath.slice(-1) === '/') {
return;
}
let inFile = path.join(inputPath, relativePath);
let outFile = path.join(writer.outputPath, relativePath);
mkdirp.sync(path.dirname(outFile));
if (relativePath.slice(-3) === '.js' && !writer.excludes.match(relativePath)) {
// wrap this in a function so it doesn't actually run yet, and can be throttled
let uglifyOperation = function() {
return writer.processFile(inFile, outFile, relativePath, writer.outputPath);
};
if (writer.async) {
pendingWork.push(uglifyOperation);
return;
}
return uglifyOperation();
} else if (relativePath.slice(-4) === '.map') {
if (writer.excludes.match(`${relativePath.slice(0, -4)}.js`)) {
// ensure .map files for excluded JS paths are also copied forward
symlinkOrCopy.sync(inFile, outFile);
}
// skip, because it will get handled when its corresponding JS does
} else {
symlinkOrCopy.sync(inFile, outFile);
}
});
});
return queue(worker, pendingWork, writer.concurrency)
.then((/* results */) => {
// files are finished processing, shut down the workers
writer.pool.terminate();
return writer.outputPath;
})
.catch(e => {
// make sure to shut down the workers on error
writer.pool.terminate();
throw e;
});
};
UglifyWriter.prototype.processFile = function(inFile, outFile, relativePath, outDir) {
// don't run this in the workerpool if concurrency is disabled (can set JOBS <= 1)
if (this.async && this.concurrency > 1) {
debug('running in workerpool, concurrency=%d', this.concurrency);
// each of these arguments is a string, which can be sent to the worker process as-is
return this.pool.exec('processFileParallel', [inFile, outFile, relativePath, outDir, silent, this.options]);
}
debug('not running in workerpool');
return processFile(inFile, outFile, relativePath, outDir, silent, this.options);
};