This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-PRESENT Anthony Fu <https://github.com/antfu>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
<p align='center'>
|
||||
<img src='./hero.png' alt="@vite-pwa/sveltekit - Zero-config PWA for SvelteKit"><br>
|
||||
Zero-config PWA Plugin for SvelteKit
|
||||
</p>
|
||||
|
||||
<p align='center'>
|
||||
<a href='https://www.npmjs.com/package/@vite-pwa/sveltekit' target="__blank">
|
||||
<img src='https://img.shields.io/npm/v/@vite-pwa/sveltekit?color=33A6B8&label=' alt="NPM version">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/@vite-pwa/sveltekit" target="__blank">
|
||||
<img alt="NPM Downloads" src="https://img.shields.io/npm/dm/@vite-pwa/sveltekit?color=476582&label=">
|
||||
</a>
|
||||
<a href="https://vite-pwa-org.netlify.app/frameworks/sveltekit" target="__blank">
|
||||
<img src="https://img.shields.io/static/v1?label=&message=docs%20%26%20guides&color=2e859c" alt="Docs & Guides">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://github.com/vite-pwa/sveltekit" target="__blank">
|
||||
<img alt="GitHub stars" src="https://img.shields.io/github/stars/vite-pwa/sveltekit?style=social">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg">
|
||||
<img src='https://cdn.jsdelivr.net/gh/antfu/static/sponsors.svg'/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🚀 Features
|
||||
|
||||
- 📖 [**Documentation & guides**](https://vite-pwa-org.netlify.app/)
|
||||
- 👌 **Zero-Config**: sensible built-in default configs for common use cases
|
||||
- 🔩 **Extensible**: expose the full ability to customize the behavior of the plugin
|
||||
- 🦾 **Type Strong**: written in [TypeScript](https://www.typescriptlang.org/)
|
||||
- 🔌 **Offline Support**: generate service worker with offline support (via Workbox)
|
||||
- ⚡ **Fully tree shakable**: auto inject Web App Manifest
|
||||
- 💬 **Prompt for new content**: built-in support for Vanilla JavaScript, Vue 3, React, Svelte, SolidJS and Preact
|
||||
- ⚙️ **Stale-while-revalidate**: automatic reload when new content is available
|
||||
- ✨ **Static assets handling**: configure static assets for offline support
|
||||
- 🐞 **Development Support**: debug your custom service worker logic as you develop your application
|
||||
- 🛠️ **Versatile**: integration with meta frameworks: [îles](https://github.com/ElMassimo/iles), [SvelteKit](https://github.com/sveltejs/kit), [VitePress](https://github.com/vuejs/vitepress), [Astro](https://github.com/withastro/astro), [Nuxt 3](https://github.com/nuxt/nuxt) and [Remix](https://github.com/remix-run/remix)
|
||||
- 💥 **PWA Assets Generator**: generate all the PWA assets from a single command and a single source image
|
||||
- 🚀 **PWA Assets Integration**: serving, generating and injecting PWA Assets on the fly in your application
|
||||
|
||||
## 📦 Install
|
||||
|
||||
> From v0.3.0, `@vite-pwa/sveltekit` supports SvelteKit 2 (should also support SvelteKit 1).
|
||||
|
||||
> From v0.2.0, `@vite-pwa/sveltekit` requires **SvelteKit 1.3.1 or above**.
|
||||
|
||||
```bash
|
||||
npm i @vite-pwa/sveltekit -D
|
||||
|
||||
# yarn
|
||||
yarn add @vite-pwa/sveltekit -D
|
||||
|
||||
# pnpm
|
||||
pnpm add @vite-pwa/sveltekit -D
|
||||
```
|
||||
|
||||
## 🦄 Usage
|
||||
|
||||
Add `SvelteKitPWA` plugin to `vite.config.js / vite.config.ts` and configure it:
|
||||
|
||||
```ts
|
||||
// vite.config.js / vite.config.ts
|
||||
import { sveltekit } from '@sveltejs/kit/vite'
|
||||
import { SvelteKitPWA } from '@vite-pwa/sveltekit'
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
SvelteKitPWA()
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Read the [📖 documentation](https://vite-pwa-org.netlify.app/frameworks/sveltekit) for a complete guide on how to configure and use
|
||||
this plugin.
|
||||
|
||||
## 👀 Full config
|
||||
|
||||
Check out the type declaration [src/types.ts](./src/types.ts) and the following links for more details.
|
||||
|
||||
- [Web app manifests](https://developer.mozilla.org/en-US/docs/Web/Manifest)
|
||||
- [Workbox](https://developers.google.com/web/tools/workbox)
|
||||
|
||||
## 📄 License
|
||||
|
||||
[MIT](./LICENSE) License © 2022-PRESENT [Anthony Fu](https://github.com/antfu)
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import { relative } from 'node:path';
|
||||
import { cyan, magenta, green, dim, yellow } from 'kolorist';
|
||||
|
||||
const version = "1.1.0";
|
||||
|
||||
function logWorkboxResult(strategy, viteOptions, buildResult) {
|
||||
const { root, logLevel = "info" } = viteOptions;
|
||||
if (logLevel === "silent")
|
||||
return;
|
||||
if (!buildResult) {
|
||||
console.info([
|
||||
"",
|
||||
`${cyan(`SvelteKit VitePWA v${version}`)}`,
|
||||
`mode ${magenta(strategy)}`
|
||||
].join("\n"));
|
||||
return;
|
||||
}
|
||||
const { count, size, filePaths, warnings } = buildResult;
|
||||
if (logLevel === "info") {
|
||||
console.info([
|
||||
"",
|
||||
`${cyan(`SvelteKit VitePWA v${version}`)}`,
|
||||
`mode ${magenta(strategy)}`,
|
||||
`precache ${green(`${count} entries`)} ${dim(`(${(size / 1024).toFixed(2)} KiB)`)}`,
|
||||
"files generated",
|
||||
...filePaths.map((p) => ` ${dim(relative(root, p))}`)
|
||||
].join("\n"));
|
||||
}
|
||||
warnings && warnings.length > 0 && console.warn(yellow([
|
||||
"warnings",
|
||||
...warnings.map((w) => ` ${w}`),
|
||||
""
|
||||
].join("\n")));
|
||||
}
|
||||
|
||||
export { logWorkboxResult };
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { VitePWAOptions } from 'vite-plugin-pwa';
|
||||
|
||||
interface KitOptions {
|
||||
/**
|
||||
* The base path for your application: by default will use the Vite base.
|
||||
*
|
||||
* @deprecated since ^0.1.0 version, the plugin has SvelteKit ^1.0.0 as peer dependency, Vite's base is now properly configured.
|
||||
* @default '/'
|
||||
* @see https://kit.svelte.dev/docs/configuration#paths
|
||||
*/
|
||||
base?: string;
|
||||
/**
|
||||
* The static folder for your application.
|
||||
*
|
||||
* @default 'static'
|
||||
* @see https://kit.svelte.dev/docs/configuration#files
|
||||
*/
|
||||
assets?: string;
|
||||
/**
|
||||
* @default '.svelte-kit'
|
||||
* @see https://kit.svelte.dev/docs/configuration#outdir
|
||||
*/
|
||||
outDir?: string;
|
||||
/**
|
||||
* @see https://kit.svelte.dev/docs/adapter-static#options-fallback
|
||||
*/
|
||||
adapterFallback?: string;
|
||||
/**
|
||||
* Check your SvelteKit version, `trailingSlash` should be used in `+page[jt]s` files or `+layout.[jt]s.
|
||||
* @default 'never'
|
||||
*/
|
||||
trailingSlash?: 'never' | 'always' | 'ignore';
|
||||
/**
|
||||
* @default `_app`
|
||||
* @see https://kit.svelte.dev/docs/configuration#appdir
|
||||
*/
|
||||
appDir?: string;
|
||||
/**
|
||||
* Include `${appDir}/version.json` in the service worker precache manifest?
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
includeVersionFile?: boolean;
|
||||
/**
|
||||
* Enable SPA mode for the application.
|
||||
*
|
||||
* By default, the plugin will use `adapterFallback` to include the entry in the service worker
|
||||
* precache manifest.
|
||||
*
|
||||
* If you are using a logical name for the fallback, you can use the object syntax with the
|
||||
* `fallbackMapping`.
|
||||
*
|
||||
* For example, if you're using `fallback: 'app.html'` in your static adapter and your server
|
||||
* is redirecting to `/app`, you can configure `fallbackMapping: '/app'`.
|
||||
*
|
||||
* Since the static adapter will run after the PWA plugin generates the service worker,
|
||||
* the PWA plugin doesn't have access to the adapter fallback page to include the revision in the
|
||||
* service worker precache manifest.
|
||||
* To generate the revision for the fallback page, the PWA plugin will use the
|
||||
* `.svelte-kit/output/client/_app/version.json` file.
|
||||
* You can configure the `fallbackRevision` to generate a custom revision.
|
||||
*
|
||||
* @see https://svelte.dev/docs/kit/single-page-apps
|
||||
*/
|
||||
spa?: true | {
|
||||
fallbackMapping?: string;
|
||||
fallbackRevision?: () => Promise<string>;
|
||||
};
|
||||
}
|
||||
interface SvelteKitPWAOptions extends Partial<VitePWAOptions> {
|
||||
kit?: KitOptions;
|
||||
}
|
||||
|
||||
declare function SvelteKitPWA(userOptions?: Partial<SvelteKitPWAOptions>): Plugin[];
|
||||
|
||||
export { type KitOptions, SvelteKitPWA, type SvelteKitPWAOptions };
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
import { Plugin } from 'vite';
|
||||
import { VitePWAOptions } from 'vite-plugin-pwa';
|
||||
|
||||
interface KitOptions {
|
||||
/**
|
||||
* The base path for your application: by default will use the Vite base.
|
||||
*
|
||||
* @deprecated since ^0.1.0 version, the plugin has SvelteKit ^1.0.0 as peer dependency, Vite's base is now properly configured.
|
||||
* @default '/'
|
||||
* @see https://kit.svelte.dev/docs/configuration#paths
|
||||
*/
|
||||
base?: string;
|
||||
/**
|
||||
* The static folder for your application.
|
||||
*
|
||||
* @default 'static'
|
||||
* @see https://kit.svelte.dev/docs/configuration#files
|
||||
*/
|
||||
assets?: string;
|
||||
/**
|
||||
* @default '.svelte-kit'
|
||||
* @see https://kit.svelte.dev/docs/configuration#outdir
|
||||
*/
|
||||
outDir?: string;
|
||||
/**
|
||||
* @see https://kit.svelte.dev/docs/adapter-static#options-fallback
|
||||
*/
|
||||
adapterFallback?: string;
|
||||
/**
|
||||
* Check your SvelteKit version, `trailingSlash` should be used in `+page[jt]s` files or `+layout.[jt]s.
|
||||
* @default 'never'
|
||||
*/
|
||||
trailingSlash?: 'never' | 'always' | 'ignore';
|
||||
/**
|
||||
* @default `_app`
|
||||
* @see https://kit.svelte.dev/docs/configuration#appdir
|
||||
*/
|
||||
appDir?: string;
|
||||
/**
|
||||
* Include `${appDir}/version.json` in the service worker precache manifest?
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
includeVersionFile?: boolean;
|
||||
/**
|
||||
* Enable SPA mode for the application.
|
||||
*
|
||||
* By default, the plugin will use `adapterFallback` to include the entry in the service worker
|
||||
* precache manifest.
|
||||
*
|
||||
* If you are using a logical name for the fallback, you can use the object syntax with the
|
||||
* `fallbackMapping`.
|
||||
*
|
||||
* For example, if you're using `fallback: 'app.html'` in your static adapter and your server
|
||||
* is redirecting to `/app`, you can configure `fallbackMapping: '/app'`.
|
||||
*
|
||||
* Since the static adapter will run after the PWA plugin generates the service worker,
|
||||
* the PWA plugin doesn't have access to the adapter fallback page to include the revision in the
|
||||
* service worker precache manifest.
|
||||
* To generate the revision for the fallback page, the PWA plugin will use the
|
||||
* `.svelte-kit/output/client/_app/version.json` file.
|
||||
* You can configure the `fallbackRevision` to generate a custom revision.
|
||||
*
|
||||
* @see https://svelte.dev/docs/kit/single-page-apps
|
||||
*/
|
||||
spa?: true | {
|
||||
fallbackMapping?: string;
|
||||
fallbackRevision?: () => Promise<string>;
|
||||
};
|
||||
}
|
||||
interface SvelteKitPWAOptions extends Partial<VitePWAOptions> {
|
||||
kit?: KitOptions;
|
||||
}
|
||||
|
||||
declare function SvelteKitPWA(userOptions?: Partial<SvelteKitPWAOptions>): Plugin[];
|
||||
|
||||
export { type KitOptions, SvelteKitPWA, type SvelteKitPWAOptions };
|
||||
+319
@@ -0,0 +1,319 @@
|
||||
import { VitePWA } from 'vite-plugin-pwa';
|
||||
import { resolve, join } from 'node:path';
|
||||
import { mkdir, rm, readFile, writeFile, rename, lstat } from 'node:fs/promises';
|
||||
import { glob } from 'tinyglobby';
|
||||
|
||||
function configureSvelteKitOptions(kit, viteOptions, options) {
|
||||
const {
|
||||
base = viteOptions.base ?? "/",
|
||||
adapterFallback,
|
||||
outDir = `${viteOptions.root}/.svelte-kit`,
|
||||
assets = "static"
|
||||
} = kit;
|
||||
if (typeof options.includeManifestIcons === "undefined")
|
||||
options.includeManifestIcons = false;
|
||||
let config;
|
||||
if (options.strategies === "injectManifest") {
|
||||
if (!options.srcDir)
|
||||
options.srcDir = "src";
|
||||
if (!options.filename)
|
||||
options.filename = "service-worker.js";
|
||||
options.injectManifest = options.injectManifest ?? {};
|
||||
config = options.injectManifest;
|
||||
} else {
|
||||
options.workbox = options.workbox ?? {};
|
||||
if (!("navigateFallback" in options.workbox))
|
||||
options.workbox.navigateFallback = adapterFallback ?? base;
|
||||
config = options.workbox;
|
||||
}
|
||||
if (!config.globDirectory)
|
||||
config.globDirectory = `${outDir}/output`;
|
||||
let buildAssetsDir = kit.appDir ?? "_app/";
|
||||
if (buildAssetsDir[0] === "/")
|
||||
buildAssetsDir = buildAssetsDir.slice(1);
|
||||
if (buildAssetsDir[buildAssetsDir.length - 1] !== "/")
|
||||
buildAssetsDir += "/";
|
||||
if (!config.modifyURLPrefix) {
|
||||
config.globPatterns = buildGlobPatterns(config.globPatterns);
|
||||
if (kit.includeVersionFile)
|
||||
config.globPatterns.push(`client/${buildAssetsDir}version.json`);
|
||||
}
|
||||
config.globIgnores = buildGlobIgnores(config.globIgnores);
|
||||
if (!("dontCacheBustURLsMatching" in config))
|
||||
config.dontCacheBustURLsMatching = new RegExp(`${buildAssetsDir}immutable/`);
|
||||
if (!config.manifestTransforms) {
|
||||
config.manifestTransforms = [createManifestTransform(
|
||||
base,
|
||||
config.globDirectory,
|
||||
options.strategies === "injectManifest" ? void 0 : options.manifestFilename ?? "manifest.webmanifest",
|
||||
kit
|
||||
)];
|
||||
}
|
||||
if (options.pwaAssets) {
|
||||
options.pwaAssets.integration = {
|
||||
baseUrl: base,
|
||||
publicDir: resolve(viteOptions.root, assets),
|
||||
outDir: resolve(outDir, "output/client")
|
||||
};
|
||||
}
|
||||
}
|
||||
function createManifestTransform(base, outDir, webManifestName, options) {
|
||||
return async (entries) => {
|
||||
const defaultAdapterFallback = "prerendered/fallback.html";
|
||||
const suffix = options?.trailingSlash === "always" ? "/" : "";
|
||||
let adapterFallback = options?.adapterFallback;
|
||||
let excludeFallback = false;
|
||||
if (!adapterFallback) {
|
||||
adapterFallback = defaultAdapterFallback;
|
||||
excludeFallback = true;
|
||||
}
|
||||
const manifest = entries.filter(({ url }) => !(excludeFallback && url === defaultAdapterFallback)).map((e) => {
|
||||
let url = e.url;
|
||||
if (url.startsWith("client/"))
|
||||
url = url.slice(7);
|
||||
else if (url.startsWith("prerendered/dependencies/"))
|
||||
url = url.slice(25);
|
||||
else if (url.startsWith("prerendered/pages/"))
|
||||
url = url.slice(18);
|
||||
else if (url === defaultAdapterFallback)
|
||||
url = adapterFallback;
|
||||
if (url.endsWith(".html")) {
|
||||
if (url.startsWith("/"))
|
||||
url = url.slice(1);
|
||||
if (url === "index.html") {
|
||||
url = base;
|
||||
} else {
|
||||
const idx = url.lastIndexOf("/");
|
||||
if (idx > -1) {
|
||||
if (url.endsWith("/index.html"))
|
||||
url = `${url.slice(0, idx)}${suffix}`;
|
||||
else
|
||||
url = `${url.substring(0, url.lastIndexOf("."))}${suffix}`;
|
||||
} else {
|
||||
url = `${url.substring(0, url.lastIndexOf("."))}${suffix}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
e.url = url;
|
||||
return e;
|
||||
});
|
||||
if (options?.spa && options?.adapterFallback) {
|
||||
const name = typeof options.spa === "object" && options.spa.fallbackMapping ? options.spa.fallbackMapping : options.adapterFallback;
|
||||
if (typeof options.spa === "object" && typeof options.spa.fallbackRevision === "function") {
|
||||
manifest.push({
|
||||
url: name,
|
||||
revision: await options.spa.fallbackRevision(),
|
||||
size: 0
|
||||
});
|
||||
} else {
|
||||
manifest.push(await buildManifestEntry(
|
||||
name,
|
||||
resolve(outDir, "client/_app/version.json")
|
||||
));
|
||||
}
|
||||
}
|
||||
if (!webManifestName)
|
||||
return { manifest };
|
||||
return { manifest: manifest.filter((e) => e.url !== webManifestName) };
|
||||
};
|
||||
}
|
||||
function buildGlobPatterns(globPatterns) {
|
||||
if (globPatterns) {
|
||||
if (!globPatterns.some((g) => g.startsWith("prerendered/")))
|
||||
globPatterns.push("prerendered/**/*.{html,json}");
|
||||
if (!globPatterns.some((g) => g.startsWith("client/")))
|
||||
globPatterns.push("client/**/*.{js,css,ico,png,svg,webp,webmanifest}");
|
||||
if (!globPatterns.some((g) => g.includes("webmanifest")))
|
||||
globPatterns.push("client/*.webmanifest");
|
||||
return globPatterns;
|
||||
}
|
||||
return ["client/**/*.{js,css,ico,png,svg,webp,webmanifest}", "prerendered/**/*.{html,json}"];
|
||||
}
|
||||
function buildGlobIgnores(globIgnores) {
|
||||
if (globIgnores) {
|
||||
if (!globIgnores.some((g) => g.startsWith("server/")))
|
||||
globIgnores.push("server/**");
|
||||
return globIgnores;
|
||||
}
|
||||
return ["server/**"];
|
||||
}
|
||||
async function buildManifestEntry(url, path) {
|
||||
const [crypto, createReadStream] = await Promise.all([
|
||||
import('node:crypto').then((m) => m.default),
|
||||
import('node:fs').then((m) => m.createReadStream)
|
||||
]);
|
||||
return new Promise((resolve2, reject) => {
|
||||
const cHash = crypto.createHash("MD5");
|
||||
const stream = createReadStream(path);
|
||||
stream.on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
stream.on("data", (chunk) => {
|
||||
cHash.update(chunk);
|
||||
});
|
||||
stream.on("end", () => {
|
||||
return resolve2({
|
||||
url,
|
||||
size: 0,
|
||||
revision: `${cHash.digest("hex")}`
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function SvelteKitPlugin(options, apiResolver) {
|
||||
let viteConfig;
|
||||
return {
|
||||
name: "vite-plugin-pwa:sveltekit:build",
|
||||
apply: "build",
|
||||
enforce: "pre",
|
||||
configResolved(config) {
|
||||
viteConfig = config;
|
||||
},
|
||||
async generateBundle(_, bundle) {
|
||||
if (viteConfig.build.ssr)
|
||||
return;
|
||||
const api = apiResolver();
|
||||
if (!api)
|
||||
return;
|
||||
const assetsGenerator = await api.pwaAssetsGenerator();
|
||||
if (assetsGenerator)
|
||||
assetsGenerator.injectManifestIcons();
|
||||
api.generateBundle(bundle, this);
|
||||
},
|
||||
writeBundle: {
|
||||
sequential: true,
|
||||
enforce: "pre",
|
||||
async handler() {
|
||||
const api = apiResolver();
|
||||
if (!api || viteConfig.build.ssr)
|
||||
return;
|
||||
const assetsGenerator = await api.pwaAssetsGenerator();
|
||||
if (assetsGenerator)
|
||||
await assetsGenerator.generate();
|
||||
}
|
||||
},
|
||||
closeBundle: {
|
||||
sequential: true,
|
||||
enforce: "pre",
|
||||
async handler() {
|
||||
const api = apiResolver();
|
||||
if (api && !api.disabled && viteConfig.build.ssr) {
|
||||
const webManifest = options.manifestFilename ?? "manifest.webmanifest";
|
||||
let swName = options.filename ?? "sw.js";
|
||||
const outDir = options.outDir ?? `${viteConfig.root}/.svelte-kit/output`;
|
||||
const clientOutputDir = join(outDir, "client");
|
||||
await mkdir(clientOutputDir, { recursive: true });
|
||||
if (!options.strategies || options.strategies === "generateSW" || options.selfDestroying) {
|
||||
let path;
|
||||
let existsFile;
|
||||
if (options.selfDestroying && options.strategies === "injectManifest") {
|
||||
if (swName.endsWith(".ts"))
|
||||
swName = swName.replace(/\.ts$/, ".js");
|
||||
path = join(clientOutputDir, "service-worker.js").replace("\\/g", "/");
|
||||
existsFile = await isFile(path);
|
||||
if (existsFile)
|
||||
await rm(path);
|
||||
}
|
||||
await api.generateSW();
|
||||
const serverOutputDir = join(outDir, "server");
|
||||
path = join(serverOutputDir, swName).replace(/\\/g, "/");
|
||||
existsFile = await isFile(path);
|
||||
if (existsFile) {
|
||||
const sw = await readFile(path, "utf-8");
|
||||
await writeFile(
|
||||
join(clientOutputDir, swName).replace("\\/g", "/"),
|
||||
sw,
|
||||
"utf-8"
|
||||
);
|
||||
await rm(path);
|
||||
}
|
||||
const result = await glob({
|
||||
patterns: ["workbox-*.js"],
|
||||
cwd: serverOutputDir,
|
||||
onlyFiles: true,
|
||||
expandDirectories: false
|
||||
});
|
||||
if (result && result.length > 0) {
|
||||
path = join(serverOutputDir, result[0]).replace(/\\/g, "/");
|
||||
await writeFile(
|
||||
join(clientOutputDir, result[0]).replace("\\/g", "/"),
|
||||
await readFile(path, "utf-8"),
|
||||
"utf-8"
|
||||
);
|
||||
await rm(path);
|
||||
}
|
||||
path = join(serverOutputDir, webManifest).replace(/\\/g, "/");
|
||||
existsFile = await isFile(path);
|
||||
if (existsFile)
|
||||
await rm(path);
|
||||
return;
|
||||
}
|
||||
if (swName.endsWith(".ts"))
|
||||
swName = swName.replace(/\.ts$/, ".js");
|
||||
const injectionPoint = !options.injectManifest || !("injectionPoint" in options.injectManifest) || !!options.injectManifest.injectionPoint;
|
||||
if (injectionPoint) {
|
||||
const injectManifestOptions = {
|
||||
globDirectory: outDir.replace(/\\/g, "/"),
|
||||
...options.injectManifest ?? {},
|
||||
swSrc: join(clientOutputDir, "service-worker.js").replace(/\\/g, "/"),
|
||||
swDest: join(clientOutputDir, "service-worker.js").replace(/\\/g, "/")
|
||||
};
|
||||
const [injectManifest, logWorkboxResult] = await Promise.all([
|
||||
import('workbox-build').then((m) => m.injectManifest),
|
||||
import('./chunks/log.mjs').then((m) => m.logWorkboxResult)
|
||||
]);
|
||||
const buildResult = await injectManifest(injectManifestOptions);
|
||||
logWorkboxResult("injectManifest", viteConfig, buildResult);
|
||||
if (swName !== "service-worker.js") {
|
||||
await rename(
|
||||
join(clientOutputDir, "service-worker.js").replace("\\/g", "/"),
|
||||
join(clientOutputDir, swName).replace("\\/g", "/")
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const { logWorkboxResult } = await import('./chunks/log.mjs');
|
||||
logWorkboxResult("injectManifest", viteConfig);
|
||||
if (swName !== "service-worker.js") {
|
||||
await rename(
|
||||
join(clientOutputDir, "service-worker.js").replace("\\/g", "/"),
|
||||
join(clientOutputDir, swName).replace("\\/g", "/")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
async function isFile(path) {
|
||||
try {
|
||||
const stats = await lstat(path);
|
||||
return stats.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function SvelteKitPWA(userOptions = {}) {
|
||||
if (!userOptions.integration)
|
||||
userOptions.integration = {};
|
||||
userOptions.integration.closeBundleOrder = "pre";
|
||||
userOptions.integration.configureOptions = (viteConfig, options) => configureSvelteKitOptions(
|
||||
userOptions.kit ?? {},
|
||||
viteConfig,
|
||||
options
|
||||
);
|
||||
const plugins = VitePWA(userOptions);
|
||||
const plugin = plugins.find((p) => p && typeof p === "object" && "name" in p && p.name === "vite-plugin-pwa");
|
||||
const resolveVitePluginPWAAPI = () => {
|
||||
return plugin?.api;
|
||||
};
|
||||
return [
|
||||
// remove the build plugin: we're using a custom one
|
||||
...plugins.filter((p) => p && typeof p === "object" && "name" in p && p.name !== "vite-plugin-pwa:build"),
|
||||
SvelteKitPlugin(userOptions, resolveVitePluginPWAAPI)
|
||||
];
|
||||
}
|
||||
|
||||
export { SvelteKitPWA };
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "@vite-pwa/sveltekit",
|
||||
"type": "module",
|
||||
"version": "1.1.0",
|
||||
"description": "Zero-config PWA for SvelteKit",
|
||||
"author": "antfu <anthonyfu117@hotmail.com>",
|
||||
"license": "MIT",
|
||||
"funding": "https://github.com/sponsors/antfu",
|
||||
"homepage": "https://github.com/vite-pwa/sveltekit#readme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vite-pwa/sveltekit.git"
|
||||
},
|
||||
"bugs": "https://github.com/vite-pwa/sveltekit/issues",
|
||||
"keywords": [
|
||||
"sveltekit",
|
||||
"workbox",
|
||||
"pwa",
|
||||
"vite",
|
||||
"vite-plugin"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.mjs"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"types": "dist/index.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"./dist/index.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@sveltejs/kit": "^1.3.1 || ^2.0.1",
|
||||
"@vite-pwa/assets-generator": "^1.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vite-pwa/assets-generator": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"kolorist": "^1.8.0",
|
||||
"tinyglobby": "^0.2.9",
|
||||
"vite-plugin-pwa": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^4.11.0",
|
||||
"@antfu/ni": "^0.23.2",
|
||||
"@types/debug": "^4.1.8",
|
||||
"@types/node": "^18.17.15",
|
||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||
"bumpp": "^9.2.0",
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-plugin-svelte": "^3.3.3",
|
||||
"typescript": "^5.7.2",
|
||||
"unbuild": "^3.2.0",
|
||||
"vite": "^5.0.10"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "nr lint --fix",
|
||||
"release": "bumpp",
|
||||
"test": "pnpm run -C examples/sveltekit-ts test && pnpm run -C examples/sveltekit-ts-assets-generator test"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user