UNPKG

14.2 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /* eslint-disable
8 no-param-reassign
9 */
10
11
12var _crypto = require('crypto');
13
14var _crypto2 = _interopRequireDefault(_crypto);
15
16var _path = require('path');
17
18var _path2 = _interopRequireDefault(_path);
19
20var _sourceMap = require('source-map');
21
22var _webpackSources = require('webpack-sources');
23
24var _RequestShortener = require('webpack/lib/RequestShortener');
25
26var _RequestShortener2 = _interopRequireDefault(_RequestShortener);
27
28var _ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers');
29
30var _ModuleFilenameHelpers2 = _interopRequireDefault(_ModuleFilenameHelpers);
31
32var _schemaUtils = require('schema-utils');
33
34var _schemaUtils2 = _interopRequireDefault(_schemaUtils);
35
36var _serializeJavascript = require('serialize-javascript');
37
38var _serializeJavascript2 = _interopRequireDefault(_serializeJavascript);
39
40var _options = require('./options.json');
41
42var _options2 = _interopRequireDefault(_options);
43
44var _uglify = require('./uglify');
45
46var _uglify2 = _interopRequireDefault(_uglify);
47
48var _versions = require('./uglify/versions');
49
50var _versions2 = _interopRequireDefault(_versions);
51
52var _utils = require('./utils');
53
54var _utils2 = _interopRequireDefault(_utils);
55
56function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
57
58function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
59
60var warningRegex = /\[.+:([0-9]+),([0-9]+)\]/;
61
62var UglifyJsPlugin = function () {
63 function UglifyJsPlugin() {
64 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
65
66 _classCallCheck(this, UglifyJsPlugin);
67
68 (0, _schemaUtils2.default)(_options2.default, options, 'UglifyJs Plugin');
69
70 var _options$uglifyOption = options.uglifyOptions,
71 uglifyOptions = _options$uglifyOption === undefined ? {} : _options$uglifyOption,
72 _options$test = options.test,
73 test = _options$test === undefined ? /\.js(\?.*)?$/i : _options$test,
74 _options$warningsFilt = options.warningsFilter,
75 warningsFilter = _options$warningsFilt === undefined ? function () {
76 return true;
77 } : _options$warningsFilt,
78 _options$extractComme = options.extractComments,
79 extractComments = _options$extractComme === undefined ? false : _options$extractComme,
80 _options$sourceMap = options.sourceMap,
81 sourceMap = _options$sourceMap === undefined ? false : _options$sourceMap,
82 _options$cache = options.cache,
83 cache = _options$cache === undefined ? false : _options$cache,
84 _options$parallel = options.parallel,
85 parallel = _options$parallel === undefined ? false : _options$parallel,
86 include = options.include,
87 exclude = options.exclude;
88
89
90 this.options = {
91 test,
92 warningsFilter,
93 extractComments,
94 sourceMap,
95 cache,
96 parallel,
97 include,
98 exclude,
99 uglifyOptions: Object.assign({
100 output: {
101 comments: extractComments ? false : /^\**!|@preserve|@license|@cc_on/
102 }
103 }, uglifyOptions)
104 };
105 this.sourceMapsCache = new WeakMap();
106 }
107
108 _createClass(UglifyJsPlugin, [{
109 key: 'buildError',
110 value: function buildError(err, file, inputSourceMap, requestShortener) {
111 // Handling error which should have line, col, filename and message
112 if (err.line) {
113 var sourceMapCacheKey = { file };
114 var sourceMap = this.sourceMapsCache.get(sourceMapCacheKey);
115 if (!sourceMap) {
116 sourceMap = new _sourceMap.SourceMapConsumer(inputSourceMap);
117 this.sourceMapsCache.set(sourceMapCacheKey, sourceMap);
118 }
119 var original = sourceMap && sourceMap.originalPositionFor({
120 line: err.line,
121 column: err.col
122 });
123 if (original && original.source) {
124 return new Error(`${file} from UglifyJs\n${err.message} [${requestShortener.shorten(original.source)}:${original.line},${original.column}][${file}:${err.line},${err.col}]`);
125 }
126 return new Error(`${file} from UglifyJs\n${err.message} [${file}:${err.line},${err.col}]`);
127 } else if (err.stack) {
128 return new Error(`${file} from UglifyJs\n${err.stack}`);
129 }
130 return new Error(`${file} from UglifyJs\n${err.message}`);
131 }
132 }, {
133 key: 'buildWarning',
134 value: function buildWarning(warning, file, inputSourceMap, warningsFilter, requestShortener) {
135 if (!file || !inputSourceMap) {
136 return warning;
137 }
138
139 var sourceMapCacheKey = { file };
140
141 var sourceMap = this.sourceMapsCache.get(sourceMapCacheKey);
142
143 if (!sourceMap) {
144 sourceMap = new _sourceMap.SourceMapConsumer(inputSourceMap);
145 this.sourceMapsCache.set(sourceMapCacheKey, sourceMap);
146 }
147
148 var match = warningRegex.exec(warning);
149 var line = +match[1];
150 var column = +match[2];
151 var original = sourceMap.originalPositionFor({
152 line,
153 column
154 });
155
156 var warningMessage = null;
157
158 if (warningsFilter(original.source)) {
159 warningMessage = warning.replace(warningRegex, '');
160
161 if (original && original.source && original.source !== file) {
162 warningMessage += `[${requestShortener.shorten(original.source)}:${original.line},${original.column}]`;
163 }
164 }
165
166 return warningMessage;
167 }
168 }, {
169 key: 'apply',
170 value: function apply(compiler) {
171 var _this = this;
172
173 var requestShortener = new _RequestShortener2.default(compiler.context);
174
175 var buildModuleFn = function buildModuleFn(moduleArg) {
176 // to get detailed location info about errors
177 moduleArg.useSourceMap = true;
178 };
179
180 var optimizeFn = function optimizeFn(compilation, chunks, callback) {
181 var uglify = new _uglify2.default({
182 cache: _this.options.cache,
183 parallel: _this.options.parallel
184 });
185
186 var uglifiedAssets = new WeakSet();
187 var tasks = [];
188
189 chunks.reduce(function (acc, chunk) {
190 return acc.concat(chunk.files || []);
191 }, []).concat(compilation.additionalChunkAssets || []).filter(_ModuleFilenameHelpers2.default.matchObject.bind(null, _this.options)).forEach(function (file) {
192 var inputSourceMap = void 0;
193 var asset = compilation.assets[file];
194 if (uglifiedAssets.has(asset)) {
195 return;
196 }
197
198 try {
199 var input = void 0;
200
201 if (_this.options.sourceMap && asset.sourceAndMap) {
202 var _asset$sourceAndMap = asset.sourceAndMap(),
203 source = _asset$sourceAndMap.source,
204 map = _asset$sourceAndMap.map;
205
206 input = source;
207
208 if (_utils2.default.isSourceMap(map)) {
209 inputSourceMap = map;
210 } else {
211 inputSourceMap = map;
212 compilation.warnings.push(new Error(`${file} contain invalid source map`));
213 }
214 } else {
215 input = asset.source();
216 inputSourceMap = null;
217 }
218
219 // Handling comment extraction
220 var commentsFile = false;
221 if (_this.options.extractComments) {
222 commentsFile = _this.options.extractComments.filename || `${file}.LICENSE`;
223 if (typeof commentsFile === 'function') {
224 commentsFile = commentsFile(file);
225 }
226 }
227
228 var task = {
229 file,
230 input,
231 inputSourceMap,
232 commentsFile,
233 extractComments: _this.options.extractComments,
234 uglifyOptions: _this.options.uglifyOptions
235 };
236
237 if (_this.options.cache) {
238 task.cacheKey = (0, _serializeJavascript2.default)({
239 'uglify-es': _versions2.default.uglify,
240 'uglifyjs-webpack-plugin': _versions2.default.plugin,
241 'uglifyjs-webpack-plugin-options': _this.options,
242 path: compiler.outputPath ? `${compiler.outputPath}/${file}` : file,
243 hash: _crypto2.default.createHash('md4').update(input).digest('hex')
244 });
245 }
246
247 tasks.push(task);
248 } catch (error) {
249 compilation.errors.push(_this.buildError(error, file, inputSourceMap, requestShortener));
250 }
251 });
252
253 uglify.runTasks(tasks, function (tasksError, results) {
254 if (tasksError) {
255 compilation.errors.push(tasksError);
256 return;
257 }
258
259 results.forEach(function (data, index) {
260 var _tasks$index = tasks[index],
261 file = _tasks$index.file,
262 input = _tasks$index.input,
263 inputSourceMap = _tasks$index.inputSourceMap,
264 commentsFile = _tasks$index.commentsFile;
265 var error = data.error,
266 map = data.map,
267 code = data.code,
268 warnings = data.warnings,
269 extractedComments = data.extractedComments;
270
271 // Handling results
272 // Error case: add errors, and go to next file
273
274 if (error) {
275 compilation.errors.push(_this.buildError(error, file, inputSourceMap, requestShortener));
276
277 return;
278 }
279
280 var outputSource = void 0;
281 if (map) {
282 outputSource = new _webpackSources.SourceMapSource(code, file, JSON.parse(map), input, inputSourceMap);
283 } else {
284 outputSource = new _webpackSources.RawSource(code);
285 }
286
287 // Write extracted comments to commentsFile
288 if (commentsFile && extractedComments.length > 0) {
289 // Add a banner to the original file
290 if (_this.options.extractComments.banner !== false) {
291 var banner = _this.options.extractComments.banner || `For license information please see ${_path2.default.posix.basename(commentsFile)}`;
292
293 if (typeof banner === 'function') {
294 banner = banner(commentsFile);
295 }
296
297 if (banner) {
298 outputSource = new _webpackSources.ConcatSource(`/*! ${banner} */\n`, outputSource);
299 }
300 }
301
302 var commentsSource = new _webpackSources.RawSource(`${extractedComments.join('\n\n')}\n`);
303
304 if (commentsFile in compilation.assets) {
305 // commentsFile already exists, append new comments...
306 if (compilation.assets[commentsFile] instanceof _webpackSources.ConcatSource) {
307 compilation.assets[commentsFile].add('\n');
308 compilation.assets[commentsFile].add(commentsSource);
309 } else {
310 compilation.assets[commentsFile] = new _webpackSources.ConcatSource(compilation.assets[commentsFile], '\n', commentsSource);
311 }
312 } else {
313 compilation.assets[commentsFile] = commentsSource;
314 }
315 }
316
317 // Updating assets
318 uglifiedAssets.add(compilation.assets[file] = outputSource);
319
320 // Handling warnings
321 if (warnings && warnings.length > 0) {
322 warnings.forEach(function (warning) {
323 var builtWarning = _this.buildWarning(warning, file, inputSourceMap, _this.options.warningsFilter, requestShortener);
324
325 if (builtWarning) {
326 compilation.warnings.push(builtWarning);
327 }
328 });
329 }
330 });
331
332 uglify.exit();
333
334 callback();
335 });
336 };
337
338 if (compiler.hooks) {
339 var plugin = { name: 'UglifyJSPlugin' };
340
341 compiler.hooks.compilation.tap(plugin, function (compilation) {
342 if (_this.options.sourceMap) {
343 compilation.hooks.buildModule.tap(plugin, buildModuleFn);
344 }
345
346 compilation.hooks.optimizeChunkAssets.tapAsync(plugin, optimizeFn.bind(_this, compilation));
347 });
348 } else {
349 compiler.plugin('compilation', function (compilation) {
350 if (_this.options.sourceMap) {
351 compilation.plugin('build-module', buildModuleFn);
352 }
353
354 compilation.plugin('optimize-chunk-assets', optimizeFn.bind(_this, compilation));
355 });
356 }
357 }
358 }]);
359
360 return UglifyJsPlugin;
361}();
362
363exports.default = UglifyJsPlugin;
\No newline at end of file