vite-plugin-pwa
vite-plugin-pwa copied to clipboard
Doesn't work with `vite-tsconfig-paths`
The VitePWA plugin seem not respecting or using Vite to transpile the files. this is my vite.config.ts
import baseConfig from '../vite.config.ts'
export default mergeConfig(baseConfig, {
plugins: [
react(),
VitePWA({
strategies: 'injectManifest',
srcDir: '.',
filename: 'service-worker.ts',
}),
],
})
and this is the parent vite.config.ts
export default defineConfig({ plugins: [tsConfigPaths({ root: './' })] });
In service-worker.ts
, I used import alias like
import someDep from '@project/module'
when building, it show this error message:
"@project/module" is imported by "core/service-worker.ts", but could not be resolved – treating it as an external dependency.
also if I use typescript for the custom service worker file,
the dev mode will be broken:
![Screen Shot 2023-02-15 at 20 11 34](https://user-images.githubusercontent.com/8536244/219011896-d2e67588-dcda-45f0-9664-185c1c6d1e5b.png)
![Screen Shot 2023-02-15 at 20 11 55](https://user-images.githubusercontent.com/8536244/219011959-5212c4e1-10e8-4c46-b4f9-7280bcee4cb8.png)
it seems the file is not passed to vite to transpile,
which means the dev-sw.js
is actually a typescript file
@nodegin on dev, the plugin doesn't build the sw, it's "build" by Vite (esbuild) removing ts annotations, you will need to resolve that dependency, try adding an alias.
can you provide a minimal repro?
@userquin I have created a minimal reproduction repo: https://github.com/nodegin/vite-pwa-reprod
I tried build, it does not respect vite plugin as well during build. Alias seem working but not a ideal solution since my project have so many aliases, it should respect the tsconfigPlugin which auto loads the aliases
dev is working, checking build...
also working on build, you need to add an alias to resolve the library:
// apps/core/vite.config.ts
resolve: {
alias: {
'@repro/library': '../../../libs/library/src/index.ts',
},
},
@userquin I understand adding resolve alias would work but as I point out before it seem to be not an ideal solution, because the paths in our real tsconfig.base.json is gigantic, it means we have to duplicate all those paths once more😢 and that's already handled by the tsconfigPlugin which is consumed by vite, is it possible to work together with other plugins?
you can use this (import defaultInjectManifestVitePlugins
adding ts plugin in injectManifest.vitePlugins
option):
// apps/core/vite.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vite';
import { VitePWA, defaultInjectManifestVitePlugins } from 'vite-plugin-pwa';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
cacheDir: '../../node_modules/.vite/core',
mode: 'development',
/*
resolve: {
alias: {
'@repro/library': '../../../libs/library/src/index.ts',
},
},
*/
server: {
port: 4200,
host: 'localhost',
},
preview: {
port: 4300,
host: 'localhost',
},
plugins: [
viteTsConfigPaths({
root: '../../',
}),
VitePWA({
mode: 'development',
strategies: 'injectManifest',
srcDir: './src',
filename: 'sw.ts',
injectManifest: {
vitePlugins: defaultInjectManifestVitePlugins.concat('vite-tsconfig-paths')
},
devOptions: {
enabled: true,
type: 'module',
}
}),
],
});
@nodegin @pgsteven have you tested my previous suggestion? you can add the names of any plugin you have in Vite plugins.
@userquin Sorry for late reply. I just tested again earlier, and still can't get it working in my real project.
After adding the defaultInjectManifestVitePlugins
it seems the alias is working now,
but then there is another new issue which seems having conflict with the @vitejs/plugin-react
plugin.
I find it related to the @vitejs/plugin-react
plugin, which would automatically add some code to the react component contains window
object,
and which is unavailable in service workers.
![image](https://user-images.githubusercontent.com/8536244/219893754-b1b1e16f-596f-40c1-836b-9b7e3311ca0a.png)
![Screen Shot 2023-02-19 at 5 22 02](https://user-images.githubusercontent.com/8536244/219893793-7659106c-25c6-4024-995b-2d8642422436.png)
I have updated my reproduction repo,
if you try to remove the @vitejs/plugin-react
plugin by commenting react(),
in vite.config.ts, it will work well.
Also, putting @vitejs/plugin-react
in defaultInjectManifestVitePlugins does not work
Why do you need react in the sw? That option is to allow add plugins configured in your vite app in custom rollup buiild for your custom sw, you can check src/modules.ts
in the repo.
I Will check your uodated repo tmr.
@userquin I didn't use React in SW.
The problem is, @repro/library
contains both the code I need to use in SW,
while also in my core application, it seem this mechanism will break the SW because the module imported contains React pieces
Split it into 2 modules, one for your app and another for the sw
You can have a lot of modules, for your app just re-export everything on one module and in the sw import just another one re-exporting what sw needs. Ofc in sw one dont use any module with react dependencies.
But the problem is, if you comment the @vitejs/plugin-react
plugin it will work, even it still contains React code.
Also, in the real project the sw.js is migrated from webpack, which also working fine even with React code.
So the problem seem to be vite-plugin-pwa
incompatible with @vitejs/plugin-react
?
Splitting is not a solution to us since our app is on production, splitting it basically mean we have to rewrite the whole app and the logics.
@nodegin
You only need to split it into 2 modules @repro/library
, you don't need to change any line in your code base just the library:
- move logic required by the sw to a separate module
- Include in
@repo/library
the import for previous new one module andexport * from xxxx
(just re-export everything from it: the logic has been only moved - add a new map
@repro/sw-library
for 1 - Import previous module in the sw
When building the sw we use a separate rollup build configuring some vite internal plugins, the plugin Will also allow you to add any plugin configured plugin in your vite config file.
You only need ts plugin to be include in the rollup build of your sw to resolve some external dependency. The option in my prevoius comment is to include ts plugin, we seek the plugin by name.
You can check L130 on src/modules.ts
.
If you have a monolitic module with disparate dependencies, you will be able to use it in some environments. For example, your app Will not work on node server if you dont use jsdom or happy-dom to mock window/document. In a sw is even worst, you dont have globalThis/global, polyfills Will also fail to mock sw self.
@userquin but I think it is still an issue, ideally even if it contains React code, it should not affect the vite to compile the code? since the sw only import the test
property which is purely a string, and as I mentioned before without the plugin-react it works perfectly, even I add something having the window.
export const func = () => (window as any)['test']
![image](https://user-images.githubusercontent.com/8536244/219932111-d4ca41ce-9bbb-4c09-9234-e8b47ccf35a7.png)
So I really don't get why it can't work with the react plugin?
@nodegin I still don't know what's failing, building the app, building the sw or running the app build?
@userquin running the dev mode with plugin-react is not working, the service worker would be invalid, you can try my reproduction repo
@nodegin you need to split your library, I've done these changes:
- add
sw-stuff.ts
in your library, exporting onlytest
- re-export all sw stuff on index.ts:
export * from ./sw-stuff
- add
"@repro/sw-library": ["libs/library/src/sw-stuff.ts"]
to paths intsconfig.base.json
- add
@vitejs/react
as dev dependency topackage.json
:"@vitejs/plugin-react": "^3.1.0",
- move
vite-pwa-plugin
to devDependencies - add
navigateFallback: '/'
todevOptions
(you should also add it toinjectManifest
entry in pwa plugin options) adding this code to the sw:
/// <reference lib="webworker" />
/// <reference types="vite/client" />
import { clientsClaim, setCacheNameDetails } from 'workbox-core';
import {createHandlerBoundToURL, precacheAndRoute} from 'workbox-precaching';
import { NavigationRoute, registerRoute } from 'workbox-routing'
import {test} from '@repro/sw-library';
import { version } from '../../../package.json';
// ServiceWorkerGlobalScope is a type from the workbox-precaching module
declare const self: Window & ServiceWorkerGlobalScope;
setCacheNameDetails({
prefix: test,
suffix: version,
});
// Tells the Service Worker to skip the waiting state and become active.
self.skipWaiting();
// Will make the Service Worker control the all clients right away
// (even if they're controlling other tabs or windows). Without this,
// we could be seeing different versions in different tabs or windows.
clientsClaim();
let allowlist: undefined | RegExp[]
if (import.meta.env.DEV)
allowlist = [/^\/$/]
precacheAndRoute([...self.__WB_MANIFEST]);
// to allow work offline
registerRoute(new NavigationRoute(
createHandlerBoundToURL('/'),
{ allowlist },
))