Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InjectManifest Plugin doesn't compile the serviceworker with webpack #1513

Closed
kesne opened this issue Jun 1, 2018 · 41 comments
Closed

InjectManifest Plugin doesn't compile the serviceworker with webpack #1513

kesne opened this issue Jun 1, 2018 · 41 comments

Comments

@kesne
Copy link

kesne commented Jun 1, 2018

Library Affected:
workbox-webpack-plugin

Browser & Platform:
all browsers

Issue or Feature Request Description:
Ideally, the SW would go through the normal webpack compilation, so that the code gets transformed. Right now, the code seems to not be transformed by it, and as a result it creates a divide in our project as the transforms that apply are different. It also makes it difficult to use something like TypeScript or Flow in the ServiceWorker.

@kesne kesne changed the title Webpack InjectManifest doesn't Webpack InjectManifest doesn't compile the serviceworker with webpack Jun 1, 2018
@kesne kesne changed the title Webpack InjectManifest doesn't compile the serviceworker with webpack InjectManifest Plugin doesn't compile the serviceworker with webpack Jun 1, 2018
@kronos93
Copy link

kronos93 commented Jun 4, 2018

I have the same problem, in my custom sw I want to import some files from node_modules but webpack do not compile the swSrc.
Does anyone know how to do that?

@edgaraskazlauskas
Copy link

If I understand the problem correctly, one way to solve this would be to first build the service worker file only and then build the rest of the app and specify swSrc to be the previously built service worker file.

To achieve this simply export multiple configs from webpack config file. In the first config, specify the service worker body file as the single entry point and do any transformations you want with it in the rest of the build. In the second build just use the file. Is this clear enough or should I give a complete example?

@kesne
Copy link
Author

kesne commented Jun 13, 2018

That’s one way to do it, but I think that’s working around the plugin, vs having the plugin work in the more ideal way.

@treetopvt
Copy link

@edgaraskazlauskas If you could provide an example that would be very helpful. I've never run through a webpack build process twice.

@laszbalo
Copy link

laszbalo commented Aug 13, 2018

I'd like to use InejctManifestPlugin as follows, without the two-pass hack suggested above:

// webpack.config.js
module.exports = {
  entry : {
    sw: './src/sw.js'
  }, 
  output: {
    filename: '[name].js'
  },
  target: 'webworker',
  plugins: [
    new InjectManifestPlugin()
  ]
}

The way it currently works is not intuitive at all. I expect webpack to compile my service worker and expect the InjectManifestPlugin to inject the manifest in a single pass. Also, both the source and the destination of my service worker are already present.

@stevenharman
Copy link

Is this clear enough or should I give a complete example?

@edgaraskazlauskas I'd much appreciate an example. Thanks!

@lwansbrough
Copy link

lwansbrough commented Nov 17, 2018

If you allow templating in the swSrc parameter, you could allow it to be defined as swSrc: './dist/js/sw.[contenthash].js' -- right?

@mcshaman
Copy link

mcshaman commented Mar 4, 2019

If I am reading this thread correctly an example still has not been provided and it is still a problem. I think I am running into the same issue expressed by the OP. I have a service worker with module imports. I wanted to use the workbox Webpack plugin to inject a precache manifest how the benefit of the injected dynamic manifest comes at the cost of modules not being transpiled.

// sw.js (original)
import {precacheAndRoute} from 'workbox-precaching/precacheAndRoute.mjs'

precacheAndRoute(self.__precacheManifest)
// webpack.config.js
const {InjectManifest} = require('workbox-webpack-plugin')
const path = require('path')

module.exports = {
	entry: {
		sw: './src/sw.js',
	},
	plugins: [
		new InjectManifest({
			swSrc: path.resolve(__dirname, 'src/sw.js'),
			importWorkboxFrom: 'disabled',
		}),
	],
}
// sw.js (bundled... not)
importScripts("precache-manifest.47565e861a50e4b271a0ce24cc9d8095.js");

import {precacheAndRoute} from 'workbox-precaching/precacheAndRoute.mjs'

precacheAndRoute(self.__precacheManifest)

As you can the bundled sw.js file does not include the webpackBootstrap and the module import is remains unchanged.

The inability to run the service worker through Webpacks transpiler pretty much renders the plugin useless for me.

Hoping to find some solutions.

@jeffposnick
Copy link
Contributor

Does the new guidance at https://developers.google.com/web/tools/workbox/guides/using-bundlers help any?

CC: @philipwalton

@renestalder
Copy link

Does the new guidance at https://developers.google.com/web/tools/workbox/guides/using-bundlers help any?

Not much. I have the same struggles. I write everything in TypeScript and Webpack is using ts-loader to combile the TypeScript code. But the plugin totally ignores this. If I set swSrc to be a TypeScript file and swDest to be a JavaScript file, the plugin simply copies the TypeScript file and renames it, but doesn't run it through the defined webpack chain.

@Wol
Copy link

Wol commented Apr 9, 2019

Does the new guidance at https://developers.google.com/web/tools/workbox/guides/using-bundlers help any?

I'm not sure which bits in particular were 'new' (I've only just started looking at this!)
I can see:

If you also want to use webpack to generate your service worker file (as described in this article), beware that the workbox-webpack-plugin's injectManifest config accepts a swSrc option that it will update with your precache manifest.
This can be problematic if you're using the same webpack configuration to generate your service worker file, since it may not exist by the time the workbox-webpack-plugin code runs.

This does acknowledge the problem, but doesn't seem to suggest a workaround.

I'm trying to migrate from the old sw-precache module, and have now had to generate my own root serviceworker.js file (rather than just additional files to include), which requires me to use calls to things like registerRoute directly, rather than it being defined via the webpack configuration. I'm trying to use imports so that my IDE actually picks up what exists, as I was getting lots of 'workbox' is not defined errors in my linter.

I tried to do a two-pass method where one pass will build from my serviceworker code to a transpiled one, and then run the injectManifest on the transpiled class, but it has issues with the filenames. Now some part of the manifest is trying to load https://app/my_main_app_file.js as in the manifest generated it has an additional slash at the front of the URL: "url": "//app/built-service-worker.js"

Is there a way to do this with workbox + webpack, or should I just stick with the sw-precache plugin instead which worked, but is deprecated?

@ALiangLiang
Copy link

I copy handleMake from serviceworker-webpack-plugin. And it's work for me. I'm new to webpack so It's maybe not perfectly solve this issue.

The code:
https://github.com/ALiangLiang/workbox/blob/feat/%231513/packages/workbox-webpack-plugin/src/inject-manifest.js

  plugins: [
    ...,
    new workboxPlugin.InjectManifest({
      swSrc: 'sw.js',
      entry: path.join(__dirname, '..', 'src/sw.js'),
    })
  ]

@ghost
Copy link

ghost commented May 21, 2019

@ALiangLiang I can't quite get your workaround to work - In your case what does swSrc refer to? If I both let entry and swSrc refer to the same TypeScript file, the raw TS Code gets copied over to the Service Worker, if it is an empty dummy JS file the service worker is empty. (in addition to the importScripts(...))

I'd even argue that a swSrc is unneeded in combination with entry. I want to write the service worker by myself, since there is a lot of stuff workbox cannot possibly handle for me(session data, live updates, ...).
But I don't want to do this in a JS file that just gets copied over, but instead write it in proper TypeScript.
The only thing I need is to (quite literally) have the generated manifest injected into the compiled service worker so that I don't have to manually hunt down static assets.

@pungggi
Copy link

pungggi commented May 25, 2019

@ALiangLiang I can't quite get your workaround to work - In your case what does swSrc refer to? If I both let entry and swSrc refer to the same TypeScript file, the raw TS Code gets copied over to the Service Worker, if it is an empty dummy JS file the service worker is empty.

I see your point. Maybe it is a typo. Did you try swDest: 'sw.js' ? That would make much more sense..

@Patrick-Sachs see
image

@pungggi
Copy link

pungggi commented May 25, 2019

@ALiangLiang Why not propose a PR ?

@ALiangLiang
Copy link

ALiangLiang commented May 25, 2019

@pungggi
As I said, I am a new to webpack. I just copied and tried this workaround. The mechanism is still not very clear. I can make a PR, but I don't think it's suitable for using it directly in the project. I need somebody help me to adjust the interface(options).

#2060

@pungggi
Copy link

pungggi commented May 26, 2019

I can confirm ALiangLiang solution works:

  1. set up output as usual and set it also under swSrc
  2. set where to find your workbox template
  3. set the final worker filename
    image

to test quickly I ve set up an npm package called 'wrkbx' do not use in production

@sibelius
Copy link

what is the final solution for this?

@henrylearn2rock
Copy link

https://stackoverflow.com/questions/56710951/how-to-get-workboxplugin-injectmanifest-to-work

I also got stuck, please update the doc and provide a solution? Thanks!

@badddams
Copy link

I'm also having the exact same problem mentioned above by @henrylearn2rock in his stackoverflow post. I would've thought this to have been a standard thing that the injectManifest plugin would take care of. Makes the whole thing kinda pointless to not transform this code through webpack first 🤔
@jeffposnick please help ☺️ (I've read through the entire guide that you posted and there's nothing in there about this and none of the steps resolve it)

@jeffposnick jeffposnick added this to the v5 milestone Jun 27, 2019
@jeffposnick
Copy link
Contributor

We are actively working on a rewrite for the InjectManifest plugin that will perform a webpack child compilation on swSrc, in addition to populate the precache manifest.

It's still too early to use, but you can see a sneak-preview of the changes at https://github.com/GoogleChrome/workbox/compare/v5...wepback-v5?expand=1

We'll be rolling out the first alphas of v5 with this functionality following some additional tests and cleanup work—likely in the order of a couple of weeks from now.

@jeffposnick
Copy link
Contributor

(I'm not 100% sure what the ergonomics of this will be if the swSrc is a TypeScript file, so I'm hoping for feedback from folks with that use case once we release our first alphas.)

@jeffposnick
Copy link
Contributor

This should be addressed by the current Workbox v5.0.0 alpha.

@yury-kozlov
Copy link

yury-kozlov commented Sep 16, 2019

I'm trying to figure out how to make webpack and workbox plugin play together (compile and inject in one flow), but a bit confused about the correct setup.
Is this already supported in the latest version of the plugin (or will be only in v5) ? do you have some examples ?
Thanks!

@jeffposnick
Copy link
Contributor

In v5, if you list a service worker file as the swSrc in InjectManifest mode, webpack will automatically perform a (child) compilation on that file, in addition to replacing self.__WB_MANIFEST with the precache manifest that was derived from the main compilation's assets.

That was not the case in v4, so if you need that functionality, please try out the v5 beta.

@yury-kozlov
Copy link

Thanks! Finally it worked for me with plugin v4.3.1 and customized sw-src.js (with "import-from" statements instead of importScripts()),

  1. entry: path.resolve('sw-src.js'),
    output: {
    path: SOME_OUTPUT_PATH,
    filename: 'bundle.js',
    },
  2. new InjectManifest({
    swSrc: 'bundle.js',
    swDest: ${SOME_OUTPUT_PATH}/sw.js,
    importWorkboxFrom: 'local',
    globDirectory: SOME_OUTPUT_PATH,
    globPatterns: [ '**/*.{html,js,css}' ],

@29rayb
Copy link

29rayb commented Oct 2, 2019

@jeffposnick , I'm trying the beta and was wondering if you plan on dropping the importsDirectory and precacheManifestFilename params when its no longer in beta

@jeffposnick
Copy link
Contributor

@ray-kim-12 yes, neither of those options should be supported in the current beta 1 release, as they are no longer relevant.

@fgarcia
Copy link

fgarcia commented Oct 5, 2019

I've just tried v5.beta-1 because I also wanted a webpack/typescript build on my worker file. I got exactly that and saw the typical webpack generated code without any single config modification (I am using InjectPlugin). However when moving from v4 to v5 I noticed the 'workbox' global no longer exists and there is no mention in the changelogs.

Is there doc/example about how to access 'workbox' in v5?

@jeffposnick
Copy link
Contributor

workbox corresponded to an instance of the workbox-sw module, which is effectively a proxy that mapped a namespace of other Workbox modules with code to import the corresponding files from the CDN.

Because you're using a local bundle of all the Workbox code that you actually need now, the idea is that workbox-sw (and therefore the workbox global symbol) should no longer be needed.

If you're trying to accomplish something specific with the workbox symbol that you can't figure out how to do in v5, could you open a new GitHub issue (or Stack Overflow question) with the details? This is a closed GitHub issue and it would be best to move the discussion elsewhere.

@amosyuen
Copy link

amosyuen commented Nov 5, 2019

Tried to use v5.0.0-beta.1, but can't get it to compile. I get an error: Can't find self.__WB_MANIFEST in your SW source.

// service-worker.js
precacheAndRoute(self.__WB_MANIFEST);
// webpack.config.js
...
config.plugins.push(
  new WorkboxWebpackPlugin.InjectManifest({
    // Use custom service worker implementation
    swSrc: path.resolve(projectConfig.srcPath, 'service-worker.js'),
    // Don't precache sourcemaps (they're large) and build asset manifest:
    exclude: [/\.map$/, /asset-manifest\.json$/],
  })
);

@amosyuen
Copy link

amosyuen commented Nov 5, 2019

Oh, found the problem, it was because I was importing another file named service-worker.js from another directory. Renaming the file fixed the problem.

@bibekthapa007
Copy link

I have the same problem, in my custom sw I want to import some files from node_modules but webpack do not compile the swSrc.
Does anyone know how to do that?

Did you solve this issue?

@novaknole
Copy link

novaknole commented Jan 30, 2020

Have you figured this out guys?

My problem seems the following:

i got service-worker in my src directory:

'use strict';
const utils = require('./utils')
const path = require('path')
const DotEnvWebpack = require('dotenv-webpack');
const WorkboxPlugin        = require('workbox-webpack-plugin');

console.log(path.resolve(__dirname, '../src/js/service-worker.js'));
module.exports = {
    mode: process.env.NODE_ENV !== 'development' ? 'production' : 'development',
    entry: {
        main: './src/js/service-worker.js'
    },

    output: {
        path: utils.resolve('dist'),
        publicPath: '/',
        filename: 'service-worker.js',
    },
    resolve: {
        alias: {
            '~': path.resolve('')
        }
    },

    plugins: [
        new DotEnvWebpack({systemvars: true}),
        new  WorkboxPlugin.InjectManifest({
            swSrc: path.resolve(__dirname, '../src/js/service-worker.js'),
            include:[
                /\.html$/,
                /\.js$/,
                /\.css$/,
                /\.woff2$/,
                /\.jpg$/,
                /\.png$/
            ]
        })
    ]
};
import { skipWaiting, clientsClaim, setCacheNameDetails } from 'workbox-core';
import { precacheAndRoute } from 'workbox-precaching';
import { registerNavigationRoute } from 'workbox-routing';

skipWaiting();
clientsClaim();

console.log(self.__precacheManifest, " hoops1");
console.log(self.__WB_MANIFEST, " hooops2");
precacheAndRoute(self.__precacheManifest);

When i run the above config of webpack, it makes service-worker.js file in dist, but doesn't contain anything such as importScripts('manifest') and also when running in browser,

console.log(self.__WB_MANIFEST, " hooops2"); //prints empty array
console.log(self.__precacheManifest, " hoops1"); //prints undefined

What do I do?

@philipwalton
Copy link
Member

@novaknole the workbox-webpack-plugin is not intended to be used if your webpack entry point is your service worker file itself (e.g. in your case, ./src/js/service-worker.js).

Instead, it's intended to be used where your application's JavaScript code is the entry point, and then it will also create a service worker file that will precache the JavaScript chunks generated by webpack after bundling your app's main JavaScript code. Does that make sense?

If you're looking specifically for how to use webpack to bundle a service worker file, I'd recommending taking a look at this guide: Using Bundlers (webpack/Rollup) with Workbox

@novaknole
Copy link

@philipwalton Thanks man. I made it work.

@bdteo
Copy link

bdteo commented Feb 10, 2020

@philipwalton

@novaknole the workbox-webpack-plugin is not intended to be used if your webpack entry point is your service worker file itself (e.g. in your case, ./src/js/service-worker.js).

Instead, it's intended to be used where your application's JavaScript code is the entry point, and then it will also create a service worker file that will precache the JavaScript chunks generated by webpack after bundling your app's main JavaScript code. Does that make sense?

If you're looking specifically for how to use webpack to bundle a service worker file, I'd recommending taking a look at this guide: Using Bundlers (webpack/Rollup) with Workbox

ServiceWorkers are not constrained to just caching assets. It is quite handy to be able to import ES6 modules into a ServiceWorker without worrying about Webpack configuration.

There are a lot of repos that have workbox-webpack-plugin as a dependency. Many projects that have the workbox-webpack-plugin as a dependency just blackbox most of the Webpack plugins they use (because it's the easier thing).

If the defaults remain like this many people will have to spend tons of time just on creating alternative Webpack configurations.

if you are saying that ES5 should be a default in 2020 I cannot agree less and the sense you are talking about is lacking.

@changyeamoon
Copy link

@philipwalton Thanks man. I made it work.

@novaknole How did you make it work :(

@novaknole
Copy link

@changyeamoon still a problem or need help?

@changyeamoon
Copy link

@novaknole It is resolved, turned out to be a different kind of issue. Thanks for checking up 😄

@blimmer
Copy link

blimmer commented Apr 18, 2022

It looks like back in 2019 a temporary package, wrkbx was published to test compiling service workers. Although the original comment stated that it shouldn't be used in production, I've got a client who was using this package as part of their build and never moved over to workbox-webpack-plugin. It looks like this package is being downloaded hundreds of times weekly:

Screen_Shot_2022-04-18_at_11_05_50

To help folks discover that they should move back over to the official package, it would be nice to mark this package as deprecated on NPM (docs).

The command would look something like:

npm deprecate wrkbx "This package should not be used in production. Please switch to the official workbox packages. See https://github.com/GoogleChrome/workbox for instructions"

cc @pungggi who it looks like the package belongs to - can you deprecate the package?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment