GoogleChrome / workbox

📦 Workbox: JavaScript libraries for Progressive Web Apps
https://developers.google.com/web/tools/workbox/
MIT License
12.36k stars 818 forks source link

sw-lib has large file size for basic cases #361

Closed patrickhulce closed 7 years ago

patrickhulce commented 7 years ago

Library Affected: sw-lib

Browser & Platform: All

Description: My old manual service worker that does basic caching for a set of URLs with a simple version key went from 1k to 45k. I know that's not particularly actionable, and there are already distinct modules for a la carte inclusion, but might be nice to hunt down some savings in parts baked into sw-lib or provide other, smaller targeted builds to cover the most basic use cases.

paulirish commented 7 years ago

I managed to get a sourcemap tree of the built sw-lib. super useful for exploring what is in this 45k.

view it: http://standing-farm.surge.sh/

image

The sourcemaps generated in utils/build seem to be borked (technically, should also be reported) .. so I had to rebuild the bundle on my own. It's hacky but this is what i ended up using:

### hacky re-build of sw-lib ```js const fs = require('fs'); const babel = require('babel-core'); const rollup = require('rollup'); const nodeResolve = require('rollup-plugin-node-resolve'); const commonjs = require('rollup-plugin-commonjs'); rollup .rollup({ entry: './packages/sw-lib/src/index.js', sourceMap: true, plugins: [ nodeResolve({ jsnext: true, main: true, browser: true }), commonjs() ] }) .then(bundle => bundle.write({ dest: 'swbundle.js', moduleName: 'goog.swlib', format: 'cjs', sourceMap: true, })) .catch(err => console.log(err.message, err.stack)) .then(_ => { const sourcejs = fs.readFileSync('swbundle.js', 'utf-8'); const result = babel.transform(sourcejs, { presets: [ ['babili', { comments: false, keepFnName: true, keepClassName: true, }], ], sourceMaps: true, inputSourceMap: JSON.parse(fs.readFileSync('swbundle.js.map', 'utf-8')) }); fs.writeFileSync('./swbundle.min.js', result.code); fs.writeFileSync('./swbundle.min.js.map', JSON.stringify(result.map)); }); ```
addyosmani commented 7 years ago

Woo! Thanks for the source maps breakdown, @paulirish! ⭐️

Digging into our gzip sizes atm, we're coming in at just under 13KB:

$ gz sw-lib.v0.0.17.min.js 
orig size    (bytes): 
   44446
gzipped size (bytes): 
   12824

Inspecting our actual built source, we have a lot of debug level logging that's useful during iteration workflow but could be slimmed down for the final production build.

We might also be able to trim down some code using babel-preset-env to only transpile the bare minimum that modern browsers need.

jeffposnick commented 7 years ago

AFAIK, the only transpilation we're doing is async/await to generators, and as per http://caniuse.com/#feat=async-functions, if we only care about the stable versions of browsers with SW support, we don't need to do that anymore.

I worry a bit about Samsung Internet and other random Chromium-based browsers which don't get auto-updated as frequently as Chrome does, though.

jeffposnick commented 7 years ago

I looked into our options for doing conditional builds with imports removed.

Given that we're using ES2015 import syntax for pulling in everything, and you can't conditionally execute import, we're somewhat limited.

What seems like the most elegant (albeit still hack-y) solution is to use https://github.com/rollup/rollup-plugin-replace as part of our build process, and rewrite a few of the import statements during the build process so that they pull in modules that are effectively no-ops, or at least very minimal.

We could do this assert.js and log-helper.js, so that statements like

import assert from 'path/to/assert.js';

get rewritten as

import assert from 'path/to/assert-no-op.js';

where assert-no-op.js just exported an object that matched the assert.js interface, but didn't do anything.

For log-helper.js we could do something similar, though we might want to respond to the warn and error methods in the interface with a corresponding console.warn and console.log, instead of being a true no-op.

jeffposnick commented 7 years ago

Here's the current breakdown of the minified, production build, with error-stack-parser omitted:

Live source-maps-explorer output pgyppse1y1k

jeffposnick commented 7 years ago

I think this is well tracked via the overall v3 work. The addition of pr-bot in particular ensures that we're keeping an eye on build sizes as part of every PR.