Library Affected:
workbox-precaching/createHandlerForURL
Browser & Platform:
All browsers for me
Issue or Feature Request Description:
I麓m triying to create cache-first service worker config to save some assets used in my project
Following this example https://gist.github.com/jeffposnick/fc761c06856fa10dbf93e62ce7c4bd57 i麓m getting the following error ERROR in ./service-worker.js Module not found: Error: Can't resolve 'workbox-precaching/createHandlerForURL' in 'C:\xampp\htdocs\my-project'
I麓m using mainly using webpack 4 in my project but I see that I have the lastest workbox 5 installed, this is correct?
Or I need to use workbox 4 dependencies?
When reporting bugs, please include relevant JavaScript Console logs and links to public URLs at which the issue could be reproduced.
This is my webpack 4 config
webpack.config.prod.js
//webpack
const path = require('path');
const webpack = require('webpack');
const RemovePlugin = require('remove-files-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const HTMLInlineCSSWebpackPlugin = require('html-inline-css-webpack-plugin').default;
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const { InjectManifest } = require('workbox-webpack-plugin');
//filesystem paths
const OUTPUT_PATH = path.resolve(__dirname, 'public/');
const WEBPACK_PATH = path.resolve(__dirname, 'assets', 'js', 'webpack');
const VIEWS_PATH = path.resolve(__dirname, 'modulos', 'views');
const SERVICE_WORKER_PATH = path.resolve(__dirname);
const PUBLIC_PATH = 'public/';
module.exports = merge(common,{
mode: 'production',
devtool: 'none',
output: {
filename: '[name].bundle.[chunkhash].js',
chunkFilename: 'lazy-modules/[name].bundle.[chunkhash].js', //used for lazy-modules
path: OUTPUT_PATH,
publicPath: PUBLIC_PATH
},
plugins:[
new RemovePlugin({
after: {
include: [
`${WEBPACK_PATH}/dist`
]
}
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
new HtmlWebpackPlugin({
filename: `${VIEWS_PATH}/index.php`,
template: `${VIEWS_PATH}/index.php`,
chunks: ['index', 'vendor', 'lib']
}),
new InjectManifest({
swSrc: `${SERVICE_WORKER_PATH}/service-worker.js`,
swDest: 'service-worker.js',
// Any other config if needed.
}),
new ScriptExtHtmlWebpackPlugin({
sync: 'important',
defaultAttribute: 'defer'
}),
//mini-css
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
},
canPrint: true
}),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// all options are optional
filename: 'css/[name].style.bundle.[contenthash].css',
chunkFilename: 'lazy-modules/[name].[contenthash].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
new HTMLInlineCSSWebpackPlugin({
filter(fileName) {
return !fileName.includes('lazy-modules');
},
})],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
test: /\.js(\?.*)?$/i,
terserOptions: {
output: {
comments: false,
},
},
extractComments: false,
}),
],
}
});
webpack.comon.js
//webpack
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const RemovePlugin = require('remove-files-webpack-plugin');
//filesystem paths
const PUBLIC_PATH = 'public/';
const WEBPACK_PATH = path.resolve(__dirname, 'assets', 'js', 'webpack');
const SYSTEM_PATH = path.resolve(__dirname, 'modulos', 'views', 'system');
module.exports = merge(common,{
mode: 'development',
// devtool: 'source-map',
node: {
fs: 'empty'
},
devServer: {
port: 5050,
contentBase: WEBPACK_PATH
},
plugins: [
new RemovePlugin({
after: {
include: [
PUBLIC_PATH
]
}
}),
new webpack.WatchIgnorePlugin([
/\.php$/,
/\.html$/,
]),
new MiniCssExtractPlugin()
]
});
service-worker.js
// Add any other logic here as needed.
import { CacheableResponsePlugin } from 'workbox-cacheable-response/CacheableResponsePlugin';
import { CacheFirst } from 'workbox-strategies/CacheFirst';
import { createHandlerForURL } from 'workbox-precaching/createHandlerForURL';
import { ExpirationPlugin } from 'workbox-expiration/ExpirationPlugin';
import { NavigationRoute } from 'workbox-routing/NavigationRoute';
import { precacheAndRoute } from 'workbox-precaching/precacheAndRoute';
import { registerRoute } from 'workbox-routing/registerRoute';
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
new NavigationRoute(createHandlerForURL('index.html'))
);
registerRoute(/^https:\/\/m.media-amazon.com\/images/, new CacheFirst({
cacheName: 'amazon-images',
matchOptions: {
ignoreVary: true,
},
plugins: [new ExpirationPlugin({
maxEntries: 500,
maxAgeSeconds: 63072e3,
purgeOnQuotaError: true,
}), new CacheableResponsePlugin({
statuses: [0, 200]
})]
}));
registerRoute(/^https:\/\/res.cloudinary.com\/my-project\/image/, new CacheFirst({
cacheName: 'product-images',
matchOptions: {
ignoreVary: true,
},
plugins: [new ExpirationPlugin({
maxEntries: 500,
maxAgeSeconds: 63072e3,
purgeOnQuotaError: true,
}), new CacheableResponsePlugin({
statuses: [0, 200]
})]
}));
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
package.json
{
"name": "my-project",
"version": "2.6.0",
"description": "my-projectwebpack 4 project",
"main": "index.js",
"scripts": {
"prod": "webpack --config webpack.prod.js",
},
"repository": {
"type": "git",
"url": "https://github.com/AlonsoK28/my-project"
},
"author": "alonsokyoyama",
"license": "ISC",
"dependencies": {
"@haikel/min-captcha": "^1.4.1",
"date-fns": "^2.16.1",
"jquery": "3.4.1",
"lazysizes": "^5.2.2",
"remove-files-webpack-plugin": "^1.4.0",
"rxjs": "^6.5.5",
"script-ext-html-webpack-plugin": "^2.1.4",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^4.2.2",
"workbox-cacheable-response": "^5.1.4",
"workbox-expiration": "^5.1.4",
"workbox-precaching": "^5.1.4",
"workbox-routing": "^5.1.4",
"workbox-strategies": "^5.1.4",
"workbox-webpack-plugin": "^5.1.4"
},
"engines": {
"node": ">=10.0.0 <=10.20.0"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.0",
"@fortawesome/fontawesome-free": "^5.13.0",
"@fortawesome/fontawesome-svg-core": "^1.2.28",
"@fortawesome/free-brands-svg-icons": "^5.13.0",
"@fortawesome/free-regular-svg-icons": "^5.13.0",
"@fortawesome/free-solid-svg-icons": "^5.13.0",
"babel-loader": "^8.1.0",
"babel-plugin-transform-imports": "^2.0.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.5.0",
"expose-loader": "^0.7.5",
"file-loader": "^4.3.0",
"html-inline-css-webpack-plugin": "^1.8.0",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^5.1.0",
"json-loader": "^0.5.7",
"mini-css-extract-plugin": "^0.8.2",
"modernizr": "^3.9.1",
"modernizr-loader": "^1.0.1",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"terser-webpack-plugin": "^4.2.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.42.1",
"webpack-bundle-analyzer": "^3.7.0",
"webpack-modernizr-loader": "^5.0.0"
}
}
index.js
/**
* @author Carlos Alonso Casales Ortega <[email protected]>
* webpack 4 'locahost/my-project' module.
* @module index
*/
import { lazyModulesSelectors as selectors, amazonAdTypes as types } from 'libreriaGeneral';
import { backToTop, unveilCommon } from 'common';
//fontawesome
import { library, dom } from '@fortawesome/fontawesome-svg-core';
import { faAngleLeft, faAngleRight, faTrophy, faCertificate } from '@fortawesome/free-solid-svg-icons'; //fa
import { faPaperPlane as farPaperPlane} from '@fortawesome/free-regular-svg-icons'; //far
import fontAwesomeComun from 'fontawesome.5.common';
//css
import '../../css/lib/responsive_bootstrap_carousel_mega_min.css';
import '../../css/lib/animate.min.css';
import '@serviceworker/service-worker.js'; //<-- service worker is imported here to my entry module
//other code..
@AlonsoK28 Hi! First. In latest version of workbox createHandlerForURL renamed to createHandlerBoundToURL.
Than check this.
Service worker must be a separate file and you need register this file as service worker. (Basically injectManifest create your service-worker file and you just need correct register him)
Thanks for answering the question, @TheForsakenSpirit!
There is more info on the new method name at https://developers.google.com/web/tools/workbox/guides/migrations/migrate-from-v4#navigation_route_changes
@AlonsoK28 Hi! First. In latest version of workbox
createHandlerForURLrenamed tocreateHandlerBoundToURL.Than check this.
Service worker must be a separate file and you need register this file as service worker. (BasicallyinjectManifestcreate your service-worker file and you just need correct register him)
Thanks for your answer
Im still triying to configure the SW on my project
Ive added the following
Register the SW
if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('service-worker.js');
});
}
service-worker.js changed function name to createHandlerBoundToURL
import { CacheableResponsePlugin } from 'workbox-cacheable-response/CacheableResponsePlugin';
import { CacheFirst } from 'workbox-strategies/CacheFirst';
import { createHandlerBoundToURL } from 'workbox-precaching/createHandlerBoundToURL'; //<--renamed from createHandlerForURL
import { ExpirationPlugin } from 'workbox-expiration/ExpirationPlugin';
import { NavigationRoute } from 'workbox-routing/NavigationRoute';
import { precacheAndRoute } from 'workbox-precaching/precacheAndRoute';
import { registerRoute } from 'workbox-routing/registerRoute';
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
new NavigationRoute(createHandlerBoundToURL('index')) //<--renamed from createHandlerForURL
);
But I got this error when compile to production
Error in console
**Uncaught (in promise) TypeError: Failed to register a ServiceWorker for scope ('http://localhost/my-project/') with script ('http://localhost/my-project/service-worker.js'): ServiceWorker script evaluation failed**
and my service-worker.js is this
// Add any other logic here as needed.
import { CacheableResponsePlugin } from 'workbox-cacheable-response/CacheableResponsePlugin';
import { CacheFirst } from 'workbox-strategies/CacheFirst';
import { createHandlerBoundToURL } from 'workbox-precaching/createHandlerBoundToURL';
import { ExpirationPlugin } from 'workbox-expiration/ExpirationPlugin';
import { NavigationRoute } from 'workbox-routing/NavigationRoute';
import { precacheAndRoute } from 'workbox-precaching/precacheAndRoute';
import { registerRoute } from 'workbox-routing/registerRoute';
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
new NavigationRoute(createHandlerBoundToURL('index'))
);
registerRoute(/^https:\/\/m.media-amazon.com\/images/, new CacheFirst({
cacheName: 'amazon-images',
matchOptions: {
ignoreVary: true,
},
plugins: [new ExpirationPlugin({
maxEntries: 500,
maxAgeSeconds: 63072e3,
purgeOnQuotaError: true,
}), new CacheableResponsePlugin({
statuses: [0, 200]
})]
}));
registerRoute(/^https:\/\/res.cloudinary.com\/my-project\/image/, new CacheFirst({
cacheName: 'product-images',
matchOptions: {
ignoreVary: true,
},
plugins: [new ExpirationPlugin({
maxEntries: 500,
maxAgeSeconds: 63072e3,
purgeOnQuotaError: true,
}), new CacheableResponsePlugin({
statuses: [0, 200]
})]
}));
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
Hmm... I don`t see any problems with your code.
@AlonsoK28 Can you try to eval your service worker code to see detailed problem?
I guess there is an problem with compilation and injection point related to different string marks " or ' .
@AlonsoK28, please make sure you're following the steps in https://developers.google.com/web/tools/workbox/guides/using-bundlers to bundle up the service worker code, as the unbundled JS module imports can't be used natively in a service worker.
Most helpful comment
Thanks for answering the question, @TheForsakenSpirit!
There is more info on the new method name at https://developers.google.com/web/tools/workbox/guides/migrations/migrate-from-v4#navigation_route_changes