pulsejet
pulsejet

Reputation: 1223

Angular service worker with webpack (without CLI)

I've a pretty large angular project that is built using webpack (I'm working with Microsoft's template of ASP.NET core). Is there any way I can use @angular/service-worker?

I've already tried adding the package and importing it, but the service worker never gets built. There's no error, but I get nothing. A new CLI project built with the flag works as expected.

Upvotes: 7

Views: 2534

Answers (2)

ambientlight
ambientlight

Reputation: 7332

For non-cli projects built with webpack, you might not need using Angular Service Worker at all. Workbox is nice library for generating service workers which has a decent webpack plugin.

npm install --save-dev workbox-webpack-plugin

webpack.config:

import { GenerateSW } from 'workbox-webpack-plugin'
// const {GenerateSW} = require('workbox-webpack-plugin')

where at default it will generate service worker that precaches your webpack output with

plugins: [
    // other webpack plugins
    new GenerateSW()
]

You can then install this generated service worker after you are bootstrapping your angular application like:

platformBrowserDynamic().bootstrapModule(AppModule).then(() => {

    if( !('serviceWorker' in navigator) ){
        console.warn('Too bad, Service worker is not supported in current browser')
        return
    }

    window.navigator.serviceWorker
        .register(`/service-worker.js`, { scope: '/' })
        .then(registration => console.log(`Service worker registration succeeded`))
        .catch(error => console.log(`Service worker registration failed`))  
})

provided that your server is serving from webpack's publicPath. For more complex scenarios please refer to its docs: workbox-webpack-plugin, however, let me highlight few common scenarios here:

I. Precaching non-webpack assets

If you want to precache assets that are not managed by webpack, use globDirectory and globPatterns options to find them like:

new GenerateSW({
     globDirectory: '.',
     globPatterns: ['assets/**/*.{svg, png}']
})

Resulting glob asset url (which you can find in service-worker.js self.__precacheManifest) will be resolved against glob directory, meaning your server should serve /assets/.

II. Precaching server-generated assets

It's might be common that your index.html is server-generated, in which case you might want to use templatedUrl to specify which routes to precache and how to revision retrieved assets. This is handy to use together with navigateFallback to make sure we gracefully fallback to our index.html when accessing non-precached route.

new GenerateSW({
    globDirectory: '.',
    globPatterns: [],
    templatedUrls: {
        '/': ['templates/Index.html']
    }
    navigateFallback: '/'
})

templateUrl specify the route you want to precache and a glob-pattern to find a resource that will be used to revision the retrieved response from this URL. Make sure you have globDirectory specified, otherwise plugin will fail with confusing error. As mentioned in workbox/issues/763, md5 hashes of files specified will be used to revision retrieved asset, which will be valid as long as /templates/Index.html is not changing. Normally, if you use HtmlWebpackPlugin to inject your bundle (with hash) into Index.html template, service-worker.js precache manifest revision will change as desired.

III. Cache API Responses on runtime

You might often want to also cache some API response and lets say user profile icons that appear in your site's dynamic content. In such we can use network-first strategy for our API to always fetch from the network if available and cache-first strategy for profile icons with something like:

new GenerateSW({
    runtimeCaching: [{
        urlPattern: /^http[s]*:\/{2}[\w.:-]+\/api\//,
        handler: 'networkFirst'
    }, {
        urlPattern: /^http[s]*:\/{2}[\w.:-]+\/profile_icons\//,
        handler: 'cacheFirst'
    }]
})

Upvotes: 7

fabjoh
fabjoh

Reputation: 76

I was struggling with this as well since i'm not using the CLI. I managed to get it working by including these scripts in npm scripts.

    "ngsw-config": "node_modules/.bin/ngsw-config dist src/ngsw-config.json",
    "ngsw-copy": "cp node_modules/@angular/service-worker/ngsw-worker.js dist/",
    "build-ngsw": "npm run ngsw-config && npm run ngsw-copy"

Include "build-ngsw" in your production build script.

The first script creates the ngsw.json file in your dist folder by reading the ngsw-config.json (which you'll have to create). The second script copies the actual angular service worker from @angular/service-worker to the dist folder.

Import and register the service worker. See step 3 in this tutorial Angular Service Worker Getting Started.

Upvotes: 6

Related Questions