source: frontend/node_modules/workbox-webpack-plugin/src/generate-sw.ts

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.8 KB
Line 
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
9import {validateWebpackGenerateSWOptions} from 'workbox-build/build/lib/validate-options';
10import {bundle} from 'workbox-build/build/lib/bundle';
11import {populateSWTemplate} from 'workbox-build/build/lib/populate-sw-template';
12import prettyBytes from 'pretty-bytes';
13import webpack from 'webpack';
14import {ManifestEntry, WebpackGenerateSWOptions} from 'workbox-build';
15import {getScriptFilesForChunks} from './lib/get-script-files-for-chunks';
16import {getManifestEntriesFromCompilation} from './lib/get-manifest-entries-from-compilation';
17import {relativeToOutputPath} from './lib/relative-to-output-path';
18
19// webpack v4/v5 compatibility:
20// https://github.com/webpack/webpack/issues/11425#issuecomment-686607633
21const {RawSource} = webpack.sources || require('webpack-sources');
22
23// Used to keep track of swDest files written by *any* instance of this plugin.
24// See https://github.com/GoogleChrome/workbox/issues/2181
25const _generatedAssetNames = new Set<string>();
26
27export interface GenerateSWConfig extends WebpackGenerateSWOptions {
28 manifestEntries?: Array<ManifestEntry>;
29}
30
31/**
32 * This class supports creating a new, ready-to-use service worker file as
33 * part of the webpack compilation process.
34 *
35 * Use an instance of `GenerateSW` in the
36 * [`plugins` array](https://webpack.js.org/concepts/plugins/#usage) of a
37 * webpack config.
38 *
39 * ```
40 * // The following lists some common options; see the rest of the documentation
41 * // for the full set of options and defaults.
42 * new GenerateSW({
43 * exclude: [/.../, '...'],
44 * maximumFileSizeToCacheInBytes: ...,
45 * navigateFallback: '...',
46 * runtimeCaching: [{
47 * // Routing via a matchCallback function:
48 * urlPattern: ({request, url}) => ...,
49 * handler: '...',
50 * options: {
51 * cacheName: '...',
52 * expiration: {
53 * maxEntries: ...,
54 * },
55 * },
56 * }, {
57 * // Routing via a RegExp:
58 * urlPattern: new RegExp('...'),
59 * handler: '...',
60 * options: {
61 * cacheName: '...',
62 * plugins: [..., ...],
63 * },
64 * }],
65 * skipWaiting: ...,
66 * });
67 * ```
68 *
69 * @memberof module:workbox-webpack-plugin
70 */
71class GenerateSW {
72 protected config: GenerateSWConfig;
73 private alreadyCalled: boolean;
74
75 /**
76 * Creates an instance of GenerateSW.
77 */
78 constructor(config: GenerateSWConfig = {}) {
79 this.config = config;
80 this.alreadyCalled = false;
81 }
82
83 /**
84 * @param {Object} [compiler] default compiler object passed from webpack
85 *
86 * @private
87 */
88 propagateWebpackConfig(compiler: webpack.Compiler): void {
89 // Because this.config is listed last, properties that are already set
90 // there take precedence over derived properties from the compiler.
91 this.config = Object.assign(
92 {
93 mode: compiler.options.mode,
94 sourcemap: Boolean(compiler.options.devtool),
95 },
96 this.config,
97 );
98 }
99
100 /**
101 * @param {Object} [compiler] default compiler object passed from webpack
102 *
103 * @private
104 */
105 apply(compiler: webpack.Compiler): void {
106 this.propagateWebpackConfig(compiler);
107
108 // webpack v4/v5 compatibility:
109 // https://github.com/webpack/webpack/issues/11425#issuecomment-690387207
110 if (webpack.version.startsWith('4.')) {
111 compiler.hooks.emit.tapPromise(this.constructor.name, (compilation) =>
112 this.addAssets(compilation).catch((error) => {
113 compilation.errors.push(error);
114 }),
115 );
116 } else {
117 const {PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER} = webpack.Compilation;
118 // Specifically hook into thisCompilation, as per
119 // https://github.com/webpack/webpack/issues/11425#issuecomment-690547848
120 compiler.hooks.thisCompilation.tap(
121 this.constructor.name,
122 (compilation) => {
123 compilation.hooks.processAssets.tapPromise(
124 {
125 name: this.constructor.name,
126 // TODO(jeffposnick): This may need to change eventually.
127 // See https://github.com/webpack/webpack/issues/11822#issuecomment-726184972
128 stage: PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER - 10,
129 },
130 () =>
131 this.addAssets(compilation).catch(
132 (error: webpack.WebpackError) => {
133 compilation.errors.push(error);
134 },
135 ),
136 );
137 },
138 );
139 }
140 }
141
142 /**
143 * @param {Object} compilation The webpack compilation.
144 *
145 * @private
146 */
147 async addAssets(compilation: webpack.Compilation): Promise<void> {
148 // See https://github.com/GoogleChrome/workbox/issues/1790
149 if (this.alreadyCalled) {
150 const warningMessage =
151 `${this.constructor.name} has been called ` +
152 `multiple times, perhaps due to running webpack in --watch mode. The ` +
153 `precache manifest generated after the first call may be inaccurate! ` +
154 `Please see https://github.com/GoogleChrome/workbox/issues/1790 for ` +
155 `more information.`;
156
157 if (
158 !compilation.warnings.some(
159 (warning) =>
160 warning instanceof Error && warning.message === warningMessage,
161 )
162 ) {
163 compilation.warnings.push(
164 Error(warningMessage) as webpack.WebpackError,
165 );
166 }
167 } else {
168 this.alreadyCalled = true;
169 }
170
171 let config: GenerateSWConfig = {};
172 try {
173 // emit might be called multiple times; instead of modifying this.config,
174 // use a validated copy.
175 // See https://github.com/GoogleChrome/workbox/issues/2158
176 config = validateWebpackGenerateSWOptions(this.config);
177 } catch (error) {
178 if (error instanceof Error) {
179 throw new Error(
180 `Please check your ${this.constructor.name} plugin ` +
181 `configuration:\n${error.message}`,
182 );
183 }
184 }
185
186 // Ensure that we don't precache any of the assets generated by *any*
187 // instance of this plugin.
188 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
189 config.exclude!.push(({asset}) => _generatedAssetNames.has(asset.name));
190
191 if (config.importScriptsViaChunks) {
192 // Anything loaded via importScripts() is implicitly cached by the service
193 // worker, and should not be added to the precache manifest.
194 config.excludeChunks = (config.excludeChunks || []).concat(
195 config.importScriptsViaChunks,
196 );
197
198 const scripts = getScriptFilesForChunks(
199 compilation,
200 config.importScriptsViaChunks,
201 );
202
203 config.importScripts = (config.importScripts || []).concat(scripts);
204 }
205
206 const {size, sortedEntries} = await getManifestEntriesFromCompilation(
207 compilation,
208 config,
209 );
210 config.manifestEntries = sortedEntries;
211
212 const unbundledCode = populateSWTemplate(config);
213
214 const files = await bundle({
215 babelPresetEnvTargets: config.babelPresetEnvTargets,
216 inlineWorkboxRuntime: config.inlineWorkboxRuntime,
217 mode: config.mode,
218 sourcemap: config.sourcemap,
219 swDest: relativeToOutputPath(compilation, config.swDest!),
220 unbundledCode,
221 });
222
223 for (const file of files) {
224 compilation.emitAsset(
225 file.name,
226 new RawSource(Buffer.from(file.contents)),
227 {
228 // See https://github.com/webpack-contrib/compression-webpack-plugin/issues/218#issuecomment-726196160
229 minimized: config.mode === 'production',
230 },
231 );
232 _generatedAssetNames.add(file.name);
233 }
234
235 if (compilation.getLogger) {
236 const logger = compilation.getLogger(this.constructor.name);
237 logger.info(`The service worker at ${config.swDest ?? ''} will precache
238 ${config.manifestEntries.length} URLs, totaling ${prettyBytes(size)}.`);
239 }
240 }
241}
242
243export {GenerateSW};
Note: See TracBrowser for help on using the repository browser.