1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | import DuplicatePackageCheckerPlugin from 'duplicate-package-checker-webpack-plugin';
|
7 | import * as fs from 'fs-extra';
|
8 | import * as webpack from 'webpack';
|
9 | import { LicenseWebpackPlugin } from 'license-webpack-plugin';
|
10 | import { LicenseIdentifiedModule } from 'license-webpack-plugin/dist/LicenseIdentifiedModule';
|
11 | import { PluginOptions } from 'license-webpack-plugin/dist/PluginOptions';
|
12 |
|
13 |
|
14 |
|
15 | const IGNORE_TIME_ENTRY = 'ignore';
|
16 |
|
17 | export namespace WPPlugin {
|
18 | |
19 |
|
20 |
|
21 | export class FrontEndPlugin {
|
22 | constructor(buildDir: string, staticDir: string) {
|
23 | this.buildDir = buildDir;
|
24 | this.staticDir = staticDir;
|
25 |
|
26 | this._first = true;
|
27 | }
|
28 |
|
29 | apply(compiler: webpack.Compiler): void {
|
30 | compiler.hooks.afterEmit.tap('FrontEndPlugin', () => {
|
31 |
|
32 | if (!this.staticDir) {
|
33 | return;
|
34 | }
|
35 |
|
36 |
|
37 | if (this._first && fs.existsSync(this.staticDir)) {
|
38 | fs.removeSync(this.staticDir);
|
39 | }
|
40 | this._first = false;
|
41 |
|
42 | fs.copySync(this.buildDir, this.staticDir);
|
43 | });
|
44 | }
|
45 |
|
46 | buildDir: string;
|
47 | staticDir: string;
|
48 |
|
49 | private _first: boolean;
|
50 | }
|
51 |
|
52 | |
53 |
|
54 |
|
55 |
|
56 | class FilterIgnoringWatchFileSystem {
|
57 | constructor(wfs: any, ignored: (path: string) => boolean) {
|
58 | this.wfs = wfs;
|
59 |
|
60 |
|
61 | this.ignored = ignored;
|
62 | }
|
63 |
|
64 | watch(
|
65 | files: any,
|
66 | dirs: any,
|
67 | missing: any,
|
68 | startTime: any,
|
69 | options: any,
|
70 | callback: any,
|
71 | callbackUndelayed: any
|
72 | ) {
|
73 | files = Array.from(files);
|
74 | dirs = Array.from(dirs);
|
75 | const notIgnored = (path: string) => !this.ignored(path);
|
76 | const ignoredFiles = files.filter(this.ignored);
|
77 | const ignoredDirs = dirs.filter(this.ignored);
|
78 |
|
79 | const watcher = this.wfs.watch(
|
80 | files.filter(notIgnored),
|
81 | dirs.filter(notIgnored),
|
82 | missing,
|
83 | startTime,
|
84 | options,
|
85 | (
|
86 | err: any,
|
87 | fileTimestamps: any,
|
88 | dirTimestamps: any,
|
89 | changedFiles: any,
|
90 | removedFiles: any
|
91 | ) => {
|
92 | if (err) return callback(err);
|
93 | for (const path of ignoredFiles) {
|
94 | fileTimestamps.set(path, IGNORE_TIME_ENTRY);
|
95 | }
|
96 |
|
97 | for (const path of ignoredDirs) {
|
98 | dirTimestamps.set(path, IGNORE_TIME_ENTRY);
|
99 | }
|
100 |
|
101 | callback(
|
102 | err,
|
103 | fileTimestamps,
|
104 | dirTimestamps,
|
105 | changedFiles,
|
106 | removedFiles
|
107 | );
|
108 | },
|
109 | callbackUndelayed
|
110 | );
|
111 |
|
112 | return {
|
113 | close: () => watcher.close(),
|
114 | pause: () => watcher.pause(),
|
115 | getContextTimeInfoEntries: () => {
|
116 | const dirTimestamps = watcher.getContextTimeInfoEntries();
|
117 | for (const path of ignoredDirs) {
|
118 | dirTimestamps.set(path, IGNORE_TIME_ENTRY);
|
119 | }
|
120 | return dirTimestamps;
|
121 | },
|
122 | getFileTimeInfoEntries: () => {
|
123 | const fileTimestamps = watcher.getFileTimeInfoEntries();
|
124 | for (const path of ignoredFiles) {
|
125 | fileTimestamps.set(path, IGNORE_TIME_ENTRY);
|
126 | }
|
127 | return fileTimestamps;
|
128 | }
|
129 | };
|
130 | }
|
131 |
|
132 | ignored: (path: string) => boolean;
|
133 | wfs: any;
|
134 | }
|
135 |
|
136 | |
137 |
|
138 |
|
139 |
|
140 | export class FilterWatchIgnorePlugin {
|
141 | constructor(ignored: (path: string) => boolean) {
|
142 | this.ignored = ignored;
|
143 | }
|
144 |
|
145 | apply(compiler: webpack.Compiler): void {
|
146 | compiler.hooks.afterEnvironment.tap('FilterWatchIgnorePlugin', () => {
|
147 | compiler.watchFileSystem = new FilterIgnoringWatchFileSystem(
|
148 | compiler.watchFileSystem,
|
149 | this.ignored
|
150 | );
|
151 | });
|
152 | }
|
153 |
|
154 | ignored: (path: string) => boolean;
|
155 | }
|
156 |
|
157 | export class NowatchDuplicatePackageCheckerPlugin extends DuplicatePackageCheckerPlugin {
|
158 | apply(compiler: webpack.Compiler): void {
|
159 | const options = this.options;
|
160 |
|
161 | compiler.hooks.run.tap(
|
162 | 'NowatchDuplicatePackageCheckerPlugin',
|
163 | compiler => {
|
164 | const p = new DuplicatePackageCheckerPlugin(options);
|
165 | p.apply(compiler);
|
166 | }
|
167 | );
|
168 | }
|
169 |
|
170 | options: DuplicatePackageCheckerPlugin.Options;
|
171 | }
|
172 |
|
173 | |
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 | export interface ILicenseReport {
|
185 | packages: IPackageLicenseInfo[];
|
186 | }
|
187 |
|
188 | |
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 | export interface IPackageLicenseInfo {
|
199 |
|
200 | name: string;
|
201 |
|
202 | versionInfo: string;
|
203 |
|
204 | licenseId: string;
|
205 |
|
206 | extractedText: string;
|
207 | }
|
208 |
|
209 | |
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 | export const DEFAULT_LICENSE_REPORT_FILENAME = 'third-party-licenses.json';
|
221 |
|
222 | |
223 |
|
224 |
|
225 |
|
226 | export class JSONLicenseWebpackPlugin extends LicenseWebpackPlugin {
|
227 | constructor(pluginOptions: PluginOptions = {}) {
|
228 | super({
|
229 | outputFilename: DEFAULT_LICENSE_REPORT_FILENAME,
|
230 | ...pluginOptions,
|
231 | renderLicenses: modules => this.renderLicensesJSON(modules),
|
232 | perChunkOutput: false
|
233 | });
|
234 | }
|
235 |
|
236 |
|
237 | renderLicensesJSON(modules: LicenseIdentifiedModule[]): string {
|
238 | const report: ILicenseReport = { packages: [] };
|
239 |
|
240 | modules.sort((left, right) => (left.name < right.name ? -1 : 1));
|
241 |
|
242 | for (const mod of modules) {
|
243 | report.packages.push({
|
244 | name: mod.name || '',
|
245 | versionInfo: mod.packageJson.version || '',
|
246 | licenseId: mod.licenseId || '',
|
247 | extractedText: mod.licenseText || ''
|
248 | });
|
249 | }
|
250 |
|
251 | return JSON.stringify(report, null, 2);
|
252 | }
|
253 | }
|
254 | }
|