Skip to content

Commit 4b473cf

Browse files
authored
feat: add rollup-plugin-workbox (#378)
1 parent d4fd21c commit 4b473cf

File tree

16 files changed

+435
-17
lines changed

16 files changed

+435
-17
lines changed

.changeset/five-peaches-poke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@web/rollup-plugin-workbox': patch
3+
---
4+
5+
moved rollup-plugin-workbox to @web

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"@typescript-eslint/parser": "^3.7.0",
4444
"chai": "^4.2.0",
4545
"concurrently": "^5.2.0",
46+
"deepmerge": "^4.2.2",
4647
"eslint": "^7.5.0",
4748
"eslint-config-prettier": "^6.11.0",
4849
"husky": "^1.0.0",
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# rollup-plugin-workbox
2+
3+
[![Published on npm](https://img.shields.io/npm/v/rollup-plugin-workbox.svg)](https://www.npmjs.com/package/rollup-plugin-workbox)
4+
5+
Rollup plugin that builds a service worker with workbox as part of your rollup build
6+
7+
## Usage
8+
9+
This package provides two rollup plugins: one that generates a complete service worker for you and one that generates a list of assets to precache that is injected into a service worker file.
10+
11+
The plugins are implemented as two function in the rollup-plugin-workbox module, named `generateSW` and `injectManifest`.
12+
13+
### `generateSW`
14+
15+
Import the `generateSW` plugin from `rollup-plugin-workbox`, and add it to your `plugins` array in your `rollup.config.js`. The plugin takes a workbox config object, and an optional render function as the second argument.
16+
17+
You can find a detailed list of supported properties for the workbox config object [here](https://developers.google.com/web/tools/workbox/modules/workbox-build#generatesw_mode).
18+
19+
```js
20+
const { generateSW } = require('@web/rollup-plugin-workbox');
21+
22+
module.exports {
23+
input: 'main.js',
24+
output: {
25+
file: 'dist/bundle.js',
26+
format: 'esm',
27+
},
28+
plugins: [
29+
generateSW({
30+
swDest: '/dist/sw.js',
31+
globDirectory: 'demo/dist/',
32+
})
33+
],
34+
};
35+
```
36+
37+
You can also `require` your `workbox-config.js` file and pass it to the plugin.
38+
39+
```js
40+
const { generateSW } = require('@web/rollup-plugin-workbox');
41+
42+
const workboxConfig = require('./workbox-config.js')
43+
44+
module.exports {
45+
// ...
46+
plugins: [
47+
generateSW(workboxConfig)
48+
],
49+
};
50+
```
51+
52+
You can also customize the console output after workbox has generated your service worker by passing an optional render function as the second argument to the plugin:
53+
54+
```js
55+
const { generateSW } = require('@web/rollup-plugin-workbox');
56+
57+
const workboxConfig = require('./workbox-config.js')
58+
59+
module.exports {
60+
// ...
61+
plugins: [
62+
generateSW(
63+
workboxConfig,
64+
function render({ swDest, count, size }) {
65+
console.log(
66+
'📦', swDest,
67+
'#️⃣', count,
68+
'🐘', size,
69+
);
70+
}),
71+
)
72+
],
73+
};
74+
```
75+
76+
### `injectManifest`
77+
78+
Import the `injectManifest` plugin from `rollup-plugin-workbox`, and add it to your `plugins` array in your `rollup.config.js`. The plugin takes a workbox config object, and an optional render function as the second argument.
79+
80+
You can find a detailed list of supported properties for the workbox config object [here](https://developers.google.com/web/tools/workbox/modules/workbox-build#injectmanifest_mode).
81+
82+
```js
83+
const { injectManifest } = require('@web/rollup-plugin-workbox');
84+
85+
module.exports {
86+
input: 'main.js',
87+
output: {
88+
file: 'dist/bundle.js',
89+
format: 'esm',
90+
},
91+
plugins: [
92+
injectManifest({
93+
swSrc: 'sw.js',
94+
swDest: '/dist/sw.js',
95+
globDirectory: 'demo/dist/',
96+
})
97+
],
98+
};
99+
```
100+
101+
You can also `require` your `workbox-config.js` file and pass it to the plugin.
102+
103+
```js
104+
const { injectManifest } = require('@web/rollup-plugin-workbox');
105+
106+
const workboxConfig = require('./workbox-config.js')
107+
108+
module.exports {
109+
// ...
110+
plugins: [
111+
injectManifest(workboxConfig)
112+
],
113+
};
114+
```
115+
116+
You can also customize the console output after workbox has created your service worker by passing an optional render function as the second argument to the plugin:
117+
118+
```js
119+
const { injectManifest } = require('@web/rollup-plugin-workbox');
120+
121+
const workboxConfig = require('./workbox-config.js')
122+
123+
module.exports {
124+
// ...
125+
plugins: [
126+
injectManifest(
127+
workboxConfig,
128+
function render({ swDest, count, size }) {
129+
console.log(
130+
'📦', swDest,
131+
'#️⃣', count,
132+
'🐘', size,
133+
);
134+
}),
135+
)
136+
],
137+
};
138+
```
139+
140+
### A note on the `mode` config property
141+
142+
The `generateSW` mode of Workbox supports a `mode` property, that when set to `'production'` will bundle your generated service worker, and get rid of any `process.env.NODE_ENV` variables that are internally used in the Workbox libraries.
143+
144+
Unfortunately this got [wrongfully documented](https://github.com/GoogleChrome/workbox/issues/2427) for `injectManifest`, and this means that `injectManifest` does not actually support the `mode` property. There is a feature request on the [Workbox repo](https://github.com/GoogleChrome/workbox/issues/2588) to support this feature for `injectManifest` as well.
145+
146+
Until this gets fixed in `workbox-build`, `rollup-plugin-workbox` **does** support the `mode` property in the Workbox configuration for `injectManifest`, and when set to `'production'` will output a production optimized service worker for you.
147+
148+
```diff
149+
const { injectManifest } = require('@web/rollup-plugin-workbox');
150+
151+
module.exports {
152+
input: 'main.js',
153+
output: {
154+
file: 'dist/bundle.js',
155+
format: 'esm',
156+
},
157+
plugins: [
158+
injectManifest({
159+
swSrc: 'sw.js',
160+
swDest: '/dist/sw.js',
161+
globDirectory: 'demo/dist/',
162+
+ mode: 'production',
163+
})
164+
],
165+
};
166+
```
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
if (process.env.NODE_ENV === 'production') {
2+
console.log('foo');
3+
}
4+
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('hello workbox');
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { generateSW, injectManifest } from '../dist/index.js';
2+
3+
export default {
4+
input: 'demo/main.js',
5+
output: {
6+
file: 'demo/dist/bundle.js',
7+
format: 'esm',
8+
},
9+
plugins: [
10+
generateSW({
11+
swDest: 'demo/dist/generateSW_sw.js',
12+
globDirectory: 'demo/dist/',
13+
globIgnores: ['injectManifest_sw.js'],
14+
},
15+
function render({ swDest, count, size }) {
16+
console.log(`\nCustom render! ${swDest}`);
17+
console.log(`Custom render! The service worker will precache ${count} URLs, totaling ${size}.\n`);
18+
}),
19+
injectManifest({
20+
swSrc: 'demo/injectManifestSwSrc.js',
21+
swDest: 'demo/dist/injectManifest_sw.js',
22+
globDirectory: 'demo/dist/',
23+
globIgnores: ['generateSW_sw.js'],
24+
mode: 'production',
25+
}),
26+
],
27+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "@web/rollup-plugin-workbox",
3+
"version": "1.0.0",
4+
"description": "Rollup plugin that builds a service worker with workbox as part of your rollup build",
5+
"license": "MIT",
6+
"repository": {
7+
"type": "git",
8+
"url": "https://github.com/modernweb-dev/web.git",
9+
"directory": "packages/rollup-plugin-workbox"
10+
},
11+
"author": "modern-web",
12+
"homepage": "https://github.com/modernweb-dev/web/tree/master/packages/rollup-plugin-workbox",
13+
"bugs": {
14+
"url": "https://github.com/modernweb-dev/web/issues"
15+
},
16+
"main": "dist/index.js",
17+
"scripts": {
18+
"build": "tsc",
19+
"demo": "rollup -c demo/rollup.config.js"
20+
},
21+
"keywords": [
22+
"rollup",
23+
"service-worker",
24+
"workbox"
25+
],
26+
"dependencies": {
27+
"@rollup/plugin-node-resolve": "^8.4.0",
28+
"@rollup/plugin-replace": "^2.3.3",
29+
"pretty-bytes": "^5.3.0",
30+
"rollup": "^2.20.0",
31+
"rollup-plugin-terser": "^6.1.0",
32+
"workbox-build": "^5.0.0"
33+
},
34+
"devDependencies": {
35+
"@types/workbox-build": "^5.0.0"
36+
}
37+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import {
2+
generateSW as _generateSw,
3+
injectManifest as _injectManifest,
4+
GenerateSWConfig,
5+
InjectManifestConfig,
6+
} from 'workbox-build';
7+
import * as prettyBytes from 'pretty-bytes';
8+
import * as rollup from 'rollup';
9+
import replace from '@rollup/plugin-replace';
10+
import { terser } from 'rollup-plugin-terser';
11+
import resolve from '@rollup/plugin-node-resolve';
12+
13+
const name = 'workbox';
14+
15+
const report = ({ swDest, count, size }: { swDest: string; count: number; size: number }) => {
16+
const prettySize = prettyBytes.default(size);
17+
18+
console.log(`\nThe service worker file was written to ${swDest}`);
19+
console.log(`The service worker will precache ${count} URLs, totaling ${prettySize}.\n`);
20+
};
21+
22+
export function generateSW(generateSWConfig: GenerateSWConfig, render = report) {
23+
const { swDest, globDirectory } = generateSWConfig;
24+
25+
if (!swDest) throw new Error('No service worker destination specified');
26+
if (!globDirectory) throw new Error('No globDirectory specified');
27+
28+
const doRender = ({
29+
count,
30+
size,
31+
}: {
32+
count: number;
33+
filePaths: string[];
34+
size: number;
35+
warnings: string[];
36+
}) => render({ swDest, count, size });
37+
38+
return {
39+
name,
40+
writeBundle() {
41+
return _generateSw(generateSWConfig).then(doRender).catch(console.error);
42+
},
43+
};
44+
}
45+
46+
export function injectManifest(injectManifestConfig: InjectManifestConfig, render = report) {
47+
const { swSrc, swDest, globDirectory, mode } = injectManifestConfig;
48+
49+
if (!swSrc) throw new Error('No service worker source specified');
50+
if (!swDest) throw new Error('No service worker destination specified');
51+
if (!globDirectory) throw new Error('No globDirectory specified');
52+
53+
const doRender = ({
54+
count,
55+
size,
56+
}: {
57+
count: number;
58+
filePaths: string[];
59+
size: number;
60+
warnings: string[];
61+
}) => render({ swDest, count, size });
62+
63+
return {
64+
name,
65+
writeBundle() {
66+
return _injectManifest(injectManifestConfig)
67+
.then(doRender)
68+
.then(async () => mode === 'production' && (await processBundle({ swDest })))
69+
.catch(console.error);
70+
},
71+
};
72+
}
73+
74+
/**
75+
* @TODO
76+
* This is a hack to be able to support the `mode` property for `injectManifest` until Workbox decides to support it.
77+
* Feature is tracked here: https://github.com/GoogleChrome/workbox/issues/2588
78+
* Once Workbox's `injectManifest` supports this out of the box, we should remove this.
79+
*/
80+
const processBundle = async ({ swDest }: { swDest: string }) => {
81+
const bundle = await rollup.rollup({
82+
input: swDest,
83+
plugins: [
84+
replace({ 'process.env.NODE_ENV': '"production"' }),
85+
resolve(),
86+
terser({ output: { comments: false } }),
87+
],
88+
});
89+
await bundle.write({
90+
file: swDest,
91+
format: 'iife',
92+
});
93+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Don't edit this file directly. It is generated by /scripts/update-package-configs.ts
2+
3+
{
4+
"extends": "../../tsconfig.node-base.json",
5+
"compilerOptions": {
6+
"module": "es2015",
7+
"outDir": "./dist",
8+
"rootDir": "./src",
9+
"composite": true,
10+
"allowJs": true,
11+
"lib": [
12+
"webworker"
13+
],
14+
"types": [
15+
"workbox-build"
16+
]
17+
},
18+
"references": [],
19+
"include": [
20+
"src"
21+
],
22+
"exclude": [
23+
"dist",
24+
"demo"
25+
]
26+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"compilerOptions": {
3+
"lib": ["webworker"],
4+
"types": ["workbox-build"]
5+
},
6+
"exclude": ["dist", "demo"]
7+
}

0 commit comments

Comments
 (0)