workbox
workbox copied to clipboard
Uncaught ReferenceError: regeneratorRuntime is not defined
Library Affected: workbox-webpack-plugin
Browser & Platform: Was found on Chrome v51
Bug: I am using this plugin like so:
new GenerateSW({
babelPresetEnvTargets: ["last 4 versions", "safari >= 7"],
cacheId: 'sw',
cleanupOutdatedCaches: true,
clientsClaim: true,
exclude: [/\.map$/, /stats\.json$/],
inlineWorkboxRuntime: true,
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com.*/,
handler: 'StaleWhileRevalidate',
},
],
skipWaiting: true,
sourcemap: false,
swDest: 'sw.js',
}),
This error is coming through into the browser console:
Uncaught ReferenceError: regeneratorRuntime is not defined
As a workaround, I'd suggest omitting babelPresetEnvTargets
from your configuration, and explicitly running your babel
configuration against your generated service worker file after the webpack
compilation completes.
Alternatively, you can switch to InjectManifest
mode and webpack
will compile your swSrc
file using the options you have configured for your main compilation, including the babel
config.
(FWIW, the earliest version of Safari to support service workers is Safari 11.1, so targeting safari >= 7
in your transpilation might not be what you want.)
Could you please explain why removing babelPresetEnvTargets
and transpiling sw.js
after webpack has created it are different from each other - they appear to be doing the exact same thing?
If you run your own babel
transpilation process after Workbox generates a service worker, you have control over adding in additional configuration options, like including the https://babeljs.io/docs/en/babel-plugin-transform-runtime or https://babeljs.io/docs/en/babel-plugin-transform-regenerator plugins for compatibility with browsers that support service workers but don't support other modern JavaScript features.
As per #2506, I'm surprised that adding this babelPresetEnvTargets
property with those values would prevent it from working in Chrome 81 (Desktop) because this browser is modern and supports Service Workers and generators?
I'm not quite understanding what is not happening during the transpilation process that I need to add in to make it work.
Is it a case that this workbox-webpack-plugin
needs to instead use the babel config file as a whole, rather than just have its presets set using babelPresetEnvTargets
?
It also feels like i just need to be importing regenerator-runtime/runtime
somewhere, but there is no easy way to do this - can this plugin simply include it by default?
When you set babelPresetEnvTargets
, there's a single transpilation performed, and a single service worker file output. You can think of it as meeting the requirements of the "lowest common denominator" based on your babelPresetEnvTargets
configuration.
If your babelPresetEnvTargets
configuration includes a browser that doesn't have support for generators, then the single service worker file that's output will include code that references regeneratorRuntime
. If regeneratorRuntime
isn't available (which it wouldn't be if you're using a transpilation configured by Workbox), then the code will fail to run on any browser—it's failing on modern browsers that have generator support because there's now a dependency on the missing regeneratorRuntime
.
As suggested, you can either perform your own transpilation after Workbox produces a service worker file, and in that transpilation, add in support for the regeneratorRuntime
(check the babel
documentation for exactly how you'd do that). Alternatively, you could ensure that you set Workbox's babelPresetEnvTargets
to only include browsers that have generator support, and the service worker file that Workbox creates should work across all of those browsers.
I'm leaving this issue open because it's definitely something that we could help prevent from happening—I think Workbox could conditionally add the regeneratorRuntime
to the service workers it transpiles without incurring a larger bundle size when it's not needed. But what I'm offering in the meantime is some workarounds that should address your issue.
I have now switched to the InjectManifest method:
new InjectManifest({
dontCacheBustURLsMatching: /^\/static\/modern\/(components\/([a-z0-9-]+\/)*|scenes\/([a-z0-9-]+\/)*)?[0-9a-z-]+\.[0-9a-z-]+\.js$/,
exclude: [/\.map$/, /stats\.json$/],
swDest: 'sw.js',
swSrc: './src/utilities/service-worker/sw-source.js',
}),
Our webpack babel config states:
"last 4 versions", "safari >= 7"
But when I run es-check
against this (checking for es5) it fails with:
· erroring file: ./dist/static/legacy/sw.js · error: SyntaxError: The keyword 'const' is reserved (1:1414)
Am I correct in thinking that Webpack should have transpiled sw-source.js
and sw.js
?
When I then run the following command on the sw.js
file, it transpiles to es5 (note that prod-client-legacy also states last 4 versions", "safari >= 7):
shell.exec(
'./node_modules/.bin/babel --config-file ../../babel.config.js --env-name "prod-client-legacy" ./dist/static/legacy/sw.js --out-file ./dist/static/legacy/sw.js'
);
InjectManifest
mode will create a childCompiler
instance under the hood, and a lot of of the webpack configuration is inherited from the main, "parent" compilation. I've heard that the plugins
from the parent compilation aren't applied consistently, though, so InjectManifest
supports a webpackCompilationPlugins
option that you could use to add in, e.g., your plugin to perform the transpilation:
https://github.com/GoogleChrome/workbox/blob/04ba6442c466d2e8197fe586672143d201af3a61/packages/workbox-webpack-plugin/src/inject-manifest.js#L118-L119
Alternatively, you can switch to
InjectManifest
mode andwebpack
will compile yourswSrc
file using the options you have configured for your main compilation, including thebabel
config.
Is this true? I can't get passed the error in the OP with using what you've suggested in this thread. Here's my stuff: https://github.com/JeremiGendron/react-typescript-pwa-poc/tree/master/lib/frontend
Check config/webpack.config.js, run yarn build, open with serve and see error.
(I'm aware my service worker is not very well formed, but shouldn't be getting this error anyway)
LMK if I missed something
EDIT: almost certain it's just not being run through babel? Would make sense since it's a loader and not a plugin.
@jeffposnick I'm trying to utilize the babel loader configuration from within my webpack config file. Given this is a loader and not a plugin, should this be expected to work?
On my end, seems like it's a general misconfiguration issue. Using async functions at all (which were previously only in my SW entry) causes this error to throw. So it's a problem with by webpack/babel config and not the plugin.
EDIT: adding the following to my .babelrc fixed the thing:
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": false,
"helpers": true,
"regenerator": true, // important line
"useESModules": false
}
]
]
@JeremiGendron Isn't "regenerator": true
the default though - how could this have made the difference?
https://babeljs.io/docs/en/babel-plugin-transform-runtime
Alternatively, you can switch to InjectManifest mode and webpack will compile your swSrc file using the options you have configured for your main compilation, including the babel config.
I am using injectManifest and facing the below issue.
service-worker.js:158 Uncaught (in promise) TypeError: Cannot read property 'async' of undefined
at Object.navigationHandler [as handle] (service-worker.js:158)
at Router.handleRequest (Router.js:196)
at eval (Router.js:63)
Webpack plugin
new InjectManifest({
swSrc: './src/service-worker.js',
swDest: 'service-worker.js',
})
Relevant service worker code
navigationPreload.enable();
const networkOnly = new NetworkOnly();
const navigationHandler = async (params) => {
try {
// Attempt a network request.
return await networkOnly.handle(params);
} catch (error) {
// If it fails, return the cached HTML.
return caches.match(FALLBACK_HTML_URL, {
cacheName: CACHE_NAME,
});
}
};
// Register this strategy to handle all navigations.
registerRoute(
new NavigationRoute(navigationHandler)
);
this code from workbox documentation and I am not able to run it.
An alternative workaround is to ignore babel or use an alternative babel.config
Example (for service worker file sw.js
)
webpack.config.js
// normal babel config (with preset env)
const babelLoader= {
loader: 'babel-loader',
options: {configFile: path.resolve(__dirname, "./babel.config.js")}
}
// babel config for work box (without preset env)
const workboxBabelLoader = {
loader: 'babel-loader',
options: {configFile: path.resolve(__dirname, "./babel.workbox.config.js")}
}
// Normal Babel Rule
const babelRule = {
test: /\.jsx?$/,
// ignore anything with workbox and sw.js within path
exclude: /(workbox|sw.js)/,
use: [babelLoader]
};
// WorkBox Babel Rule
const workboxBabelRule = {
// may need to tweak this using a function instead of just regex
test: /(workbox|sw.js)/,
use: [workboxBabelLoader]
}
Use workboxBabelRule
and babelRule
export default = {
...
module: {
rules: {
....
// add the rules here
}
}
}
I got the same error when using workbox-webpack-plugin 5.1.4
and webpack 5.2.0
with InjectManifest()
. I have fixed the problem by setting the target browser in my .babelrc
to a more recent browser (Chrome 58). I'd be interested to know what the minimum value I can set this to so as to cover the greatest number of browsers.
I'm a bit confused by the answer given above about regeneratorRuntime not being available after compilation:
If regeneratorRuntime isn't available (which it wouldn't be if you're using a transpilation configured by Workbox)
since regeneratorRuntime is a dependency of both Babel and of Workbox?
If I understand correctly, regeneratorRuntime is a kind of polyfill for generator functions, so why would a compilation process targeting older browsers leave it out?
Any news on this? I had this issue using Next.js and Next-PWA which uses Workbox. Because it's a third-party lib (next-pwa) that uses another third-party lib (workbox) inside a framework with its own webpack/babel setup (next.js) it's really crazy to go and try to understand why the bug appears and where and how it should be handled. I mean, this issue creates a domino effect for the third party libs and it should be handled somehow in Workbox either by including the polyfill and/or documenting this clearly so that everybody must know about it and handle it.
When you set
babelPresetEnvTargets
... Alternatively, you could ensure that you set Workbox'sbabelPresetEnvTargets
to only include browsers that have generator support, and the service worker file that Workbox creates should work across all of those browsers.
Where would that setting be, precisely?
I'm trying to use the WorkboxPlugin.InjectManifest webpack 5 plugin and I can't get past this error. I just need to make this go away. Where exactly is the setting for " Workbox's babelPresetEnvTargets
" ? What do I set it to in order to remove the error? I need to know what the incantation is, and where to put it. Anyone?
Hey all. Sorry for not updating this for a while.
@phil-w, the babelPresetEnvTargets
setting is available when you're using the GenerateSW
plugin.
If you're using the InjectManifest
plugin, then any Babel plugins from the parent compilation is applied to the child compilation that outputs your service worker.
@mycolaos, if you could point me to a GitHub project or some other code archive that includes a full setup which reproduces the problem you're seeing, I'll dive into it and tell you what needs to be configured where, and potentially see how those changes could be upstreamed to the source projects.
In general, one option that wasn't mentioned yet is that if you want to pull in the regenerator runtime into your service worker, it can be explicitly loaded from, e.g., the unpkg CDN (or using a local copy that you maintain). The mechanism for loading it varies depending on which webpack plugin you're using:
-
GenerateSW
: addimportScripts: ['https://unpkg.com/[email protected]/runtime.js']
to your Workbox configuration. -
InjectManifest
: addimportScripts('https://unpkg.com/[email protected]/runtime.js');
to the top of yourswSrc
file.
Again, you can replace those URLs with a copy of the regenerator-runtime
code served from a local URL if you'd rather not rely on a CDN.