Skip to content

Commit bebafcf

Browse files
authoredMay 15, 2020
refactor: code
BREAKING CHANGE: the missing file error is now an error
1 parent e3803ce commit bebafcf

10 files changed

+90
-146
lines changed
 

‎src/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class CopyPlugin {
2727
compilation.hooks.additionalAssets.tapAsync(
2828
'copy-webpack-plugin',
2929
async (callback) => {
30-
logger.debug('start to adding additionalAssets');
30+
logger.debug('start to adding additional assets');
3131

3232
const globalRef = {
3333
context: compiler.options.context,
@@ -70,7 +70,7 @@ class CopyPlugin {
7070
)
7171
);
7272

73-
logger.debug('end to adding additionalAssets');
73+
logger.debug('end to adding additional assets');
7474

7575
callback();
7676
} catch (error) {

‎src/postProcessPattern.js

+9-12
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export default async function postProcessPattern(globalRef, pattern, file) {
4343
// If this came from a glob, add it to the file watchlist
4444
if (pattern.fromType === 'glob') {
4545
logger.debug(`add ${file.absoluteFrom} as fileDependencies`);
46+
4647
compilation.fileDependencies.add(file.absoluteFrom);
4748
}
4849

@@ -54,16 +55,13 @@ export default async function postProcessPattern(globalRef, pattern, file) {
5455
content = await readFile(inputFileSystem, file.absoluteFrom);
5556
} catch (error) {
5657
compilation.errors.push(error);
58+
5759
return;
5860
}
5961

6062
if (pattern.transform) {
6163
logger.log(`transforming content for '${file.absoluteFrom}'`);
6264

63-
// eslint-disable-next-line no-shadow
64-
const transform = (content, absoluteFrom) =>
65-
pattern.transform(content, absoluteFrom);
66-
6765
if (pattern.cacheTransform) {
6866
if (!globalRef.cacheDir) {
6967
globalRef.cacheDir =
@@ -87,8 +85,8 @@ export default async function postProcessPattern(globalRef, pattern, file) {
8785
);
8886

8987
content = result.data;
90-
} catch (e) {
91-
content = await transform(content, file.absoluteFrom);
88+
} catch (_ignoreError) {
89+
content = await pattern.transform(content, file.absoluteFrom);
9290

9391
logger.debug(`caching transformation for '${file.absoluteFrom}'`);
9492

@@ -97,7 +95,7 @@ export default async function postProcessPattern(globalRef, pattern, file) {
9795
.then(() => content);
9896
}
9997
} else {
100-
content = await transform(content, file.absoluteFrom);
98+
content = await pattern.transform(content, file.absoluteFrom);
10199
}
102100
}
103101

@@ -109,7 +107,7 @@ export default async function postProcessPattern(globalRef, pattern, file) {
109107
// If it doesn't have an extension, remove it from the pattern
110108
// ie. [name].[ext] or [name][ext] both become [name]
111109
if (!path.extname(file.relativeFrom)) {
112-
file.webpackTo = file.webpackTo.replace(/\.?\[ext\]/g, '');
110+
file.webpackTo = file.webpackTo.replace(/\.?\[ext]/g, '');
113111
}
114112

115113
file.webpackTo = loaderUtils.interpolateName(
@@ -137,13 +135,10 @@ export default async function postProcessPattern(globalRef, pattern, file) {
137135
}
138136

139137
const targetPath = normalizePath(file.webpackTo);
140-
141138
const source = new RawSource(content);
142139

143-
const hasAssetsAPI = typeof compilation.emitAsset === 'function';
144-
145140
// For old version webpack 4
146-
if (!hasAssetsAPI) {
141+
if (typeof compilation.emitAsset !== 'function') {
147142
compilation.assets[targetPath] = source;
148143

149144
return;
@@ -156,10 +151,12 @@ export default async function postProcessPattern(globalRef, pattern, file) {
156151
);
157152

158153
compilation.updateAsset(targetPath, source);
154+
159155
return;
160156
}
161157

162158
logger.log(`skipping '${file.webpackTo}', because it already exists`);
159+
163160
return;
164161
}
165162

‎src/preProcessPattern.js

+15-24
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,25 @@ import { stat } from './utils/promisify';
88
export default async function preProcessPattern(globalRef, pattern) {
99
const { context, logger, inputFileSystem } = globalRef;
1010

11-
pattern =
12-
typeof pattern === 'string'
13-
? { from: pattern }
14-
: Object.assign({}, pattern);
15-
16-
pattern.to = pattern.to || '';
17-
pattern.context = pattern.context || context;
18-
19-
if (!path.isAbsolute(pattern.context)) {
20-
pattern.context = path.join(context, pattern.context);
21-
}
22-
23-
pattern.noErrorOnMissing = pattern.noErrorOnMissing || false;
24-
25-
// Todo remove this in next major
26-
const isToDirectory =
27-
path.extname(pattern.to) === '' || pattern.to.slice(-1) === path.sep;
28-
11+
pattern = typeof pattern === 'string' ? { from: pattern } : { ...pattern };
2912
pattern.fromOrigin = pattern.from;
3013
pattern.from = path.normalize(pattern.from);
31-
pattern.context = path.normalize(pattern.context);
32-
pattern.to = path.normalize(pattern.to);
14+
pattern.to = path.normalize(
15+
typeof pattern.to !== 'undefined' ? pattern.to : ''
16+
);
17+
pattern.context = path.normalize(
18+
typeof pattern.context !== 'undefined'
19+
? !path.isAbsolute(pattern.context)
20+
? path.join(context, pattern.context)
21+
: pattern.context
22+
: context
23+
);
3324

3425
logger.debug(`processing from: '${pattern.from}' to: '${pattern.to}'`);
3526

27+
const isToDirectory =
28+
path.extname(pattern.to) === '' || pattern.to.slice(-1) === path.sep;
29+
3630
switch (true) {
3731
// if toType already exists
3832
case !!pattern.toType:
@@ -67,10 +61,7 @@ export default async function preProcessPattern(globalRef, pattern) {
6761

6862
if (stats.isDirectory()) {
6963
pattern.fromType = 'dir';
70-
return pattern;
71-
}
72-
73-
if (stats.isFile()) {
64+
} else if (stats.isFile()) {
7465
pattern.fromType = 'file';
7566
pattern.stats = stats;
7667
}

‎src/processPattern.js

+3-12
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import globby from 'globby';
44

55
import createPatternGlob from './utils/createPatternGlob';
66

7-
/* eslint-disable no-param-reassign */
8-
97
export default async function processPattern(globalRef, pattern) {
108
const { logger, output, compilation } = globalRef;
119

@@ -22,20 +20,13 @@ export default async function processPattern(globalRef, pattern) {
2220
return Promise.resolve();
2321
}
2422

25-
const newWarning = new Error(
23+
const missingError = new Error(
2624
`unable to locate '${pattern.from}' at '${pattern.absoluteFrom}'`
2725
);
28-
const hasWarning = compilation.warnings.some(
29-
// eslint-disable-next-line no-shadow
30-
(warning) => warning.message === newWarning.message
31-
);
3226

33-
// Only display the same message once
34-
if (!hasWarning) {
35-
logger.warn(newWarning.message);
27+
logger.error(missingError.message);
3628

37-
compilation.warnings.push(newWarning);
38-
}
29+
compilation.errors.push(missingError);
3930

4031
return Promise.resolve();
4132
}

‎src/utils/createPatternGlob.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,9 @@ function createPatternGlob(pattern, globalRef) {
6262
/* eslint-enable no-param-reassign */
6363

6464
break;
65-
66-
default:
65+
default: {
6766
logger.debug(`determined '${pattern.absoluteFrom}' is a glob`);
6867

69-
// eslint-disable-next-line no-case-declarations
7068
const contextDependencies = path.normalize(
7169
globParent(pattern.absoluteFrom)
7270
);
@@ -83,7 +81,8 @@ function createPatternGlob(pattern, globalRef) {
8381
getAbsoluteContext(pattern.context),
8482
pattern.fromOrigin
8583
);
86-
/* eslint-enable no-param-reassign */
84+
/* eslint-enable no-param-reassign */
85+
}
8786
}
8887

8988
return pattern;

‎test/CopyPlugin.test.js

+26-78
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { readAssets } from './helpers';
66

77
const FIXTURES_DIR = path.join(__dirname, 'fixtures');
88

9-
describe('apply function', () => {
9+
describe('CopyPlugin', () => {
1010
describe('basic', () => {
1111
it('should copy a file', (done) => {
1212
runEmit({
@@ -221,9 +221,7 @@ describe('apply function', () => {
221221
.then(done)
222222
.catch(done);
223223
});
224-
});
225224

226-
describe('difference path segment separation', () => {
227225
it('should work with linux path segment separation path when "from" is glob', (done) => {
228226
runEmit({
229227
expectedAssetKeys: ['directory/nested/nestedfile.txt'],
@@ -237,34 +235,6 @@ describe('apply function', () => {
237235
.catch(done);
238236
});
239237

240-
// Windows path segment (\\) can not use as path segment in glob, but can use as dirname at linux
241-
it.skip('should work with windows path segment separation path when "from" is glob', (done) => {
242-
runEmit({
243-
expectedAssetKeys: ['directory/nested/nestedfile.txt'],
244-
patterns: [
245-
{
246-
from: 'directory\\nested\\*',
247-
},
248-
],
249-
})
250-
.then(done)
251-
.catch(done);
252-
});
253-
254-
// Windows path segment (\\) can not use as path segment in glob, but can use as dirname at linux
255-
it.skip('should work with mixed path segment separation path when "from" is glob', (done) => {
256-
runEmit({
257-
expectedAssetKeys: ['directory/nested/nestedfile.txt'],
258-
patterns: [
259-
{
260-
from: 'directory/nested\\*',
261-
},
262-
],
263-
})
264-
.then(done)
265-
.catch(done);
266-
});
267-
268238
it('should exclude path with linux path segment separators', (done) => {
269239
runEmit({
270240
expectedAssetKeys: [
@@ -285,28 +255,6 @@ describe('apply function', () => {
285255
.then(done)
286256
.catch(done);
287257
});
288-
289-
// Windows path segment (\\) can not use as path segment in glob, but can use as dirname at linux
290-
it.skip('should exclude path with windows path segment separators', (done) => {
291-
runEmit({
292-
expectedAssetKeys: [
293-
'[!]/hello.txt',
294-
'[special?directory]/(special-*file).txt',
295-
'[special?directory]/directoryfile.txt',
296-
'[special?directory]/nested/nestedfile.txt',
297-
'dir (86)/file.txt',
298-
'dir (86)/nesteddir/deepnesteddir/deepnesteddir.txt',
299-
'dir (86)/nesteddir/nestedfile.txt',
300-
],
301-
patterns: [
302-
{
303-
from: '!(directory)\\**\\*.txt',
304-
},
305-
],
306-
})
307-
.then(done)
308-
.catch(done);
309-
});
310258
});
311259

312260
describe('watch mode', () => {
@@ -538,33 +486,33 @@ describe('apply function', () => {
538486
.catch(done);
539487
});
540488
});
541-
});
542489

543-
describe('logging', () => {
544-
it('should logging', (done) => {
545-
const expectedAssetKeys = ['file.txt'];
546-
547-
run({
548-
patterns: [
549-
{
550-
from: 'file.txt',
551-
},
552-
],
553-
})
554-
.then(({ compiler, stats }) => {
555-
const root = path.resolve(__dirname).replace(/\\/g, '/');
556-
const logs = stats.compilation.logging
557-
.get('copy-webpack-plugin')
558-
.map((entry) =>
559-
entry.args[0].replace(/\\/g, '/').split(root).join('.')
560-
);
490+
describe('logging', () => {
491+
it('should logging', (done) => {
492+
const expectedAssetKeys = ['file.txt'];
561493

562-
expect(
563-
Array.from(Object.keys(readAssets(compiler, stats))).sort()
564-
).toEqual(expectedAssetKeys);
565-
expect({ result: logs }).toMatchSnapshot({ result: logs });
494+
run({
495+
patterns: [
496+
{
497+
from: 'file.txt',
498+
},
499+
],
566500
})
567-
.then(done)
568-
.catch(done);
501+
.then(({ compiler, stats }) => {
502+
const root = path.resolve(__dirname).replace(/\\/g, '/');
503+
const logs = stats.compilation.logging
504+
.get('copy-webpack-plugin')
505+
.map((entry) =>
506+
entry.args[0].replace(/\\/g, '/').split(root).join('.')
507+
);
508+
509+
expect(
510+
Array.from(Object.keys(readAssets(compiler, stats))).sort()
511+
).toEqual(expectedAssetKeys);
512+
expect({ result: logs }).toMatchSnapshot({ result: logs });
513+
})
514+
.then(done)
515+
.catch(done);
516+
});
569517
});
570518
});
+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`logging should logging 1`] = `
3+
exports[`CopyPlugin logging should logging 1`] = `
44
Object {
55
"result": Array [
6-
"start to adding additionalAssets",
6+
"start to adding additional assets",
77
"processing from: 'file.txt' to: '.'",
88
"getting stats for './fixtures/file.txt' to determinate 'fromType'",
99
"determined './fixtures/file.txt' is a file",
@@ -14,7 +14,7 @@ Object {
1414
"getting stats for './fixtures/file.txt' to write to assets",
1515
"reading './fixtures/file.txt' to write to assets",
1616
"writing 'file.txt' to compilation assets from './fixtures/file.txt'",
17-
"end to adding additionalAssets",
17+
"end to adding additional assets",
1818
],
1919
}
2020
`;

‎test/from-option.test.js

+25-7
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ describe('from option', () => {
6767
it('should move a file (symbolic link)', (done) => {
6868
runEmit({
6969
symlink: true,
70-
expectedWarnings:
70+
expectedErrors:
7171
process.platform === 'win32'
7272
? [
7373
new Error(
@@ -86,10 +86,10 @@ describe('from option', () => {
8686
.catch(done);
8787
});
8888

89-
it('should warn when file not found', (done) => {
89+
it('should throw an error on the missing file', (done) => {
9090
runEmit({
9191
expectedAssetKeys: [],
92-
expectedWarnings: [
92+
expectedErrors: [
9393
new Error(
9494
`unable to locate 'nonexistent.txt' at '${FIXTURES_DIR}${path.sep}nonexistent.txt'`
9595
),
@@ -206,7 +206,7 @@ describe('from option', () => {
206206
runEmit({
207207
// Windows doesn't support symbolic link
208208
symlink: true,
209-
expectedWarnings:
209+
expectedErrors:
210210
process.platform === 'win32'
211211
? [
212212
new Error(
@@ -290,10 +290,10 @@ describe('from option', () => {
290290
.catch(done);
291291
});
292292

293-
it('should warn when directory not found', (done) => {
293+
it('should throw an error on the missing directory', (done) => {
294294
runEmit({
295295
expectedAssetKeys: [],
296-
expectedWarnings: [
296+
expectedErrors: [
297297
new Error(
298298
`unable to locate 'nonexistent' at '${FIXTURES_DIR}${path.sep}nonexistent'`
299299
),
@@ -471,7 +471,7 @@ describe('from option', () => {
471471
runEmit({
472472
// Windows doesn't support symbolic link
473473
symlink: true,
474-
expectedWarnings:
474+
expectedErrors:
475475
process.platform === 'win32'
476476
? [
477477
new Error(
@@ -499,5 +499,23 @@ describe('from option', () => {
499499
.then(done)
500500
.catch(done);
501501
});
502+
503+
it('should throw an error on the missing glob', (done) => {
504+
runEmit({
505+
expectedAssetKeys: [],
506+
expectedErrors: [
507+
new Error(
508+
`unable to locate 'nonexistent${path.sep}**${path.sep}*' at '${FIXTURES_DIR}${path.sep}nonexistent${path.sep}**${path.sep}*'`
509+
),
510+
],
511+
patterns: [
512+
{
513+
from: 'nonexistent/**/*',
514+
},
515+
],
516+
})
517+
.then(done)
518+
.catch(done);
519+
});
502520
});
503521
});

‎test/globOptions-option.test.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe('from option', () => {
4141
describe('globOptions ignore option', () => {
4242
it('should ignore files when "from" is a file', (done) => {
4343
runEmit({
44-
expectedWarnings: [
44+
expectedErrors: [
4545
new Error(
4646
`unable to locate 'file.txt' at '${FIXTURES_DIR}${path.sep}file.txt'`
4747
),
@@ -218,7 +218,7 @@ describe('globOptions ignore option', () => {
218218

219219
it('should ignores all files even if they start with a dot', (done) => {
220220
runEmit({
221-
expectedWarnings: [
221+
expectedErrors: [
222222
new Error(
223223
`unable to locate 'directory' at '${FIXTURES_DIR}${path.sep}directory${path.sep}**${path.sep}*'`
224224
),
@@ -238,7 +238,7 @@ describe('globOptions ignore option', () => {
238238

239239
it('should ignore files when "from" is a file (global ignore)', (done) => {
240240
runEmit({
241-
expectedWarnings: [
241+
expectedErrors: [
242242
new Error(
243243
`unable to locate 'file.txt' at '${FIXTURES_DIR}${path.sep}file.txt'`
244244
),

‎test/toType-option.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe('toType option', () => {
8686
it('should warn when file not found and stats is undefined', (done) => {
8787
runEmit({
8888
expectedAssetKeys: [],
89-
expectedWarnings: [
89+
expectedErrors: [
9090
new Error(
9191
`unable to locate 'nonexistent.txt' at '${FIXTURES_DIR}${path.sep}nonexistent.txt'`
9292
),

0 commit comments

Comments
 (0)
Please sign in to comment.