-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
101 lines (95 loc) · 3.3 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
const path = require('path');
const chalk = require('chalk'); // Terminal string styling done right(命令行样式工具)
const ora = require('ora');
const fs = require('fs');
const { searchFiles } = require('./lib/utils'); // deglob: Take a list of glob patterns and return an array of file locations(获取文件位置)
// 由 webpack.config.js 传入的 options
function UnusedPlugin(options) {
this.sourceDirectories = options.directories || [];
this.exclude = options.exclude || [];
this.root = options.root;
this.failOnUnused = options.failOnUnused || false;
this.useGitIgnore = options.useGitIgnore || true;
this.remove = options.remove || false;
}
UnusedPlugin.prototype.apply = function apply(compiler) {
const checkUnused = (compilation, callback) => {
// Files used by Webpack during compilation
// compilation.fileDependencies:模块中引入的源文件路径构成的数组
const usedModules = Array.from(compilation.fileDependencies)
.filter(file => this.sourceDirectories.some(dir => file.indexOf(dir) !== -1))
.reduce(
(obj, item) => Object.assign(obj, {
[item]: true,
}),
{},
);
// Go through sourceDirectories to find all source files
Promise.all(
this.sourceDirectories.map(directory => searchFiles(directory, this.exclude, this.useGitIgnore)),
)
// Find unused source files
.then(files => files.map(array => array.filter(file => !usedModules[file])))
.then(display.bind(this))
.then(continueOrFail.bind(this, this.failOnUnused, compilation))
.then(callback);
};
// webpack 4
if (compiler.hooks && compiler.hooks.emit) {
compiler.hooks.emit.tapAsync('UnusedPlugin', checkUnused);
// webpack 3
} else {
compiler.plugin('emit', checkUnused);
}
};
module.exports = UnusedPlugin;
function continueOrFail(failOnUnused, compilation, allFiles) {
if (allFiles && allFiles.length > 0) {
if (failOnUnused) {
compilation.errors.push(new Error('Unused files found'));
} else {
compilation.warnings.push(new Error('Unused files found'));
}
}
}
function display(filesByDirectory) {
const allFiles = filesByDirectory.reduce(
(array, item) => array.concat(item),
[],
);
if (!allFiles.length) {
return [];
}
process.stdout.write('\n');
process.stdout.write(chalk.green('\n*** Unused Plugin ***\n'));
process.stdout.write(
chalk.red(`${allFiles.length} unused source files found.\n`),
);
filesByDirectory.forEach((files, index) => {
const directory = this.sourceDirectories[index];
const relative = this.root
? path.relative(this.root, directory)
: directory;
process.stdout.write(chalk.blue(`\n● ${relative}\n`));
files.forEach(file => process.stdout.write(
chalk.yellow(` • ${path.relative(directory, file)}\n`),
));
});
if (this.remove) {
process.stdout.write('\n');
// 删除文件
const spinnerDelete = ora('Deleting').start();
allFiles.forEach((img) => {
fs.unlink(img, (err) => {
if (err) {
spinnerDelete.fail();
throw err;
}
});
});
spinnerDelete.text = '🔥 all unused source files deleted.';
spinnerDelete.succeed();
}
process.stdout.write(chalk.green('\n*** Unused Plugin ***\n\n'));
return allFiles;
}