-
-
Notifications
You must be signed in to change notification settings - Fork 210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve imports when bundling #35
Comments
That gives me this error when building:
The error message makes kind of sense since my service worker file is not in public but rather in a sub directory of The docs say I'd need to configure that top level when using |
yes, I remove the comment, you have to deal with workbox, the error is on workbox side not in VitePWA... |
Hi again, I have it working, I ask @antfu and waiting its response: // see below: just change imports by assignments
// import { cacheNames } from 'workbox-core'
// import { registerRoute, setCatchHandler, setDefaultHandler } from 'workbox-routing'
// import { CacheableResponsePlugin } from 'workbox-cacheable-response'
// import {
// NetworkFirst,
// StaleWhileRevalidate,
// NetworkOnly,
// } from 'workbox-strategies'
// import { ExpirationPlugin } from 'workbox-expiration'
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.1.1/workbox-sw.js')
// Note: Ignore the error that Glitch raises about workbox being undefined.
workbox.setConfig({
debug: true,
})
// To avoid async issues, we load strategies before we call it in the event listener
workbox.loadModule('workbox-core')
workbox.loadModule('workbox-routing')
workbox.loadModule('workbox-cacheable-response')
workbox.loadModule('workbox-strategies')
workbox.loadModule('workbox-expiration')
const cacheNames = workbox.core.cacheNames
const { registerRoute, setCatchHandler, setDefaultHandler } = workbox.routing
const { CacheableResponsePlugin } = workbox.cacheableResponse
const {
NetworkFirst,
StaleWhileRevalidate,
NetworkOnly,
} = workbox.strategies
const { ExpirationPlugin } = workbox.expiration
const cacheName = cacheNames.runtime |
The problem is that the sw.js is sent to the client, but this script cannot be a module, you need to transform it or use the approach using https://developers.google.com/web/tools/workbox/modules/workbox-sw |
I have found this bug: https://bugs.chromium.org/p/chromium/issues/detail?id=824647 We cannot use esmodules yet on service workers: once implemented, we can use it using if('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js', { scope: '/', type: 'module' })
})
} The broswer fails to load the sw with: |
@userquin how would I go about transforming the SW? I actually thought this is what this plugin would do. I knew about the module type when registering a service worker, it's just not something I would do for a production app given the lack of browser support at the moment. |
@kolaente Yeah, I was talking with @antfu and there is a pending branch here (bundle-sw). Anyway, in the docs, it is marked as You need to transform it manually or programatically. I'm working on You can use getManifest from workbox to generate the manifest ( |
@kolaente You can see there some implementations, for example see this using workbox-v4 and look into package.json:
I use second approach:
const swSrc = resolve(__dirname, options.swDest)
// extract workbox libraries
const workboxDirectoryName = await copyWorkboxLibraries(resolve(options.outDir))
// read template
const content = await fs.readFile(resolve(__dirname, 'client/build/networkfirst.mjs'), 'utf-8')
// configure workbox template
const result = content
.replace('__SW_WS__', `${options.base}workbox-sw/index.mjs`)
.replace('__SW_IMPORT_SCRIPTS__', `${slash(join(options.base, workboxDirectoryName, '/workbox-sw.js'))}`)
.replace('__SW_MODULE_PATH_PREFIX__', `${slash(join(options.base, workboxDirectoryName, '/'))}`)
.replace('__SW_DEBUG__', options.mode === 'production' ? 'false' : 'true')
.replace('__SW_INDEX_HTML__', index)
await fs.writeFile(swSrc, result, {
encoding: 'utf-8',
})
const swSrc = resolve(__dirname, options.swDest)
// inject manifest
await injectManifest({
swSrc,
swDest: swSrc, // this will not fail since there is an injectionPoint
injectionPoint: 'self.__WB_MANIFEST',
globDirectory,
additionalManifestEntries,
dontCacheBustURLsMatching,
globFollow,
globIgnores,
globPatterns,
globStrict,
manifestTransforms,
maximumFileSizeToCacheInBytes,
modifyURLPrefix,
templatedURLs,
}) Here a snippet of my /* eslint-disable comma-dangle */
// @ts-ignore
importScripts('__SW_IMPORT_SCRIPTS__')
// @ts-ignore
declare let self: ServiceWorkerGlobalScope
declare let workbox: any
// Note: Ignore the error that Glitch raises about workbox being undefined.
workbox.setConfig({
debug: JSON.parse('__SW_DEBUG__') === true,
modulePathPrefix: '__SW_MODULE_PATH_PREFIX__',
})
// To avoid async issues, we load strategies before we call it in the event listener
workbox.loadModule('workbox-core')
workbox.loadModule('workbox-routing')
workbox.loadModule('workbox-cacheable-response')
workbox.loadModule('workbox-strategies')
workbox.loadModule('workbox-expiration')
const cacheNames = workbox.core.cacheNames
const { registerRoute, setCatchHandler, setDefaultHandler } = workbox.routing
const { CacheableResponsePlugin } = workbox.cacheableResponse
const {
NetworkFirst,
StaleWhileRevalidate,
NetworkOnly
} = workbox.strategies
const { ExpirationPlugin } = workbox.expiration
// @ts-ignore
const manifest = self.__WB_MANIFEST
...
... with this result: // src/client/build/networkfirst.ts
importScripts("/workbox-v6.1.1/workbox-sw.js");
workbox.setConfig({
debug: JSON.parse("true") === true,
modulePathPrefix: "/workbox-v6.1.1/"
});
workbox.loadModule("workbox-core");
workbox.loadModule("workbox-routing");
workbox.loadModule("workbox-cacheable-response");
workbox.loadModule("workbox-strategies");
workbox.loadModule("workbox-expiration");
var cacheNames = workbox.core.cacheNames;
var {registerRoute, setCatchHandler, setDefaultHandler} = workbox.routing;
var {CacheableResponsePlugin} = workbox.cacheableResponse;
var {
NetworkFirst,
StaleWhileRevalidate,
NetworkOnly
} = workbox.strategies;
var {ExpirationPlugin} = workbox.expiration;
var manifest = [
{"revision":"fa8820bba32afa2ec310297ff3c52601","url":"assets/[name].0718b5f8.js"},
{"revision":"dd6d1382ece531785b016772a7ab1f6a","url":"assets/about.c4a91220.js"},
{"revision":"1b13e9d07bf3590700bb2dfe4f8adc8d","url":"assets/home.379f6d36.js"},
{"revision":"5145da3e9a7f1e16f62028ba40335f70","url":"assets/index.7685bec4.js"},
{"revision":"a760355bef2fd5ded385ccabf84c8de0","url":"assets/index.f3bb671a.css"},
{"revision":"440f26a0e8951f5454d0dae54bee0822","url":"index.html"},
{"revision":"1872c500de691dce40960bb85481de07","url":"registerSW.js"},
...
...
];
...
... |
@hannoeru maybe this will help you for If you need some feedback, just contact me here or on discord... |
@hannoeru I have pushed I'm trying another approach: see https://developers.google.com/web/tools/workbox/modules/workbox-recipes Instead having an awful The result will be more redeable (see import { networkfirst } from 'vite-plugin-pwa/receipts/networkfirst'
networkfirst(self.__WB_MANIFEST, /*options*/{...}) |
Until a more robust solution, I went with bundling service-worker.js after Vite's build.
import { nodeResolve } from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import replace from '@rollup/plugin-replace';
export default {
input: './dist/sw.js',
output: {
dir: 'dist',
format: 'esm'
},
plugins: [
replace({
'process.env.NODE_ENV': JSON.stringify('production'),
'preventAssignment': true
}),
nodeResolve({
browser: true
}),
commonjs(),
babel({
exclude: '**/node_modules/**',
extensions: ['js'],
babelHelpers: 'runtime',
presets: [
[
'@babel/preset-env',
{
corejs: 3,
useBuiltIns: 'entry',
targets: {
'esmodules': true
},
modules: false
}
]
]
}),
terser()
]
};
{
"build": "vite build && rollup -c ./rollup.sw.js "
} |
@userquin The bundle branch looks like a great solution. When do you think this could be used in production? I'd happily beta test it. |
@Mehdi-Hp looks great per se, wondering if that could be integrated more into vite. But I guess then we're back to this plugin again 🙂 |
@hannoeru or @antfu should answer this: when done I will use it on the The idea behind this is to abstract the user from using |
If someone wants to finish bundle-sw branch, feel free to do that! |
I'm playing with web workers and it is really strange: I thought that we cannot use I have a web worker with 128 modules with type script, and testing on a separate project (copy/paste from the original to isolate the logic), using I have both versions working with and without On service workers, right now, we cannot use 'import' statements inside the service worker (in any browser), so we can use the same approach I use for web workers, that is, do not use I'll try to do a simple test... about web worker, I have this:
with service worker, its corresponding code will be: import { precacheAndRoute } from 'workbox-precaching'
precacheAndRoute(self.__WB_MANIFEST) then using this script and running it: "scripts": {
"build": "esno scripts/build.ts"
}
the result is is const worker = new Worker('/parse-file-worker-module.mjs', { type: 'module' }) If we can do this with the |
The test is working, with some manual configuration but at least working, now we need to find a way to do the following, if possible: First, the configuration:
cd examples/vue-basic
pnpm i --save-dev esno tsup workbox-precaching
import { precacheAndRoute } from 'workbox-precaching'
console.log('QUE PASA TRON')
// self.__WB_MANIFEST is default injection point
// @ts-ignore
precacheAndRoute(self.__WB_MANIFEST)
"example:build:sw": "npm -C examples/vue-basic run build-sw",
"example:start:sw": "npm -C examples/vue-basic run start-sw",
"start-sw": "npm run run-build-sw && npm run serve",
"run-build-sw": "cross-env DEBUG=vite-plugin-pwa:* BASE_URL=/ SOURCE_MAP=true SW=true vite build",
"build-sw": "esno scripts/build-sw.ts",
import { UserConfig } from 'vite'
import Vue from '@vitejs/plugin-vue'
import { VitePWA, Options as VitePWAOptions } from 'vite-plugin-pwa'
import replace from '@rollup/plugin-replace'
const pwaConfig: Partial<VitePWAOptions> = {
mode: 'development',
base: '/',
}
if (process.env.SW === 'true') {
pwaConfig.strategies = 'injectManifest'
pwaConfig.injectManifest = {
swSrc: 'sw.js',
}
}
const config: UserConfig = {
// base: process.env.BASE_URL || 'https://github.com/',
build: {
sourcemap: process.env.SOURCE_MAP === 'true',
},
plugins: [
Vue(),
VitePWA(pwaConfig),
replace({
__DATE__: new Date().toISOString(),
}),
],
}
export default config Now build time:
const process = {
env: {
NODE_ENV: 'production',
},
} below: // ../../node_modules/.pnpm/workbox-core@6.1.2/node_modules/workbox-core/_version.js
"use strict";
try {
self["workbox:core:6.1.2"] && _();
} catch (e) {
}
The server will start and you can test it. |
As per the workbox docs, I have this in my service worker file:
However, when I build my app, that part stays the same which results in the service worker not working because browsers can't execute js
import
statements in service workers (at least for now). It fails to execute the service worker with the errorUncaught SyntaxError: Cannot use import statement outside a module
.Not sure if this is an issue with the bundler or my understanding of workbox. All examples use import statements.
Relevant part of my
vite.config.js
:The text was updated successfully, but these errors were encountered: