Skip to content

Commit 2b4d2a4

Browse files
authoredSep 13, 2019
feat: emit warning when comment file conlict with an existing asset (#156)
1 parent efbd383 commit 2b4d2a4

5 files changed

+133
-24
lines changed
 

‎package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"prettier": "^1.18.2",
7272
"standard-version": "^7.0.0",
7373
"uglify-js": "^3.6.0",
74-
"webpack": "^4.39.3"
74+
"webpack": "^4.40.1"
7575
},
7676
"keywords": [
7777
"uglify",

‎src/index.js

+62-20
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,28 @@ class TerserPlugin {
154154
return `Terser Plugin: ${warningMessage}${locationMessage}`;
155155
}
156156

157+
static removeQueryString(filename) {
158+
let targetFilename = filename;
159+
160+
const queryStringIdx = targetFilename.indexOf('?');
161+
162+
if (queryStringIdx >= 0) {
163+
targetFilename = targetFilename.substr(0, queryStringIdx);
164+
}
165+
166+
return targetFilename;
167+
}
168+
169+
static hasAsset(commentFilename, assets) {
170+
const assetFilenames = Object.keys(assets).map((assetFilename) =>
171+
TerserPlugin.removeQueryString(assetFilename)
172+
);
173+
174+
return assetFilenames.includes(
175+
TerserPlugin.removeQueryString(commentFilename)
176+
);
177+
}
178+
157179
apply(compiler) {
158180
this.options.sourceMap =
159181
typeof this.options.sourceMap === 'undefined'
@@ -212,16 +234,16 @@ class TerserPlugin {
212234
}
213235

214236
// Handling comment extraction
215-
let commentsFile = false;
237+
let commentsFilename = false;
216238

217239
if (this.options.extractComments) {
218-
commentsFile =
240+
commentsFilename =
219241
this.options.extractComments.filename ||
220242
'[file].LICENSE[query]';
221243

222244
// Todo remove this in next major release
223-
if (typeof commentsFile === 'function') {
224-
commentsFile = commentsFile.bind(null, file);
245+
if (typeof commentsFilename === 'function') {
246+
commentsFilename = commentsFilename.bind(null, file);
225247
}
226248

227249
let query = '';
@@ -243,14 +265,28 @@ class TerserPlugin {
243265

244266
const data = { filename, basename, query };
245267

246-
commentsFile = compilation.getPath(commentsFile, data);
268+
commentsFilename = compilation.getPath(commentsFilename, data);
269+
}
270+
271+
if (
272+
commentsFilename &&
273+
TerserPlugin.hasAsset(commentsFilename, compilation.assets)
274+
) {
275+
// Todo make error and stop uglifing in next major release
276+
compilation.warnings.push(
277+
new Error(
278+
`The comment file "${TerserPlugin.removeQueryString(
279+
commentsFilename
280+
)}" conflicts with an existing asset, this may lead to code corruption, please use a different name`
281+
)
282+
);
247283
}
248284

249285
const task = {
250286
file,
251287
input,
252288
inputSourceMap,
253-
commentsFile,
289+
commentsFilename,
254290
extractComments: this.options.extractComments,
255291
terserOptions: this.options.terserOptions,
256292
minify: this.options.minify,
@@ -299,7 +335,7 @@ class TerserPlugin {
299335
await taskRunner.exit();
300336

301337
completedTasks.forEach((completedTask, index) => {
302-
const { file, input, inputSourceMap, commentsFile } = tasks[index];
338+
const { file, input, inputSourceMap, commentsFilename } = tasks[index];
303339
const { error, map, code, warnings } = completedTask;
304340
let { extractedComments } = completedTask;
305341

@@ -339,11 +375,15 @@ class TerserPlugin {
339375
outputSource = new RawSource(code);
340376
}
341377

342-
// Write extracted comments to commentsFile
343-
if (commentsFile && extractedComments && extractedComments.length > 0) {
344-
if (commentsFile in compilation.assets) {
378+
// Write extracted comments to commentsFilename
379+
if (
380+
commentsFilename &&
381+
extractedComments &&
382+
extractedComments.length > 0
383+
) {
384+
if (commentsFilename in compilation.assets) {
345385
const commentsFileSource = compilation.assets[
346-
commentsFile
386+
commentsFilename
347387
].source();
348388

349389
extractedComments = extractedComments.filter(
@@ -357,11 +397,11 @@ class TerserPlugin {
357397
let banner =
358398
this.options.extractComments.banner ||
359399
`For license information please see ${path.posix.basename(
360-
commentsFile
400+
commentsFilename
361401
)}`;
362402

363403
if (typeof banner === 'function') {
364-
banner = banner(commentsFile);
404+
banner = banner(commentsFilename);
365405
}
366406

367407
if (banner) {
@@ -376,22 +416,24 @@ class TerserPlugin {
376416
`${extractedComments.join('\n\n')}\n`
377417
);
378418

379-
if (commentsFile in compilation.assets) {
419+
if (commentsFilename in compilation.assets) {
380420
// commentsFile already exists, append new comments...
381-
if (compilation.assets[commentsFile] instanceof ConcatSource) {
382-
compilation.assets[commentsFile].add('\n');
383-
compilation.assets[commentsFile].add(commentsSource);
421+
if (
422+
compilation.assets[commentsFilename] instanceof ConcatSource
423+
) {
424+
compilation.assets[commentsFilename].add('\n');
425+
compilation.assets[commentsFilename].add(commentsSource);
384426
} else {
385427
// eslint-disable-next-line no-param-reassign
386-
compilation.assets[commentsFile] = new ConcatSource(
387-
compilation.assets[commentsFile],
428+
compilation.assets[commentsFilename] = new ConcatSource(
429+
compilation.assets[commentsFilename],
388430
'\n',
389431
commentsSource
390432
);
391433
}
392434
} else {
393435
// eslint-disable-next-line no-param-reassign
394-
compilation.assets[commentsFile] = commentsSource;
436+
compilation.assets[commentsFilename] = commentsSource;
395437
}
396438
}
397439
}

‎test/__snapshots__/extractComments-option.test.js.snap

+18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`extractComments option should match snapshot and throw error when comment file exists in assets: errors 1`] = `Array []`;
4+
5+
exports[`extractComments option should match snapshot and throw error when comment file exists in assets: errors 2`] = `Array []`;
6+
7+
exports[`extractComments option should match snapshot and throw error when comment file exists in assets: warnings 1`] = `
8+
Array [
9+
"Error: The comment file \\"one.js\\" conflicts with an existing asset, this may lead to code corruption, please use a different name",
10+
"Error: The comment file \\"one.js\\" conflicts with an existing asset, this may lead to code corruption, please use a different name",
11+
]
12+
`;
13+
14+
exports[`extractComments option should match snapshot and throw error when comment file exists in assets: warnings 2`] = `
15+
Array [
16+
"Error: The comment file \\"one.js\\" conflicts with an existing asset, this may lead to code corruption, please use a different name",
17+
"Error: The comment file \\"one.js\\" conflicts with an existing asset, this may lead to code corruption, please use a different name",
18+
]
19+
`;
20+
321
exports[`extractComments option should match snapshot for a "function" value: assets 1`] = `
422
Object {
523
"chunks/4.4.735e78ca27ceea7298d5.js": "/*! For license information please see 4.4.735e78ca27ceea7298d5.js.LICENSE */

‎test/extractComments-option.test.js

+49
Original file line numberDiff line numberDiff line change
@@ -406,4 +406,53 @@ describe('extractComments option', () => {
406406
expect(warnings).toMatchSnapshot('warnings');
407407
expect(getAssets(stats, compiler)).toMatchSnapshot('assets');
408408
});
409+
410+
it('should match snapshot and throw error when comment file exists in assets', async () => {
411+
compiler = createCompiler({
412+
entry: {
413+
one: `${__dirname}/fixtures/comments.js`,
414+
},
415+
});
416+
417+
new TerserPlugin({
418+
extractComments: {
419+
condition: true,
420+
filename: 'one.js',
421+
},
422+
}).apply(compiler);
423+
424+
const stats = await compile(compiler);
425+
426+
const errors = stats.compilation.errors.map(cleanErrorStack);
427+
const warnings = stats.compilation.warnings.map(cleanErrorStack);
428+
429+
expect(errors).toMatchSnapshot('errors');
430+
expect(warnings).toMatchSnapshot('warnings');
431+
});
432+
433+
it('should match snapshot and throw error when comment file exists in assets', async () => {
434+
compiler = createCompiler({
435+
entry: {
436+
one: `${__dirname}/fixtures/comments.js`,
437+
},
438+
output: {
439+
filename: '[name].js?[chunkhash]',
440+
},
441+
});
442+
443+
new TerserPlugin({
444+
extractComments: {
445+
condition: true,
446+
filename: 'one.js?foo=bar',
447+
},
448+
}).apply(compiler);
449+
450+
const stats = await compile(compiler);
451+
452+
const errors = stats.compilation.errors.map(cleanErrorStack);
453+
const warnings = stats.compilation.warnings.map(cleanErrorStack);
454+
455+
expect(errors).toMatchSnapshot('errors');
456+
expect(warnings).toMatchSnapshot('warnings');
457+
});
409458
});

0 commit comments

Comments
 (0)
Failed to load comments.