@serwist/webpack-plugin 8.4.4 → 9.0.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/chunks/relative-to-output-path.js +10 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.internal.d.ts +3 -1
  5. package/dist/index.internal.d.ts.map +1 -0
  6. package/dist/index.internal.js +3 -7
  7. package/dist/index.js +29 -317
  8. package/dist/inject-manifest.d.ts +7 -3
  9. package/dist/inject-manifest.d.ts.map +1 -0
  10. package/dist/lib/child-compilation-plugin.d.ts +1 -0
  11. package/dist/lib/child-compilation-plugin.d.ts.map +1 -0
  12. package/dist/lib/get-asset-hash.d.ts +1 -0
  13. package/dist/lib/get-asset-hash.d.ts.map +1 -0
  14. package/dist/lib/get-manifest-entries-from-compilation.d.ts +2 -1
  15. package/dist/lib/get-manifest-entries-from-compilation.d.ts.map +1 -0
  16. package/dist/lib/get-script-files-for-chunks.d.ts +2 -1
  17. package/dist/lib/get-script-files-for-chunks.d.ts.map +1 -0
  18. package/dist/lib/get-sourcemap-asset-name.d.ts +2 -1
  19. package/dist/lib/get-sourcemap-asset-name.d.ts.map +1 -0
  20. package/dist/lib/relative-to-output-path.d.ts +5 -4
  21. package/dist/lib/relative-to-output-path.d.ts.map +1 -0
  22. package/dist/lib/resolve-webpack-url.d.ts +2 -1
  23. package/dist/lib/resolve-webpack-url.d.ts.map +1 -0
  24. package/package.json +24 -29
  25. package/src/index.internal.ts +4 -0
  26. package/src/index.ts +11 -0
  27. package/src/inject-manifest.ts +287 -0
  28. package/src/lib/child-compilation-plugin.ts +66 -0
  29. package/src/lib/get-asset-hash.ts +27 -0
  30. package/src/lib/get-manifest-entries-from-compilation.ts +214 -0
  31. package/src/lib/get-script-files-for-chunks.ts +38 -0
  32. package/src/lib/get-sourcemap-asset-name.ts +47 -0
  33. package/src/lib/relative-to-output-path.ts +29 -0
  34. package/src/lib/resolve-webpack-url.ts +27 -0
  35. package/dist/index.cjs +0 -579
  36. package/dist/index.d.cts +0 -0
  37. package/dist/index.internal.cjs +0 -54
  38. package/dist/index.internal.d.cts +0 -2
  39. package/dist/inject-manifest.d.cts +0 -0
  40. package/dist/lib/child-compilation-plugin.d.cts +0 -20
  41. package/dist/lib/get-asset-hash.d.cts +0 -8
  42. package/dist/lib/get-manifest-entries-from-compilation.d.cts +0 -6
  43. package/dist/lib/get-script-files-for-chunks.d.cts +0 -0
  44. package/dist/lib/get-sourcemap-asset-name.d.cts +0 -0
  45. package/dist/lib/relative-to-output-path.d.cts +0 -11
  46. package/dist/lib/resolve-webpack-url.d.cts +0 -12
  47. package/dist/relative-to-output-path.cjs +0 -22
  48. package/dist/relative-to-output-path.js +0 -20
@@ -16,4 +16,5 @@ import type { Compilation } from "webpack";
16
16
  * name of that asset. Otherwise, it will return undefined.
17
17
  * @private
18
18
  */
19
- export declare function getSourcemapAssetName(compilation: Compilation, swContents: string, swDest: string): string | undefined;
19
+ export declare const getSourcemapAssetName: (compilation: Compilation, swContents: string, swDest: string) => string | undefined;
20
+ //# sourceMappingURL=get-sourcemap-asset-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-sourcemap-asset-name.d.ts","sourceRoot":"","sources":["../../src/lib/get-sourcemap-asset-name.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,qBAAqB,gBAAiB,WAAW,cAAc,MAAM,UAAU,MAAM,KAAG,MAAM,GAAG,SAiB7G,CAAC"}
@@ -1,11 +1,12 @@
1
1
  import type { Compilation } from "webpack";
2
2
  /**
3
3
  * @param compilation The webpack compilation.
4
- * @param swDest The original swDest value.
4
+ * @param path The original path value.
5
5
  *
6
- * @returns If swDest was not absolute, the returns swDest as-is.
7
- * Otherwise, returns swDest relative to the compilation's output path.
6
+ * @returns If path was not absolute, the returns path as-is.
7
+ * Otherwise, returns path relative to the compilation's output path.
8
8
  *
9
9
  * @private
10
10
  */
11
- export declare function relativeToOutputPath(compilation: Compilation, swDest: string): string;
11
+ export declare const relativeToOutputPath: (compilation: Compilation, path: string) => string;
12
+ //# sourceMappingURL=relative-to-output-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relative-to-output-path.d.ts","sourceRoot":"","sources":["../../src/lib/relative-to-output-path.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,gBAAiB,WAAW,QAAQ,MAAM,KAAG,MAQ7E,CAAC"}
@@ -9,4 +9,5 @@
9
9
  * @returns Joined file path
10
10
  * @private
11
11
  */
12
- export declare function resolveWebpackURL(publicPath: string, ...paths: Array<string>): string;
12
+ export declare const resolveWebpackURL: (publicPath: string, ...paths: string[]) => string;
13
+ //# sourceMappingURL=resolve-webpack-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-webpack-url.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-webpack-url.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,eAAgB,MAAM,YAAY,MAAM,EAAE,KAAG,MAO1E,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@serwist/webpack-plugin",
3
- "version": "8.4.4",
3
+ "version": "9.0.0-preview.1",
4
4
  "type": "module",
5
5
  "description": "A plugin for your Webpack build process, helping you generate a manifest of local files that should be precached.",
6
6
  "files": [
7
- "dist",
8
- "!dist/**/dts"
7
+ "src",
8
+ "dist"
9
9
  ],
10
10
  "keywords": [
11
11
  "serwist",
@@ -18,15 +18,14 @@
18
18
  "file manifest"
19
19
  ],
20
20
  "engines": {
21
- "node": ">=16.0.0"
21
+ "node": ">=18.0.0"
22
22
  },
23
23
  "author": "Google's Web DevRel Team, Serwist's Team",
24
24
  "license": "MIT",
25
25
  "repository": "serwist/serwist",
26
26
  "bugs": "https://github.com/serwist/serwist/issues",
27
27
  "homepage": "https://serwist.pages.dev",
28
- "module": "./dist/index.js",
29
- "main": "./dist/index.cjs",
28
+ "main": "./dist/index.js",
30
29
  "types": "./dist/index.d.ts",
31
30
  "typesVersions": {
32
31
  "*": {
@@ -37,41 +36,37 @@
37
36
  },
38
37
  "exports": {
39
38
  ".": {
40
- "import": {
41
- "types": "./dist/index.d.ts",
42
- "default": "./dist/index.js"
43
- },
44
- "require": {
45
- "types": "./dist/index.d.cts",
46
- "default": "./dist/index.cjs"
47
- }
39
+ "types": "./dist/index.d.ts",
40
+ "default": "./dist/index.js"
48
41
  },
49
42
  "./internal": {
50
- "import": {
51
- "types": "./dist/index.internal.d.ts",
52
- "default": "./dist/index.internal.js"
53
- },
54
- "require": {
55
- "types": "./dist/index.internal.d.cts",
56
- "default": "./dist/index.internal.cjs"
57
- }
43
+ "types": "./dist/index.internal.d.ts",
44
+ "default": "./dist/index.internal.js"
58
45
  },
59
46
  "./package.json": "./package.json"
60
47
  },
61
48
  "dependencies": {
62
49
  "fast-json-stable-stringify": "2.1.0",
50
+ "pretty-bytes": "6.1.1",
63
51
  "upath": "2.0.1",
64
- "@serwist/build": "8.4.4"
52
+ "@serwist/build": "9.0.0-preview.1"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "20.11.16",
56
+ "@types/webpack": "5.28.5",
57
+ "rollup": "4.9.6",
58
+ "typescript": "5.4.0-dev.20240203",
59
+ "webpack": "5.90.1",
60
+ "@serwist/constants": "9.0.0-preview.1"
65
61
  },
66
62
  "peerDependencies": {
63
+ "typescript": ">=5.0.0",
67
64
  "webpack": "4.4.0 || ^5.9.0"
68
65
  },
69
- "devDependencies": {
70
- "@types/node": "20.10.5",
71
- "@types/webpack": "5.28.5",
72
- "pretty-bytes": "6.1.1",
73
- "rollup": "4.9.1",
74
- "@serwist/constants": "8.4.4"
66
+ "peerDependenciesMeta": {
67
+ "typescript": {
68
+ "optional": true
69
+ }
75
70
  },
76
71
  "scripts": {
77
72
  "build": "rimraf dist && cross-env NODE_ENV=production rollup --config rollup.config.js",
@@ -0,0 +1,4 @@
1
+ import { ChildCompilationPlugin } from "./lib/child-compilation-plugin.js";
2
+ import { relativeToOutputPath } from "./lib/relative-to-output-path.js";
3
+
4
+ export { ChildCompilationPlugin, relativeToOutputPath };
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import { InjectManifest } from "./inject-manifest.js";
10
+
11
+ export { InjectManifest };
@@ -0,0 +1,287 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+ import type { WebpackInjectManifestOptions } from "@serwist/build";
9
+ import { escapeRegExp, replaceAndUpdateSourceMap, validateWebpackInjectManifestOptions } from "@serwist/build";
10
+ import stringify from "fast-json-stable-stringify";
11
+ import prettyBytes from "pretty-bytes";
12
+ import upath from "upath";
13
+ import type { Compilation } from "webpack";
14
+ import webpack from "webpack";
15
+
16
+ import { getManifestEntriesFromCompilation } from "./lib/get-manifest-entries-from-compilation.js";
17
+ import { getSourcemapAssetName } from "./lib/get-sourcemap-asset-name.js";
18
+ import { relativeToOutputPath } from "./lib/relative-to-output-path.js";
19
+
20
+ // Used to keep track of swDest files written by *any* instance of this plugin.
21
+ // See https://github.com/GoogleChrome/workbox/issues/2181
22
+ const _generatedAssetNames = new Set<string>();
23
+
24
+ /**
25
+ * This class supports compiling a service worker file provided via `swSrc`,
26
+ * and injecting into that service worker a list of URLs and revision
27
+ * information for precaching based on the webpack asset pipeline.
28
+ *
29
+ * Use an instance of `InjectManifest` in the
30
+ * [`plugins` array](https://webpack.js.org/concepts/plugins/#usage) of a
31
+ * webpack config.
32
+ *
33
+ * In addition to injecting the manifest, this plugin will perform a compilation
34
+ * of the `swSrc` file, using the options from the main webpack configuration.
35
+ *
36
+ * ```
37
+ * // The following lists some common options; see the rest of the documentation
38
+ * // for the full set of options and defaults.
39
+ * new InjectManifest({
40
+ * exclude: [/.../, '...'],
41
+ * maximumFileSizeToCacheInBytes: ...,
42
+ * swSrc: '...',
43
+ * });
44
+ * ```
45
+ */
46
+ export class InjectManifest {
47
+ protected config: WebpackInjectManifestOptions;
48
+ private alreadyCalled: boolean;
49
+
50
+ /**
51
+ * Creates an instance of InjectManifest.
52
+ */
53
+ constructor(config: WebpackInjectManifestOptions) {
54
+ this.config = config;
55
+ this.alreadyCalled = false;
56
+ }
57
+
58
+ /**
59
+ * @param compiler default compiler object passed from webpack
60
+ *
61
+ * @private
62
+ */
63
+ propagateWebpackConfig(compiler: webpack.Compiler): void {
64
+ const parsedSwSrc = upath.parse(this.config.swSrc);
65
+ // Because this.config is listed last, properties that are already set
66
+ // there take precedence over derived properties from the compiler.
67
+ this.config = Object.assign(
68
+ {
69
+ mode: compiler.options.mode,
70
+ // Use swSrc with a hardcoded .js extension, in case swSrc is a .ts file.
71
+ swDest: `${parsedSwSrc.name}.js`,
72
+ },
73
+ this.config,
74
+ );
75
+ }
76
+
77
+ /**
78
+ * `getManifestEntriesFromCompilation` with a few additional checks.
79
+ *
80
+ * @private
81
+ */
82
+ async getManifestEntries(compilation: webpack.Compilation, config: WebpackInjectManifestOptions) {
83
+ if (config.disablePrecacheManifest) {
84
+ return {
85
+ size: 0,
86
+ sortedEntries: undefined,
87
+ manifestString: "undefined",
88
+ };
89
+ }
90
+
91
+ // See https://github.com/GoogleChrome/workbox/issues/1790
92
+ if (this.alreadyCalled) {
93
+ const warningMessage = `${this.constructor.name} has been called multiple times, perhaps due to running webpack in --watch mode. The precache manifest generated after the first call may be inaccurate! Please see https://github.com/GoogleChrome/workbox/issues/1790 for more information.`;
94
+
95
+ if (!compilation.warnings.some((warning) => warning instanceof Error && warning.message === warningMessage)) {
96
+ compilation.warnings.push(new Error(warningMessage) as webpack.WebpackError);
97
+ }
98
+ } else {
99
+ this.alreadyCalled = true;
100
+ }
101
+
102
+ // Ensure that we don't precache any of the assets generated by *any*
103
+ // instance of this plugin.
104
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
105
+ config.exclude!.push(({ asset }) => _generatedAssetNames.has(asset.name));
106
+
107
+ const { size, sortedEntries } = await getManifestEntriesFromCompilation(compilation, config);
108
+
109
+ let manifestString = stringify(sortedEntries);
110
+ if (
111
+ this.config.compileSrc &&
112
+ // See https://github.com/GoogleChrome/workbox/issues/2729
113
+ !(compilation.options?.devtool === "eval-cheap-source-map" && compilation.options.optimization?.minimize)
114
+ ) {
115
+ // See https://github.com/GoogleChrome/workbox/issues/2263
116
+ manifestString = manifestString.replace(/"/g, `'`);
117
+ }
118
+
119
+ return { size, sortedEntries, manifestString };
120
+ }
121
+
122
+ /**
123
+ * @param compiler default compiler object passed from webpack
124
+ *
125
+ * @private
126
+ */
127
+ apply(compiler: webpack.Compiler): void {
128
+ this.propagateWebpackConfig(compiler);
129
+
130
+ compiler.hooks.make.tapPromise(this.constructor.name, (compilation) =>
131
+ this.handleMake(compilation, compiler).catch((error: webpack.WebpackError) => {
132
+ compilation.errors.push(error);
133
+ }),
134
+ );
135
+
136
+ const { PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER } = webpack.Compilation;
137
+ // Specifically hook into thisCompilation, as per
138
+ // https://github.com/webpack/webpack/issues/11425#issuecomment-690547848
139
+ compiler.hooks.thisCompilation.tap(this.constructor.name, (compilation) => {
140
+ compilation.hooks.processAssets.tapPromise(
141
+ {
142
+ name: this.constructor.name,
143
+ // TODO(jeffposnick): This may need to change eventually.
144
+ // See https://github.com/webpack/webpack/issues/11822#issuecomment-726184972
145
+ stage: PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER - 10,
146
+ },
147
+ () =>
148
+ this.addAssets(compilation).catch((error: webpack.WebpackError) => {
149
+ compilation.errors.push(error);
150
+ }),
151
+ );
152
+ });
153
+ }
154
+
155
+ /**
156
+ * @param compilation The webpack compilation.
157
+ * @param parentCompiler The webpack parent compiler.
158
+ *
159
+ * @private
160
+ */
161
+ async performChildCompilation(compilation: webpack.Compilation, parentCompiler: webpack.Compiler): Promise<void> {
162
+ const outputOptions: Parameters<Compilation["createChildCompiler"]>["1"] = {
163
+ filename: this.config.swDest,
164
+ };
165
+
166
+ const childCompiler = compilation.createChildCompiler(this.constructor.name, outputOptions, []);
167
+
168
+ childCompiler.context = parentCompiler.context;
169
+ childCompiler.inputFileSystem = parentCompiler.inputFileSystem;
170
+ childCompiler.outputFileSystem = parentCompiler.outputFileSystem;
171
+
172
+ if (Array.isArray(this.config.webpackCompilationPlugins)) {
173
+ for (const plugin of this.config.webpackCompilationPlugins) {
174
+ plugin.apply(childCompiler);
175
+ }
176
+ }
177
+
178
+ new webpack.EntryPlugin(parentCompiler.context, this.config.swSrc, this.constructor.name).apply(childCompiler);
179
+
180
+ await new Promise<void>((resolve, reject) => {
181
+ childCompiler.runAsChild((error, _entries, childCompilation) => {
182
+ if (error) {
183
+ reject(error);
184
+ } else {
185
+ compilation.warnings = compilation.warnings.concat(childCompilation?.warnings ?? []);
186
+ compilation.errors = compilation.errors.concat(childCompilation?.errors ?? []);
187
+
188
+ resolve();
189
+ }
190
+ });
191
+ });
192
+ }
193
+
194
+ /**
195
+ * @param compilation The webpack compilation.
196
+ * @param parentCompiler The webpack parent compiler.
197
+ *
198
+ * @private
199
+ */
200
+ addSrcToAssets(compilation: webpack.Compilation, parentCompiler: webpack.Compiler): void {
201
+ // eslint-disable-next-line
202
+ const source = (parentCompiler.inputFileSystem as any).readFileSync(this.config.swSrc);
203
+ compilation.emitAsset(this.config.swDest!, new webpack.sources.RawSource(source));
204
+ }
205
+
206
+ /**
207
+ * @param compilation The webpack compilation.
208
+ * @param parentCompiler The webpack parent compiler.
209
+ *
210
+ * @private
211
+ */
212
+ async handleMake(compilation: webpack.Compilation, parentCompiler: webpack.Compiler): Promise<void> {
213
+ this.config = await validateWebpackInjectManifestOptions(this.config);
214
+ this.config.swDest = relativeToOutputPath(compilation, this.config.swDest!);
215
+ _generatedAssetNames.add(this.config.swDest);
216
+
217
+ if (this.config.compileSrc) {
218
+ await this.performChildCompilation(compilation, parentCompiler);
219
+ } else {
220
+ this.addSrcToAssets(compilation, parentCompiler);
221
+ // This used to be a fatal error, but just warn at runtime because we
222
+ // can't validate it easily.
223
+ if (Array.isArray(this.config.webpackCompilationPlugins) && this.config.webpackCompilationPlugins.length > 0) {
224
+ compilation.warnings.push(
225
+ new Error("compileSrc is false, so the " + "webpackCompilationPlugins option will be ignored.") as webpack.WebpackError,
226
+ );
227
+ }
228
+ }
229
+ }
230
+
231
+ /**
232
+ * @param compilation The webpack compilation.
233
+ *
234
+ * @private
235
+ */
236
+ async addAssets(compilation: webpack.Compilation): Promise<void> {
237
+ const config = Object.assign({}, this.config);
238
+
239
+ const { size, sortedEntries, manifestString } = await this.getManifestEntries(compilation, config);
240
+
241
+ // See https://webpack.js.org/contribute/plugin-patterns/#monitoring-the-watch-graph
242
+ const absoluteSwSrc = upath.resolve(config.swSrc);
243
+ compilation.fileDependencies.add(absoluteSwSrc);
244
+
245
+ const swAsset = compilation.getAsset(config.swDest!);
246
+ const swAssetString = swAsset!.source.source().toString();
247
+
248
+ const globalRegexp = new RegExp(escapeRegExp(config.injectionPoint!), "g");
249
+ const injectionResults = swAssetString.match(globalRegexp);
250
+
251
+ if (!injectionResults) {
252
+ throw new Error(`Can't find ${config.injectionPoint} in your SW source.`);
253
+ }
254
+ if (injectionResults.length !== 1) {
255
+ throw new Error(
256
+ `Multiple instances of ${config.injectionPoint} were found in your SW source. Include it only once. For more info, see https://github.com/GoogleChrome/workbox/issues/2681`,
257
+ );
258
+ }
259
+
260
+ const sourcemapAssetName = getSourcemapAssetName(compilation, swAssetString, config.swDest!);
261
+
262
+ if (sourcemapAssetName) {
263
+ _generatedAssetNames.add(sourcemapAssetName);
264
+ const sourcemapAsset = compilation.getAsset(sourcemapAssetName);
265
+ const { source, map } = await replaceAndUpdateSourceMap({
266
+ jsFilename: config.swDest!,
267
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
268
+ originalMap: JSON.parse(sourcemapAsset!.source.source().toString()),
269
+ originalSource: swAssetString,
270
+ replaceString: manifestString,
271
+ searchString: config.injectionPoint!,
272
+ });
273
+
274
+ compilation.updateAsset(sourcemapAssetName, new webpack.sources.RawSource(map));
275
+ compilation.updateAsset(config.swDest!, new webpack.sources.RawSource(source));
276
+ } else {
277
+ // If there's no sourcemap associated with swDest, a simple string
278
+ // replacement will suffice.
279
+ compilation.updateAsset(config.swDest!, new webpack.sources.RawSource(swAssetString.replace(config.injectionPoint!, manifestString)));
280
+ }
281
+
282
+ if (compilation.getLogger) {
283
+ const logger = compilation.getLogger(this.constructor.name);
284
+ logger.info(`The service worker at ${config.swDest ?? ""} will precache ${sortedEntries?.length ?? 0} URLs, totaling ${prettyBytes(size)}.`);
285
+ }
286
+ }
287
+ }
@@ -0,0 +1,66 @@
1
+ import type { Compilation, WebpackPluginInstance } from "webpack";
2
+ import webpack from "webpack";
3
+
4
+ import { relativeToOutputPath } from "./relative-to-output-path.js";
5
+
6
+ export interface ChildCompilationPluginOptions {
7
+ src: string;
8
+ dest: string;
9
+ plugins?: WebpackPluginInstance[];
10
+ }
11
+
12
+ /**
13
+ * Compile a file by creating a child of the hooked compiler.
14
+ *
15
+ * @private
16
+ */
17
+ export class ChildCompilationPlugin implements WebpackPluginInstance {
18
+ src: string;
19
+ dest: string;
20
+ plugins: WebpackPluginInstance[] | undefined;
21
+ constructor({ src, dest, plugins }: ChildCompilationPluginOptions) {
22
+ this.src = src;
23
+ this.dest = dest;
24
+ this.plugins = plugins;
25
+ }
26
+ apply(compiler: webpack.Compiler) {
27
+ compiler.hooks.make.tapPromise(this.constructor.name, (compilation) =>
28
+ this.performChildCompilation(compilation, compiler).catch((error: webpack.WebpackError) => {
29
+ compilation.errors.push(error);
30
+ }),
31
+ );
32
+ }
33
+ async performChildCompilation(compilation: webpack.Compilation, parentCompiler: webpack.Compiler): Promise<void> {
34
+ const resolvedDest = relativeToOutputPath(compilation, this.dest);
35
+ const outputOptions: Parameters<Compilation["createChildCompiler"]>["1"] = {
36
+ filename: resolvedDest,
37
+ };
38
+
39
+ const childCompiler = compilation.createChildCompiler(this.constructor.name, outputOptions, []);
40
+
41
+ childCompiler.context = parentCompiler.context;
42
+ childCompiler.inputFileSystem = parentCompiler.inputFileSystem;
43
+ childCompiler.outputFileSystem = parentCompiler.outputFileSystem;
44
+
45
+ if (this.plugins !== undefined) {
46
+ for (const plugin of this.plugins) {
47
+ plugin?.apply(childCompiler);
48
+ }
49
+ }
50
+
51
+ new webpack.EntryPlugin(parentCompiler.context, this.src, this.constructor.name).apply(childCompiler);
52
+
53
+ await new Promise<void>((resolve, reject) => {
54
+ childCompiler.runAsChild((error, _entries, childCompilation) => {
55
+ if (error) {
56
+ reject(error);
57
+ } else {
58
+ compilation.warnings = compilation.warnings.concat(childCompilation?.warnings ?? []);
59
+ compilation.errors = compilation.errors.concat(childCompilation?.errors ?? []);
60
+
61
+ resolve();
62
+ }
63
+ });
64
+ });
65
+ }
66
+ }
@@ -0,0 +1,27 @@
1
+ /*
2
+ Copyright 2018 Google LLC
3
+
4
+ Use of this source code is governed by an MIT-style
5
+ license that can be found in the LICENSE file or at
6
+ https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import crypto from "crypto";
10
+ import type { Asset } from "webpack";
11
+
12
+ /**
13
+ * @param asset
14
+ * @returns The MD5 hash of the asset's source.
15
+ *
16
+ * @private
17
+ */
18
+ export const getAssetHash = (asset: Asset): string | null => {
19
+ // If webpack has the asset marked as immutable, then we don't need to
20
+ // use an out-of-band revision for it.
21
+ // See https://github.com/webpack/webpack/issues/9038
22
+ if (asset.info?.immutable) {
23
+ return null;
24
+ }
25
+
26
+ return crypto.createHash("md5").update(Buffer.from(asset.source.source())).digest("hex");
27
+ };