@serwist/vite 8.2.0 → 8.3.0

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.
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import { m as mainPlugin, d as devPlugin, c as createContext, a as createApi } from './main-dzWmj8BB.js';
1
+ import { m as mainPlugin, d as devPlugin, c as createContext, a as createApi } from './main.js';
2
+ import 'node:fs/promises';
2
3
  import 'node:path';
4
+ import 'vite';
3
5
  import 'node:process';
4
6
  import 'node:crypto';
5
7
  import 'node:fs';
@@ -35,7 +37,7 @@ const buildPlugin = (ctx, api)=>{
35
37
  return [
36
38
  mainPlugin(ctx, api),
37
39
  buildPlugin(ctx, api),
38
- devPlugin(ctx)
40
+ devPlugin(ctx, api)
39
41
  ];
40
42
  };
41
43
 
@@ -1,15 +1,29 @@
1
- import { l as loadSerwistBuild, m as mainPlugin, d as devPlugin, c as createContext, a as createApi } from '../../main-dzWmj8BB.js';
1
+ import { r as resolveEntry, l as loadSerwistBuild, m as mainPlugin, d as devPlugin, c as createContext, a as createApi } from '../../main.js';
2
+ import crypto from 'node:crypto';
3
+ import os from 'node:os';
2
4
  import path from 'node:path';
5
+ import { errors } from '@serwist/build';
6
+ import 'node:fs/promises';
7
+ import 'vite';
3
8
  import 'node:process';
4
- import 'node:crypto';
5
9
  import 'node:fs';
6
10
  import 'fast-glob';
7
11
 
8
12
  const configurateSvelteKitOptions = (viteConfig, kit, options)=>{
9
13
  const clientOutDir = path.resolve(viteConfig.root, viteConfig.build.outDir, "../client");
10
14
  // Kit fixes the service worker's name to 'service-worker.js'
11
- options.swSrc = path.resolve(clientOutDir, "service-worker.js");
12
- options.swDest = path.resolve(clientOutDir, "service-worker.js");
15
+ if (viteConfig.isProduction) {
16
+ options.swSrc = path.resolve(clientOutDir, "service-worker.js");
17
+ options.swDest = path.resolve(clientOutDir, "service-worker.js");
18
+ } else {
19
+ const swSrc = resolveEntry(path.join(viteConfig.root, kit.files?.serviceWorker ?? "src/service-worker"));
20
+ if (swSrc) {
21
+ options.swSrc = swSrc;
22
+ options.swDest = path.join(os.tmpdir(), `serwist-vite-integration-svelte-${crypto.randomUUID()}.js`);
23
+ } else {
24
+ throw new Error(errors["invalid-sw-src"]);
25
+ }
26
+ }
13
27
  options.swUrl = "/service-worker.js";
14
28
  // SvelteKit's outDir is `.svelte-kit/output/client`.
15
29
  // We need to include the parent folder in globDirectory since SvelteKit will generate SSG in `.svelte-kit/output/prerendered` folder.
@@ -36,6 +50,9 @@ const configurateSvelteKitOptions = (viteConfig, kit, options)=>{
36
50
  if (!("dontCacheBustURLsMatching" in options)) {
37
51
  options.dontCacheBustURLsMatching = new RegExp(`${buildAssetsDir}immutable/`);
38
52
  }
53
+ if (!options.injectionPoint) {
54
+ options.injectionPoint = "self.__SW_MANIFEST";
55
+ }
39
56
  };
40
57
  function createManifestTransform(base, webManifestName, options) {
41
58
  return async (entries)=>{
@@ -119,7 +136,7 @@ const serwistSveltePlugin = (ctx, api)=>{
119
136
  if (api && !api.disabled && ctx.viteConfig.build.ssr) {
120
137
  const [injectManifest, logSerwistResult] = await Promise.all([
121
138
  loadSerwistBuild().then((m)=>m.injectManifest),
122
- import('../../log-Dyh-Moyt.js').then((m)=>m.logSerwistResult)
139
+ import('../../log.js').then((m)=>m.logSerwistResult)
123
140
  ]);
124
141
  // Inject the manifest
125
142
  const buildResult = await injectManifest(ctx.options.injectManifest);
@@ -143,7 +160,7 @@ const serwistSveltePlugin = (ctx, api)=>{
143
160
  const api = createApi(ctx);
144
161
  return [
145
162
  mainPlugin(ctx, api),
146
- devPlugin(ctx),
163
+ devPlugin(ctx, api),
147
164
  serwistSveltePlugin(ctx, api)
148
165
  ];
149
166
  };
@@ -1,7 +1,7 @@
1
1
  import type { KitConfig } from "@sveltejs/kit";
2
2
  import type { PluginOptions as BasePluginOptions } from "../../types.js";
3
3
  import type { Optional } from "../../utils-types.js";
4
- export interface KitOptions extends Pick<KitConfig, "appDir"> {
4
+ export interface KitOptions extends Pick<KitConfig, "appDir" | "files"> {
5
5
  /**
6
6
  * @see https://kit.svelte.dev/docs/adapter-static#options-fallback
7
7
  */
@@ -1,5 +1,7 @@
1
- import { b as cyan, v as version, g as green, e as dim, y as yellow } from './main-dzWmj8BB.js';
1
+ import { b as cyan, v as version, g as green, e as dim, y as yellow } from './main.js';
2
+ import 'node:fs/promises';
2
3
  import 'node:path';
4
+ import 'vite';
3
5
  import 'node:process';
4
6
  import 'node:crypto';
5
7
  import 'node:fs';
@@ -1,7 +1,9 @@
1
+ import fs from 'node:fs/promises';
1
2
  import path, { resolve } from 'node:path';
3
+ import { normalizePath } from 'vite';
2
4
  import process$1 from 'node:process';
3
5
  import crypto from 'node:crypto';
4
- import fs from 'node:fs';
6
+ import fs$1 from 'node:fs';
5
7
  import fg from 'fast-glob';
6
8
 
7
9
  let enabled = true;
@@ -64,7 +66,7 @@ const green = kolorist(32, 39);
64
66
  const yellow = kolorist(33, 39);
65
67
  const cyan = kolorist(36, 39);
66
68
 
67
- var version = "8.2.0";
69
+ var version = "8.3.0";
68
70
 
69
71
  const logSerwistResult = (buildResult, viteOptions)=>{
70
72
  const { logLevel = "info" } = viteOptions;
@@ -108,34 +110,40 @@ const generateInjectManifest = async (options, viteOptions)=>{
108
110
  define["process.env.NODE_ENV"] = JSON.stringify(options.mode);
109
111
  const { format, plugins, rollupOptions } = options.injectManifestRollupOptions;
110
112
  const parsedSwDest = path.parse(options.injectManifest.swDest);
111
- await build({
112
- root: viteOptions.root,
113
- base: viteOptions.base,
114
- resolve: viteOptions.resolve,
115
- // Don't copy anything from public folder
116
- publicDir: false,
117
- build: {
118
- sourcemap: viteOptions.build.sourcemap,
119
- lib: {
120
- entry: options.injectManifest.swSrc,
121
- name: "app",
122
- formats: [
123
- format
124
- ]
113
+ if (viteOptions.isProduction || options.devOptions.bundle) {
114
+ await build({
115
+ logLevel: viteOptions.isProduction ? "info" : "warn",
116
+ root: viteOptions.root,
117
+ base: viteOptions.base,
118
+ resolve: viteOptions.resolve,
119
+ // Don't copy anything from public folder
120
+ publicDir: false,
121
+ build: {
122
+ sourcemap: viteOptions.build.sourcemap,
123
+ lib: {
124
+ entry: options.injectManifest.swSrc,
125
+ name: "app",
126
+ formats: [
127
+ format
128
+ ]
129
+ },
130
+ rollupOptions: {
131
+ ...rollupOptions,
132
+ plugins,
133
+ output: {
134
+ entryFileNames: parsedSwDest.base
135
+ }
136
+ },
137
+ outDir: parsedSwDest.dir,
138
+ emptyOutDir: false,
139
+ minify: viteOptions.isProduction
125
140
  },
126
- rollupOptions: {
127
- ...rollupOptions,
128
- plugins,
129
- output: {
130
- entryFileNames: parsedSwDest.base
131
- }
132
- },
133
- outDir: parsedSwDest.dir,
134
- emptyOutDir: false
135
- },
136
- configFile: false,
137
- define
138
- });
141
+ configFile: false,
142
+ define
143
+ });
144
+ } else {
145
+ await fs.copyFile(options.injectManifest.swSrc, options.injectManifest.swDest);
146
+ }
139
147
  // If the user doesn't have an injectionPoint, skip injectManifest.
140
148
  if (!options.injectManifest.injectionPoint) return;
141
149
  await options.integration?.beforeBuildServiceWorker?.(options);
@@ -146,9 +154,7 @@ const generateInjectManifest = async (options, viteOptions)=>{
146
154
  };
147
155
  const { injectManifest } = await loadSerwistBuild();
148
156
  // Inject the manifest
149
- const buildResult = await injectManifest(resolvedInjectManifestOptions);
150
- // Log workbox result
151
- logSerwistResult(buildResult, viteOptions);
157
+ return await injectManifest(resolvedInjectManifestOptions);
152
158
  };
153
159
 
154
160
  const createApi = (ctx)=>{
@@ -160,7 +166,19 @@ const createApi = (ctx)=>{
160
166
  if (ctx.options.disable) {
161
167
  return undefined;
162
168
  }
163
- return await generateInjectManifest(ctx.options, ctx.viteConfig);
169
+ const buildResult = await generateInjectManifest(ctx.options, ctx.viteConfig);
170
+ if (buildResult) {
171
+ if (ctx.viteConfig.isProduction) {
172
+ // Log Serwist result
173
+ logSerwistResult(buildResult, ctx.viteConfig);
174
+ } else if (buildResult.warnings && buildResult.warnings.length > 0) {
175
+ console.warn(yellow([
176
+ "[@serwist/vite] Warnings",
177
+ ...buildResult.warnings.map((w)=>` - ${w}`),
178
+ ""
179
+ ].join("\n")));
180
+ }
181
+ }
164
182
  },
165
183
  extendManifestEntries (fn) {
166
184
  const { options } = ctx;
@@ -183,12 +201,86 @@ const createContext = (userOptions)=>{
183
201
  };
184
202
  };
185
203
 
186
- const devPlugin = (ctx)=>{
204
+ const slash = (str)=>{
205
+ return str.replace(/\\/g, "/");
206
+ };
207
+ const resolveBasePath = (base)=>{
208
+ if (isAbsolute(base)) return base;
209
+ return !base.startsWith("/") && !base.startsWith("./") ? `/${base}` : base;
210
+ };
211
+ const isAbsolute = (url)=>{
212
+ return url.match(/^(?:[a-z]+:)?\/\//i);
213
+ };
214
+ // Source: https://github.com/sveltejs/kit/blob/6419d3eaa7bf1b0a756b28f06a73f71fe042de0a/packages/kit/src/utils/filesystem.js
215
+ // License: MIT
216
+ const resolveEntry = (entry)=>{
217
+ if (fs$1.existsSync(entry)) {
218
+ const stats = fs$1.statSync(entry);
219
+ if (stats.isDirectory()) {
220
+ return resolveEntry(path.join(entry, "index"));
221
+ }
222
+ return entry;
223
+ } else {
224
+ const dir = path.dirname(entry);
225
+ if (fs$1.existsSync(dir)) {
226
+ const base = path.basename(entry);
227
+ const files = fs$1.readdirSync(dir);
228
+ const found = files.find((file)=>file.replace(/\.[^.]+$/, "") === base);
229
+ if (found) return path.join(dir, found);
230
+ }
231
+ }
232
+ return null;
233
+ };
234
+ // Source: https://github.com/sveltejs/kit/blob/6419d3eaa7bf1b0a756b28f06a73f71fe042de0a/packages/kit/src/utils/filesystem.js
235
+ // License: MIT
236
+ function toFs(str) {
237
+ str = str.replace(/\\/g, "/");
238
+ // Windows/Linux separation - Windows starts with a drive letter, we need a / in front there
239
+ return `/@fs${str.startsWith("/") ? "" : "/"}${str}`;
240
+ }
241
+
242
+ // This plugin handles the service worker in two ways:
243
+ // - If `devOptions.bundle` is enabled, hook a middleware that bundles the service worker
244
+ // through `api.generateSW()` and returns the result into Vite's dev server.
245
+ // - Otherwise, run `injectManifest` and return the service worker through `async load(id)`. Although
246
+ // `precacheEntries` is always `undefined`, we still do this to check the user's `injectManifest` options
247
+ // in dev mode.
248
+ const devPlugin = (ctx, api)=>{
187
249
  return {
188
250
  name: "@serwist/vite:dev",
189
251
  apply: "serve",
190
- configureServer () {
252
+ configureServer (server) {
191
253
  ctx.devEnvironment = true;
254
+ server.middlewares.use(async (req, res, next)=>{
255
+ if (!ctx.options.disable && req.url === ctx.options.swUrl) {
256
+ if (ctx.options.devOptions.bundle) {
257
+ await api.generateSW();
258
+ const content = await fs.readFile(ctx.options.injectManifest.swDest, "utf-8");
259
+ await fs.rm(ctx.options.injectManifest.swDest);
260
+ res.setHeader("Content-Type", "application/javascript");
261
+ res.write(content);
262
+ res.end();
263
+ } else {
264
+ res.setHeader("Content-Type", "application/javascript");
265
+ res.write(`import "${toFs(path.resolve(ctx.options.injectManifest.swSrc))}";`);
266
+ res.end();
267
+ }
268
+ } else {
269
+ next();
270
+ }
271
+ });
272
+ },
273
+ async load (id) {
274
+ if (!ctx.options.disable && !ctx.options.devOptions.bundle) {
275
+ const swSrcId = normalizePath(ctx.options.injectManifest.swSrc);
276
+ if (id === swSrcId) {
277
+ await api.generateSW();
278
+ const content = await fs.readFile(ctx.options.injectManifest.swDest, "utf-8");
279
+ await fs.rm(ctx.options.injectManifest.swDest);
280
+ return content;
281
+ }
282
+ }
283
+ return undefined;
192
284
  }
193
285
  };
194
286
  };
@@ -199,7 +291,7 @@ const RESOLVED_INTERNAL_SERWIST_VIRTUAL = `\0${INTERNAL_SERWIST_VIRTUAL}`;
199
291
  const buildManifestEntry = (publicDir, url)=>{
200
292
  return new Promise((resolve$1, reject)=>{
201
293
  const cHash = crypto.createHash("MD5");
202
- const stream = fs.createReadStream(resolve(publicDir, url));
294
+ const stream = fs$1.createReadStream(resolve(publicDir, url));
203
295
  stream.on("error", (err)=>{
204
296
  reject(err);
205
297
  });
@@ -257,24 +349,17 @@ const configureStaticAssets = async (resolvedPluginOptions, viteConfig)=>{
257
349
  }
258
350
  };
259
351
 
260
- const slash = (str)=>{
261
- return str.replace(/\\/g, "/");
262
- };
263
- const resolveBasePath = (base)=>{
264
- if (isAbsolute(base)) return base;
265
- return !base.startsWith("/") && !base.startsWith("./") ? `/${base}` : base;
266
- };
267
- const isAbsolute = (url)=>{
268
- return url.match(/^(?:[a-z]+:)?\/\//i);
269
- };
270
-
271
352
  const resolveOptions = async (options, viteConfig)=>{
272
- const { type = "classic", mode = process$1.env.NODE_ENV || "production", injectRegister = "auto", registerType = "prompt", minify = true, base = viteConfig.base, includeAssets = undefined, useCredentials = false, disable = false, integration = {}, buildBase, ...injectManifest } = options;
353
+ const { type = "classic", mode = process$1.env.NODE_ENV || "production", injectRegister = "auto", registerType = "prompt", minify = true, base = viteConfig.base, includeAssets = undefined, useCredentials = false, disable = false, integration = {}, buildBase, devOptions, ...injectManifest } = options;
273
354
  const basePath = resolveBasePath(base);
274
355
  // check typescript service worker for injectManifest strategy
275
356
  const scope = options.scope || basePath;
276
357
  let assetsDir = slash(viteConfig.build.assetsDir ?? "assets");
277
358
  if (assetsDir[assetsDir.length - 1] !== "/") assetsDir += "/";
359
+ const resolvedDevOptions = {
360
+ bundle: true,
361
+ ...devOptions
362
+ };
278
363
  // remove './' prefix from assetsDir
279
364
  const dontCacheBustURLsMatching = new RegExp(`^${assetsDir.replace(/^\.*?\//, "")}`);
280
365
  const { plugins = [], rollupOptions = {}, rollupFormat = "es", swUrl = "/sw.js", swSrc, swDest, ...userInjectManifest } = injectManifest || {};
@@ -303,7 +388,8 @@ const resolveOptions = async (options, viteConfig)=>{
303
388
  plugins,
304
389
  rollupOptions,
305
390
  format: rollupFormat
306
- }
391
+ },
392
+ devOptions: resolvedDevOptions
307
393
  };
308
394
  // calculate hash only when required
309
395
  const calculateHash = !resolvedPluginOptions.disable && resolvedPluginOptions.includeAssets && viteConfig.command === "build";
@@ -345,4 +431,4 @@ export const swType = "${ctx.devEnvironment ? "module" : ctx.options.type}";`;
345
431
  };
346
432
  };
347
433
 
348
- export { createApi as a, cyan as b, createContext as c, devPlugin as d, dim as e, green as g, loadSerwistBuild as l, mainPlugin as m, version as v, yellow as y };
434
+ export { createApi as a, cyan as b, createContext as c, devPlugin as d, dim as e, green as g, loadSerwistBuild as l, mainPlugin as m, resolveEntry as r, version as v, yellow as y };
package/dist/modules.d.ts CHANGED
@@ -2,4 +2,4 @@ import type * as SerwistBuild from "@serwist/build";
2
2
  import type { ResolvedConfig } from "vite";
3
3
  import type { ResolvedPluginOptions } from "./types.js";
4
4
  export declare const loadSerwistBuild: () => Promise<typeof SerwistBuild>;
5
- export declare const generateInjectManifest: (options: ResolvedPluginOptions, viteOptions: ResolvedConfig) => Promise<void>;
5
+ export declare const generateInjectManifest: (options: ResolvedPluginOptions, viteOptions: ResolvedConfig) => Promise<SerwistBuild.BuildResult | undefined>;
@@ -1,3 +1,4 @@
1
- import type { Plugin } from "vite";
1
+ import { type Plugin } from "vite";
2
2
  import type { SerwistViteContext } from "../context.js";
3
- export declare const devPlugin: (ctx: SerwistViteContext) => Plugin;
3
+ import type { SerwistViteApi } from "../types.js";
4
+ export declare const devPlugin: (ctx: SerwistViteContext, api: SerwistViteApi) => Plugin;
package/dist/types.d.ts CHANGED
@@ -34,6 +34,17 @@ export interface SerwistViteHooks {
34
34
  closeBundleOrder?: "pre" | "post" | null;
35
35
  configureOptions?: (viteOptions: ResolvedConfig, options: PluginOptions) => void | Promise<void>;
36
36
  }
37
+ export interface DevOptions {
38
+ /**
39
+ * Whether the service worker should be bundled in development mode.
40
+ *
41
+ * [Many browsers still do not support ES Modules in service workers.](https://caniuse.com/mdn-api_serviceworker_ecmascript_modules) However, in development
42
+ * mode, certain frameworks, such as SvelteKit, do not bundle the service worker. As a result, trying to register that service worker on browsers lacking
43
+ * support, such as Firefox or Safari, will fail, but doing so on browsers not lacking support will not fail. This option is provided to prevent that from
44
+ * happening. What the plugin does is intercepting any request to the service worker (requests for `swUrl`) and returning a bundled one.
45
+ */
46
+ bundle?: boolean;
47
+ }
37
48
  /**
38
49
  * Plugin options.
39
50
  */
@@ -135,7 +146,9 @@ export interface BasePluginOptions {
135
146
  */
136
147
  buildBase?: string;
137
148
  }
138
- export type PluginOptions = Partial<BasePluginOptions> & CustomInjectManifestOptions;
149
+ export interface PluginOptions extends Partial<BasePluginOptions>, CustomInjectManifestOptions {
150
+ devOptions?: DevOptions;
151
+ }
139
152
  export interface InjectManifestRollupOptions {
140
153
  format: "es" | "iife";
141
154
  plugins: Plugin[];
@@ -144,6 +157,7 @@ export interface InjectManifestRollupOptions {
144
157
  export interface ResolvedPluginOptions extends Required<BasePluginOptions>, Required<Pick<CustomInjectManifestOptions, "swUrl">> {
145
158
  injectManifest: InjectManifestOptions;
146
159
  injectManifestRollupOptions: InjectManifestRollupOptions;
160
+ devOptions: Required<DevOptions>;
147
161
  }
148
162
  export interface ShareTargetFiles {
149
163
  name: string;
package/dist/utils.d.ts CHANGED
@@ -2,3 +2,5 @@ export declare const slash: (str: string) => string;
2
2
  export declare const resolveBasePath: (base: string) => string;
3
3
  export declare const isAbsolute: (url: string) => RegExpMatchArray | null;
4
4
  export declare const normalizePath: (path: string) => string;
5
+ export declare const resolveEntry: (entry: string) => string | null;
6
+ export declare function toFs(str: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serwist/vite",
3
- "version": "8.2.0",
3
+ "version": "8.3.0",
4
4
  "type": "module",
5
5
  "description": "A module that integrates Serwist into your Vite application.",
6
6
  "files": [
@@ -77,8 +77,8 @@
77
77
  "debug": "4.3.4",
78
78
  "fast-glob": "3.3.2",
79
79
  "pretty-bytes": "6.1.1",
80
- "@serwist/build": "8.2.0",
81
- "@serwist/window": "8.2.0"
80
+ "@serwist/build": "8.3.0",
81
+ "@serwist/window": "8.3.0"
82
82
  },
83
83
  "devDependencies": {
84
84
  "@playwright/test": "1.40.1",
@@ -100,7 +100,7 @@
100
100
  "typescript": "5.4.0-dev.20231226",
101
101
  "vite": "5.0.10",
102
102
  "vue": "3.3.13",
103
- "@serwist/constants": "8.2.0"
103
+ "@serwist/constants": "8.3.0"
104
104
  },
105
105
  "peerDependencies": {
106
106
  "@sveltejs/kit": "^1.0.0 || ^2.0.0",