Comments (51)
I ran into the same problem. In my case, I am using the adapter-netlify
. I will admit much of this is over my head. I tried some of the initial suggestions, but I feel the conversation moved beyond my understanding of the internals of the frameworks involved.
Should I assume the pwa plugin will remain as is and I should work through the information in this issue, or would that work be nullified by an upcoming release that will address this issue?
Thank you all again for the great work you are doing!
from sveltekit.
@kyllerss pwa plugin is just a wrapper for workbox-build, that is file based, that's, to generate the sw precache manifest (injection point/self.__WB_MANIFEST
) it will traverse a folder, and so kit integration will configure pwa plugin to run after prerender but before adapter processes in kit/vite lifecycle: we need the assets but also the prerendered pages.
Once prerender finish, pwa plugin will call workbox-build to generate the sw precache manifest: we need to configure pwa plugin properly via globDirectory
on workbox
or injectManifest
: workbox-build will use globDirectory
to traverse it and generate the sw with the sw precache manifest. We also need to configure properly the output folder, that's, the sw.js should be generated in the kit output build folder, that adapter will copy to the final build folder.
Once we have configured the pwa plugin, we can add some hooks to workbox-build before sw.js is written to disk: kit integration adds a ManifestTransform (will receive file paths in globDirectory and their revision/hash, a list of ManifestEntry objects) to apply some custom transformations (pretty url and fallback url for adapter). You can check it here, the config module has a few comments about kit output folder: https://github.com/vite-pwa/sveltekit/blob/main/src/config.ts#L60
With latest vite-plugin-pwa
version released 0.14.0
(kit integration not updated nor released yet) we can use custom sw without injection point (I also need to update the docs to add this new option).
from sveltekit.
Hi, checking in. Is the fix for this one on the roadmap or is there some workaround I should be applying in the meantime (wasn't clear from the comments). Thanks!
from sveltekit.
@userquin I am using the standard service worker.
import {
cleanupOutdatedCaches,
createHandlerBoundToURL,
precacheAndRoute
} from 'workbox-precaching';
import { NavigationRoute, registerRoute } from 'workbox-routing';
declare let self: ServiceWorkerGlobalScope;
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') self.skipWaiting();
});
// self.__WB_MANIFEST is default injection point
precacheAndRoute(self.__WB_MANIFEST);
// clean old assets
cleanupOutdatedCaches();
let allowlist: undefined | RegExp[];
if (import.meta.env.DEV) allowlist = [/^\/$/];
// to allow work offline
registerRoute(new NavigationRoute(createHandlerBoundToURL('/'), { allowlist }));
After removing the offline part, the service worker is working fine. But what If I want to use the offline mode?
from sveltekit.
@Cluster2a can you create a minimal repro?
https://github.com/Cluster2a/pwa_examle - same stuff with the wrong URLs.
from sveltekit.
@Cluster2a I'll check it tmr, thx
from sveltekit.
This is also failing for me. I'll try the SvelteKit suplied service worker, but it would be cool to have a big notice saying vite-pwa
doesn't work in SvelteKit if you're using adapter-node` so we don't lose so much time trying to guess what happens.
from sveltekit.
I'm still having this issue with the latest with adapter-auto deployed on vercel. Simultaneously I'm also struggling where my default route in development seems to be caching a redirect (but rendering the content from the redirect at the / route). I'm going to keep diving in, but wanted to give a heads up. vite config below.
SvelteKitPWA({ srcDir: './src', mode: process.env.NODE_ENV, // will default to process.env.NODE_ENV scope: '/', base: '/', selfDestroying: process.env.SELF_DESTROYING_SW === 'true', manifest: { short_name: 'XXXX', name: 'XXXX', start_url: '/', scope: '/', display: 'standalone', theme_color: "#ffffff", background_color: "#ffffff", icons: [ { "src": "/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icon-256x256.png", "sizes": "256x256", "type": "image/png" }, { "src": "/icon-384x384.png", "sizes": "384x384", "type": "image/png" }, { "src": "/icon-512x512.png", "sizes": "512x512", "type": "image/png", "purpose": 'any maskable', } ], }, workbox: { globPatterns: ['client/**/*.{js,css,ico,png,svg,webp,woff,woff2}'] }, devOptions: { enabled: true, type: 'module' }, // if you have shared info in svelte config file put in a separate module and use it also here kit: {} })
`
from sveltekit.
@phil-w You need to prerender that route, workbox requires the html file, check if the index.html is present in your kit output folder, inside prerender folder
from sveltekit.
@Cluster2a can you shared your pwa plugin options?
from sveltekit.
Hey - sure! Her you go.
SvelteKitPWA({
srcDir: './src',
mode: process.env.NODE_ENV as 'development' | 'production',
strategies: 'injectManifest',
filename: 'sw.ts',
scope: '/',
base: '/',
injectRegister: 'script',
includeAssets: ['favicon.ico', 'apple-touch-icon.png', '/img/mask-icon.svg'],
manifest: {
short_name: 'freispace',
name: 'freispace',
description: 'Your supercharged resource and project management.',
start_url: '/dashboard?source=pwa',
scope: '/',
display: 'standalone',
theme_color: '#006aa3',
background_color: '#f3f4f6',
icons: [
{
src: '/img/pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any'
},
{
src: '/img/pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any'
},
{
src: '/img/favicon.svg',
sizes: 'any',
type: 'image/svg+xml',
purpose: 'any'
}
],
shortcuts: [
{
name: 'freispace Dashboard',
short_name: 'Dashboard',
url: '/dashboard?source=pwa',
icons: [
{
src: '/img/pwa-dashboard.png',
type: 'image/png',
sizes: '96x96'
},
{
src: '/img/pwa-dashboard.svg',
type: 'image/svg+xml',
sizes: 'any'
}
]
},
{
name: 'freispace Planner',
short_name: 'Planner',
url: '/planning/overview?source=pwa',
icons: [
{
src: '/img/pwa-planner.png',
type: 'image/png',
sizes: '96x96'
},
{
src: '/img/pwa-planner.svg',
type: 'image/svg+xml',
sizes: 'any'
}
]
}
]
},
injectManifest: {
globPatterns: ['client/**/*.{js,css,ico,png,svg,webp,woff,woff2}']
},
devOptions: {
enabled: true,
type: 'module',
navigateFallback: '/'
}
})
from sveltekit.
@Cluster2a can you share your sw.ts?
EDIT: you can try removing offline route:
// to allow work offline
registerRoute(new NavigationRoute(
createHandlerBoundToURL('/'),
{ allowlist },
))
from sveltekit.
@userquin, what if I want to use the offline mode?
Removing this is just like a workaround but not a real fix, or am I mistaken here?
from sveltekit.
@Cluster2a try configuring /404
adding +error.svelte
with prerender enabled in +error.ts
: export const prerender = true;
.
from sveltekit.
@userquin do you mean like this? It doesn't work either:
from sveltekit.
@userquin, ah I see - you asked for an +error.ts. This does not seem to be allowed in svelteKit:
To make it a little bit more clear, my app is calling an API in the hooks.server.ts. Because of this, I am disabling the prerendering in the svelte.config.js.
I could enable this again and only pre-render the 404, but according to the svelteKit documentation, there is no way to set pretender = true for the error-page.
from sveltekit.
@Cluster2a try adding it at least to the entry point (/
: +page.ts
), if there is no prerender we cannot fallback to any url...
from sveltekit.
@Cluster2a have you tried to just request some missing page without the offline entry?
from sveltekit.
@Cluster2a the docs allows you to create an error.html
under src folder, check where it is copied then use it as fallback:
https://kit.svelte.dev/docs/routing#error
from sveltekit.
@userquin I created a /sw/+page.svelte & /sw/+page.ts (prerender = true).
registerRoute(new NavigationRoute(createHandlerBoundToURL('/sw'), { allowlist }));
I also excluded this route from my hook.
This seems to work now.
Is this a valid way to handle this?
from sveltekit.
I also checked the fallback error:
But I wasn't able to access it via URL.
from sveltekit.
@Cluster2a what adapter are you using? try adding the fallback to kit adapter config file and also to kit entry in pwa options:
https://vite-pwa-org.netlify.app/frameworks/sveltekit.html#sveltekit-and-adapters
The fallback is always generated, the adapter should copy it to the build folder... if you don't add the fallback to the adapter, the page will not be copied
from sveltekit.
@userquin, i am using @sveltejs/adapter-node.
I am not aware of the fallback option. I need to check that out.
from sveltekit.
@Cluster2a you can check this repo (using static adapter):
- pwa: https://github.com/Giszmo/nostroid/blob/master/nostroid-config.js#L46
- kit: https://github.com/Giszmo/nostroid/blob/master/svelte.config.js#L15
- vite: https://github.com/Giszmo/nostroid/blob/master/vite.config.ts#L13
EDIT: what's the build folder for adapter node? can you check if the fallback is there? Your previous screenshot is the kit output.
from sveltekit.
@userquin, I can not use the static adapter since I am using server-side endpoints which are not supported by this adapter.
The node-adapter does not seem to accept a fallback option.
My build folder looks like this:
from sveltekit.
@Cluster2a it is using also build
folder, and it is copying all client and prerendered folders, so we need to add a custom manifestTransform
to the pwa plugin: just check the code in the config.ts module in this repo.
The layout is different, static-adapter will copy the client and prerendered folders contents in the build folder, adapter node will copy also the client and the prerendered to the build.
EDIT: Im think we don't need to change it, it is a problem serving assets: what is the url for /sw
? it should be /sw
and not /prerendered/sw
so you need a hack to serve any generated html page.
from sveltekit.
The node-adapter does not seem to accept a fallback option.
Then, how the adapter serves the client assets? Maybe you only need to add a node/express middleware, when requesting /sw
just serve the content from prerendered/sw.html
.
EDIT: the client and the prerender folders are part of the request? if so, you will need to change the manifestTransform
. Can you share the repo? I can review the vite pwa kit integration to add custom manifestTransform for each adapter.
from sveltekit.
EDIT: Im think we don't need to change it, it is a problem serving assets: what is the url for
/sw
? it should be/sw
and not/prerendered/sw
so you need a hack to serve any generated html page.
@userquin I think you got me wrong... When requesting /sw the prerendered/sw.html is served correctly and the service worker is working.
But somehow this feels kind of hacky to create a custom pre-rendered page and exclude it in my hook just for the service worker to work correctly.
from sveltekit.
@Cluster2a configure /sw
in the offline route: try requesting some non existing route/page
EDIT: I was checking the adapter hander, it has 3 serve entries forwarding content from static, client and prerendered folder: https://github.com/sveltejs/kit/blob/master/packages/adapter-node/src/handler.js#L139
from sveltekit.
@userquin requesting an invalid route will bring up my error-page (404). So this seems to work.
from sveltekit.
@userquin requesting an invalid route will bring up my error-page (404). So this seems to work.
try it also setting offline the browser
from sveltekit.
@userquin, the cache seems to be messed up:
All the JS files are served directly from the /_app -Folder.
When accessing the files form cache, it somehow messes up the path:
It is adding the folder of the route, which is wrong.
from sveltekit.
@Cluster2a can you create a minimal repro?
from sveltekit.
@Cluster2a check this commit on my fork: userquin/vite-pwa-kit-issue-16@29fb7bc
The main problem with this approach is the navigation pages is not being cached, so you need to refresh/visit the page twice, check it, the offline support should work (since you have a login page I cannot test it).
Check also the changes in the pwa options, added useCredentials and removed includeAssets adding also the exclusion of the icons in the manifest (on kit there is no need, only when using Vite).
You can check the sw and adjust the logic, the sw logic is being called:
from sveltekit.
@Cluster2a pushed another commit on my fork, app working but kit not showing the content (hydration problem?)
from sveltekit.
I'm adding @vite-pwa/sveltekit to my SvelteKit template project, and I have the same issue, though I'm using adapter-static for debugging. So I stepped through the sw.js with debugger in the browser and figured out that there is a disconnect between how the urls are actually handled and how example code shows them.
If I replace:
- registerRoute(new NavigationRoute(createHandlerBoundToURL('/sw'), { allowlist: [/^\/$/] }));
+ registerRoute(new NavigationRoute(createHandlerBoundToURL('prerendered/pages/sw.html'), { allowlist: [/^\/$/] }));
- it gets to pass this route ok.
However, it fails further down with the 404 error trying to cache the very first item from the manifest, and the code is complaining about url:
/client/_app/immutable/assets/_layout-ba887965.css
I find the same item in the precache manifest, but without the leading slash '/':
client/_app/immutable/assets/_layout-ba887965.css
However, the request works only for:
/_app/immutable/assets/_layout-ba887965.css
@userquin - is that what your clone repo tries to do - sanitize the urls and clip the prefix?
from sveltekit.
I investigated further, and concluded that SW on client is wrong place to sort out the problem. Precache manifest should be handled at build time, with manifestTransforms parameter to SvelteKitPWA plugin.
Here's version that works with adapter-static, adapter-netlify and adapter-vercel (sorry, I don't have a setup to try adapter-node):
const scope = '/';
// For @sveltejs/adapter-static, @sveltejs/adapter-netlify, @sveltejs/adapter-vercel
/** @type {import('workbox-build').ManifestTransform} */
const manifestTransformStatic = async (manifestEntries) => {
console.info('Precache Manifest Entries:');
const manifest = manifestEntries
.filter(
({ url }) =>
// Remove paths that should not be cached:
url !== 'client/vite-manifest.json' && url !== 'prerendered/fallback.html'
// && url !== 'client/manifest.webmanifest' && !url.endsWith('sw.js') && !url.startsWith('workbox-')
)
.map((e) => {
// Adjust paths to match what the adapter server understands:
const url1 = e.url;
let url = e.url;
if (url.startsWith('/')) url = url.slice(1);
if (url.startsWith('client/')) url = url.slice(7);
if (url.startsWith('prerendered/pages/')) url = url.slice(18);
// router paths
if (url && url.endsWith('.html')) {
url = url === 'index.html' ? '' : `${url.substring(0, url.lastIndexOf('.'))}`;
}
e.url = scope + url; // Canonical URL starts with base
console.info(` ${url1.padEnd(100)} => ${JSON.stringify(e)}`);
return e;
});
return { manifest };
};
const manifestTransforms = [manifestTransformStatic];
Pass manifestTransforms
to SvelteKitPWA.
from sveltekit.
I also checked source of @vite-pwa/sveltekit
, and found it sets default manifestTransforms
by createManifestTransform()
which does pretty much the same as what I posted above in manifestTransformStatic()
, with createManifestTransform()
handling settings more thoroughly.
The reason it was not working in my case, is I had manifestTransforms
set to a non-transform, just to log the precache manifest.
So for the adapter-node
- it server static, client and prerender. Note that adapter-static serves prerender/pages, which means adapter-node will have /page/index.html
, not /index.html
. Default createManifestTransform()
does not handle that case. The quick fix could be to use my manifestTransformStatic()
and adjust the paths until they match what adapter-node serves.
BTW, createManifestTransform()
might emit precache manifest with a duplicate entry, if fallback
is set to index.html
. Just note that it is a special case and handle it accordingly - precache manifest is created from list of paths found in ./.svelte-kit/output/client
, and transformManifest should emit the list of paths matching what is served by the adapter.
from sveltekit.
@iva2k thx for investigating this, I have it pending, maybe we can add some presets, pr welcome
from sveltekit.
thx for investigating this, I have it pending, maybe we can add some presets, pr welcome
I'd like to submit a PR, but the scope is unclear...
I'm thinking that best design would be to have createManifestTransform()
coordinate with the adapter, maybe just get a map (source file -> URL destination) from the adapter and use that map, or adapter should provide the transform function, since it only knows how things will be on the server.
Another improvement is to expose / export createManifestTransform(), and allow caller to compose their array of transforms and invoke the standard one which came from the adapter in their chain. That way adapter will have a say, and custom transform added before or after can act on URLs (post) or on file paths (pre), and won't need to know how things are mapped.
Right now custom transform should know what the adapter does, but it has no context to get which adapter is used. In case of adapter-auto, there are few possible actual adapters that custom transform has to figure out. And users could make their own custom adapters. Extending adapter scope will go into sveltejs/kit
repo. If that PR is rejected, there's no way to make an informed transform.
from sveltekit.
@iva2k if you provide a custom TransformManifest the plugin will no register the default one. We can add some preset folder adding there the required stuff, maybe also adding some custom configuration options, not only the TransformManifest:
https://github.com/vite-pwa/sveltekit/blob/main/src/config.ts#L56
from sveltekit.
if you provide a custom TransformManifest the plugin will no register the default one
Yes. What I'm saying is if I can call createManifestTransform()
and get the default transform, I could use it in my chain and do this:
import {createManifestTransform} from '@vite-pwa/sveltekit';
const myPreTransform = (manifest) => {... my file transforms; return manifest; }
const myPostTransform = (manifest) => {... my URL transforms; return manifest; }
const defaultTransform = createManifestTransform();
const transforms = [
myPreTransform,
defaultTransform,
myPostTransform
];
Then just pass transforms
to the plugin.
from sveltekit.
@iva2k oh yeah, maybe we can add preManifestTransform
and postManifestTransform
options to the kit entry with the following logic:
- if
manifestTransform
not empty, then unshiftpreManifestTransform
and addpostManifestTransform
(this no makes sense, since you are adding the callbacks on the pwa workbox/injectManifest option, so can be ignored, add all in the corresponding option) - if
manifestTransform
not configured or empty then addpreManifestTransform
, then add default one and finally addpostManifestTransform
We can also export createManifestTransform
: I guess we can also add default presets for adapters (if needed).
If we need the presets for the adapters, we'll also need to add an option for the preset: in previous logic we'll use the preset instead the default one (that shhould be the default preset, similar to adapter-auto)
from sveltekit.
I'm also getting this issue with the default config provided in the docs and using adapter-auto, seems like it's preventing the service-worker to install in safari
from sveltekit.
check #30 we've detected a bug in custom manifest transform, should be fixed once new version released, in the meantime try adding the manifest transform in the PR to your workbox: { manifestTransform: [] }
or injectManifest: { manifestTransform: [] }
array depending on the strategy used.
from sveltekit.
So has this issue been resolved? And if so, is there a guide or demo project I can follow? The above discussion does not seem to solve this issue for me. I can't seem to get the offline caching of the pages working, receiving the same error Uncaught non-precached-url: non-precached-url :: [{"url":"/"}]
when deployed to Vercel.
I want to purely store the application in cache and nothing else, the webapp can just make http requests which will be handled by the service workers.
from sveltekit.
@ESchouten have you tried the service worker from the SvelteKit docs? It pretty much does caching and nothing else, and it's pretty straight forward to modify.
from sveltekit.
@nadanke @ktecho Yes, that's what I am doing now, I am using the Workbox libraries and use these functions directly in Sveltekits service-worker.ts.
But since VitePWA advertises with being zero-config, I was hoping the caching & offline working part of PWAs would be automatically solved for my application.
from sveltekit.
closed via #32
from sveltekit.
Yeah I'm getting this too, not sure what it's about as I have a path / and it works fine, so I can't see why it'd whine about it.
from sveltekit.
Ah, thanks, copy that.
from sveltekit.
Related Issues (20)
- Having an issue with ssr = false HOT 8
- Issues with SPA HOT 1
- Inject Register script or inline has no effect on output HTML. HOT 6
- [Info] Cloudflare Adapter Routes misses vite-pwa HOT 1
- Cannot find module 'virtual:pwa-info' or its corresponding type declarations HOT 26
- Importing 'virtual:pwa-register' causes bug on build HOT 3
- Make client Javascript work offline HOT 2
- Deprecated packages HOT 2
- Uncaught (in promise) non-precached-url: non-precached-url :: [{"url":"/"}] HOT 13
- Navigating to SvelteKit error page after a new build causes infinite page reload loop HOT 6
- InjectManifest `The 'swSrc' file can't be read. ENOENT: no such file or directory` error on Gitlab CI HOT 5
- Uncaught ReferenceError: process is not defined for injectManifest HOT 1
- Error: [InjectManifest] 'plugins' property is not expected to be here. HOT 1
- Support Node v20 HOT 1
- Uncaught SyntaxError: Unexpected token 'export' HOT 3
- `_app/version.json` should be included in sw precache manifest
- Please document that images that are outside of `/static` will NOT build in production HOT 2
- Workbox responses with cached data for network only requests HOT 20
- One of the glob patterns doesn't match any files HOT 6
- Please provide a minimal example
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sveltekit.