Workbox: Incompatibility with compression-webpack-plugin in webpack 5

Created on 10 Nov 2020  ·  8Comments  ·  Source: GoogleChrome/workbox

Library Affected:
workbox-webpack-plugin

Browser & Platform:

## System:
 - OS: Linux 4.15 Linux Mint 19.1 (Tessa)
## Binaries:
 - Node: 10.16.0 - /usr/local/bin/node
 - Yarn: 1.22.5 - /usr/bin/yarn
 - npm: 6.9.0 - /usr/local/bin/npm

BUG: Compression happened before __WB_MANIFEST injection
We use the InjectManifest module. After migrating to WebPack version 5, we noticed that the generated service-worker.js file is compressed by workbox-webpack-plugin before the injection of self.WB__MANIFETS happens. We guess that in the previous version, this file was delivered to this plugin after the injection phase, but in the current version, it is delivered after the file creation phase and before the injection, hence the compressed file Is incomplete.

webpack plugins

{
  plugins: [
    new WorkboxPlugin.InjectManifest({
      swSrc: './src/setup/sw.js',
      swDest: 'service-worker.js',
      exclude: [/\.(gz|br)$/],
    }),
    new CompressionPlugin({
      algorithm: 'gzip',
      minRatio: 0.8,
      test: /\.(js|css|html|svg)$/,
   })
  ]
}

package.json

{
  "webpack": "^5.4.0",
  "compression-webpack-plugin": "^6.1.0",
  "workbox-webpack-plugin": "^6.0.0-alpha.3",
}
workbox-webpack-plugin

Most helpful comment

Thanks for pointing this out.

After investigating a bit, changing this line in the compression-webpack-plugin's source from compiler.hooks.compilation.tap to compiler.hooks.thisCompilation.tap seems to resolve the issue, without having to change any of the ordering of the stages.

When the compression plugin hooks into compilation instead of thisCompilation, I see that it's compression logic runs twice—once for the child compilation created by InjectManifest (which results in the compression happening prior to the manifest injection), and then again following the manifest injection (which I think is a no-op, since that swDest file was already compressed). If I switch it to thisCompilation, then the compression only happens once, after the manifest injection has taken place.

I'm going to open an issue with the compression-webpack-plugin folks to investigate further, and see if switching to thisCompilation is the right approach for them to take.

All 8 comments

Thanks for pointing this out.

After investigating a bit, changing this line in the compression-webpack-plugin's source from compiler.hooks.compilation.tap to compiler.hooks.thisCompilation.tap seems to resolve the issue, without having to change any of the ordering of the stages.

When the compression plugin hooks into compilation instead of thisCompilation, I see that it's compression logic runs twice—once for the child compilation created by InjectManifest (which results in the compression happening prior to the manifest injection), and then again following the manifest injection (which I think is a no-op, since that swDest file was already compressed). If I switch it to thisCompilation, then the compression only happens once, after the manifest injection has taken place.

I'm going to open an issue with the compression-webpack-plugin folks to investigate further, and see if switching to thisCompilation is the right approach for them to take.

Thank you @jeffposnick 🙏🏽

This should be fixed by upgrading to compression-webpack-plugin v6.1.1.

@jeffposnick Do you think we can/should use the alpha releases in production environment to take advantage of webpack v5?

We're still likely to make at least one change between the latest alpha and the final v6 release to account for the ordering in which our plugin runs in relation to others (c.f. https://github.com/webpack/webpack/issues/11822#issuecomment-726184972). So it's possible you'd need to make an adjustment to your webpack configuration to account for that breaking change.

The actual code that Workbox generates in your service worker is unlikely to change between now and the v6.0.0 release, though.

I am reopening this, as @alexander-akait & @sokra have pointed out that the current implementation needs to be remediated.

I will fix it on compression-webpack-plugin side, but maybe you need to change stage here too, I don't look at this deeply

@jeffposnick I fixed it https://github.com/webpack-contrib/compression-webpack-plugin/pull/234, but it is very strange, tests passed on linux and macos, but failed on windows:

console.warn
      'D:acompression-webpack-plugincompression-webpack-plugin
      ode_modulesworkbox-precaching/precacheAndRoute.mjs' is imported by C:\Users\RUNNER~1\AppData\Local\Temp\988e796220541bbd29bb0f442f6e0cc5\service-worker.js, but could not be resolved – treating it as an external dependency

      at Object.defaultOnWarn [as onwarn] (node_modules/rollup/dist/shared/rollup.js:34:42)
      at ModuleLoader.handleResolveId (node_modules/rollup/dist/shared/rollup.js:18435:26)
      at node_modules/rollup/dist/shared/rollup.js:18402:22
          at async Promise.all (index 0)
      at ModuleLoader.fetchStaticDependencies (node_modules/rollup/dist/shared/rollup.js:18400:34)
          at async Promise.all (index 0)
      at ModuleLoader.fetchModule (node_modules/rollup/dist/shared/rollup.js:18377:9)
          at async Promise.all (index 0)

Config:

new InjectManifest({
  swSrc: path.resolve(__dirname, "./fixtures/sw.js"),
}).apply(compiler);

I known it is not related to this problem, but I want to notify you

Was this page helpful?
0 / 5 - 0 ratings