webpackworkboxworkbox-webpack-plugin

workbox-webpack-plugin's InjectManifest only works with `devtoolModuleFilenameTemplate: 'file:///[absolute-resource-path]'`


I want to use workbox-webpack-plugin to include my own service worker. However, using InjectManifest doesn't work unless I use the output option devToolModuleFilenameTemplate. It seems library: "[name]" is the failing configuration in combination with the workbox-webpack-plugin. Why do I have to set devToolModuleFilenameTemplate when using library: "[name]" option?

Minimal project to reproduce the error

https://gitlab.com/d.kuhnke/workbox-webpack-plugin-problem

NPM depedencies

  "devDependencies": {
    "ts-loader": "^8.1.0",
    "webpack": "^5.31.2",
    "webpack-cli": "^4.6.0",
    "webpack-merge": "^5.7.3",
    "workbox-webpack-plugin": "^6.1.2"
  }

Failing config (webpack.common.js / webpack.prod.js)

const path = require('path');
const { InjectManifest } = require('workbox-webpack-plugin');

module.exports = {
    entry: {
        Test: './src/index.js'
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist'),
        library: "[name]", // this is the line which makes problems
        clean: true,
    },
    plugins: [
        new InjectManifest({
            swSrc: './src/test-offline-worker.js'
        }),
    ],
    watchOptions: {
        ignored: ['dist', '**/node_modules']
    },
    mode: 'development',
    devtool: 'source-map', // production source map
};

Working config (webpack.dev.js)

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

const path = require('path');

module.exports = merge(common, {
    output: { // InjectManifest only works with this setting
        devtoolModuleFilenameTemplate: 'file:///[absolute-resource-path]'  // map to source with absolute file path not webpack:// protocol
    },
});

Error message of failing config

PS C:\Users\USERNAME\dev\git\personal\webpack-problem> npm run build:prod

> webpack-problem@1.0.0 build:prod
> webpack --config webpack.prod.js

asset Test.bundle.js 618 bytes [compared for emit] (name: Test) 1 related asset
asset test-offline-worker.js 300 bytes [emitted] 1 related asset
./src/index.js 1 bytes [built] [code generated]

ERROR in Invalid URL: webpack://[name]/./src/test-offline-worker.js

webpack 5.31.2 compiled with 1 error in 104 ms
npm ERR! code 1
npm ERR! path C:\Users\USERNAME\dev\git\personal\webpack-problem
npm ERR! command failed
npm ERR! command C:\Windows\system32\cmd.exe /d /s /c webpack --config webpack.prod.js

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\USERNAME\scoop\persist\nodejs\cache\_logs\2021-04-12T14_28_43_806Z-debug.log

Update (2021-05-18)

As Jeff Posnick explained the problem is missing replacement of the placeholder string [name]. A solution / workaround is to set the output.devtoolNamespace to a constant value as described here.


Solution

  • There are a couple of things at play here.

    First, webpack's sourcemap generator doesn't seem to work properly when output.library is set to '[name]', independent of anything having to do with Workbox:

    If you comment out the InjectManifest plugin from your "failing config" example, then it will produce a sourcemap that contains:

    {"sources":["webpack://[name]/./src/index.js"], ...}

    which I don't believe is valid either. It doesn't trigger a compilation error, but it's not the expected output. That would be an issue to raise with the webpack team.

    Second, I can't think of a valid use case for when you'd add the InjectManifest plugin to a compilation that produced library output. The service worker created with InjectManfest is supposed to precache the output of a given compilation, but at the same time, the output of a compilation with output.library set is meant to be a reusable library that others will pull in from their own codebase, i.e. something suitable for releasing on npm. It does not make sense to ship a service worker alongside that library, or anything like that.