Workbox: Error: Can't resolve 'workbox-precaching/createHandlerForURL' [webpack 4]

Created on 16 Sep 2020  路  5Comments  路  Source: GoogleChrome/workbox

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..

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

All 5 comments

@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 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 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.

Was this page helpful?
0 / 5 - 0 ratings