Webpack-encore: Problems integrating service workers with the workbox plugin.

Created on 30 Apr 2018  路  2Comments  路  Source: symfony/webpack-encore

I am working to upgrade an older symfony site (recently upgraded from 2.3 -> 3.4) into a PWA. I have refactored the site into using Encore for asset management and am now attempting to get a service worker registered and functioning with workbox.

The public path in webpack.config is set to a relative path, which could be the issue. When I run "yarn encore [env]" I get a warning to start the path with "/" but, if I do this, my localhost server looks for the assets generated at the server root, rather than the web root of the site. If I set this to "build" the assets are handled perfectly, but it seems the service workers are not.

The workbox plugin is using the public path to locate the precache-manifest and the files to cache relative to the service-worker.js file's location. I have scoured the workbox config docs and have experimented with every option that seemed relevant to force it to find the files (didn't work, obviously).

I am going to attempt to integrate the offline-plugin instead after reading all relevant open/closed issues trying to figure this out. I'd prefer to use workbox though.

Any suggestions are super appreciated.

webpack.conifg.js (relevant parts of):

const Encore = require('@symfony/webpack-encore');
const WorkboxPlugin = require('workbox-webpack-plugin');

Encore
    // the project directory where all compiled assets will be stored
    .setOutputPath('web/build/')
    // the public path used by the web server to access the previous directory
    .setPublicPath('build')
    // allow legacy applications to use $/jQuery as an app variable 
    // Note: Doesn't work if js not processed through webpack
    .autoProvidejQuery()
    // enable source maps during development
    .enableSourceMaps(!Encore.isProduction())
    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()
    // show OS notifications when builds finish/fail
    .enableBuildNotifications()
    // filenames include a hash that changes whenever the file contents change
    .enableVersioning()
    // you can use this method to provide other common global variables,
    // such as '_' for the 'underscore' library
    .autoProvideVariables({
        agGrid: 'ag-grid'
    })
    .addPlugin(
        new WorkboxPlugin.GenerateSW({
            // these options encourage the ServiceWorkers to get in there fast 
            // and not allow any straggling "old" SWs to hang around
            clientsClaim: true,
            skipWaiting: true,
            importsDirectory: 'sw/'
    }))

build/manifest.json:

{
  "build/app.js": "build/app.909ece53.js",
  "build/app.css": "build/app.660f3f02.css",
  "build/libs.js": "build/libs.29162d72.js",
}

build/service-worker.js:

importScripts(
  "build/precache-manifest.55e3eef33cfaaa7431419f43032726c5.js"
);

Most helpful comment

Hey @rnbwspctrm!

Yes, hopefully I can help - let me try :). Or at least, I'll give you some hints!

First, yea, Encore doesn't work well with a relative public path. Actually, it's not Encore, it's just that using relative paths is much harder / doesn't work through all parts of Webpack. It's something we're checking into, but it's really complex. In short, your setPublicPath() really should be the absolute public path to your assets. So, in your case, I would use .setPublicPath('/build'). However, it sounds like /build is not actually your web's root? Are you under a subdirectory? If so, you should actually include this in your public path - e.g. /subdirectory/build. Btw, getting the public path correct is also important if you ever do any "code splitting", as it must be correct for Webpack to complete the AJAX calls for the async "chunks".

If you do use /subdirectory/build as your public path, then your templates will need to look like asset('subdirectory/build/main.js'). But, you can also control that by calling .setManifestKeyPrefix('/build'). That will reset the keys in manifest.json, so you can continue saying things like asset('build/main.js')

LONG way of saying that your most likely cause is indeed the relative paths. But, if this doesn't help, exactly what is the problem with the worker? I mean, you mentioned that build/service-worker.js looks like this:

importScripts(
  "build/precache-manifest.55e3eef33cfaaa7431419f43032726c5.js"
);

Is that not the correct path?

Cheers!

All 2 comments

Hey @rnbwspctrm!

Yes, hopefully I can help - let me try :). Or at least, I'll give you some hints!

First, yea, Encore doesn't work well with a relative public path. Actually, it's not Encore, it's just that using relative paths is much harder / doesn't work through all parts of Webpack. It's something we're checking into, but it's really complex. In short, your setPublicPath() really should be the absolute public path to your assets. So, in your case, I would use .setPublicPath('/build'). However, it sounds like /build is not actually your web's root? Are you under a subdirectory? If so, you should actually include this in your public path - e.g. /subdirectory/build. Btw, getting the public path correct is also important if you ever do any "code splitting", as it must be correct for Webpack to complete the AJAX calls for the async "chunks".

If you do use /subdirectory/build as your public path, then your templates will need to look like asset('subdirectory/build/main.js'). But, you can also control that by calling .setManifestKeyPrefix('/build'). That will reset the keys in manifest.json, so you can continue saying things like asset('build/main.js')

LONG way of saying that your most likely cause is indeed the relative paths. But, if this doesn't help, exactly what is the problem with the worker? I mean, you mentioned that build/service-worker.js looks like this:

importScripts(
  "build/precache-manifest.55e3eef33cfaaa7431419f43032726c5.js"
);

Is that not the correct path?

Cheers!

Hi!

The project does live in a subdirectory. I have updated the webpack.config and my assets are loading perfectly with the absolute path.

The problem with the service-worker.js was that it was importing relative to it's location, also in build. So the server was looking for the precache-manifest at 'build/build/precache-manifest.[hash].js'.

With these changes to the config, everything works with workbox! FWIW, I had gotten a functioning service worker using the offline plugin, as there is a config option that sets the public path the plugin will use explicitly.

I'd much rather use workbox, so thank you for your help! =}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

iammichiel picture iammichiel  路  3Comments

weaverryan picture weaverryan  路  4Comments

pensiero picture pensiero  路  4Comments

Aerendir picture Aerendir  路  4Comments

rebangm picture rebangm  路  4Comments