-
Notifications
You must be signed in to change notification settings - Fork 816
ES2015 Modules & Browser Bundles
This document covers how the source code is set up for V3 of Workbox and how it's intended to be released / published.
Each package will have a structure of:
workbox-example/
package.json
README.md
index.mjs
_private.mjs
FileName1.mjs
exampleDirectory/
FileName2.mjs
-
package.json
is a normal NPM package file with the following pieces of information:-
"main": "./builds/browser/index.js"
will point to a browser friendly build of the module. -
"module": "./index.mjs"
: will be used by Rollup to find the ES2015 module code. -
"workbox": { "browserNamespace": "....", "packageType": "...." }
: These fields are used during the build process to generate the bundles release on NPM and the CDN. The namespace value affects how the module exposed on the global scope, if we set"browserNamespace": "xyz"
this would be accessed viaworkbox.xyz
.
-
-
index.mjs
is the default ES2015 export of the module. This will have a default export and named exports. -
browser.mjs
is the default browser export of the module. This will export a single object which provides the default and named exports.
These files have a symbolic importance and should be similar across each package.
-
_default.mjs
This should define the default export of the module that index.mjs and browser.mjs will proivde. -
_private.mjs
This should be the central place where all private classes and objects are exposed to be used by otherworkbox-*
modules. -
_types.mjs
Is used to define custom JSDoc types. This should contain no code - just JSDocs comments. -
_version.mjs
These files are autogenerated and added to each file. Build tools are smart enough to only include this once, but it provides version of a module - helpful for debugging.
All of the browser libraries for Workbox are written in ES2015 modules and files end with .mjs
extension.
When generating a browser friendly bundle we generate dev
and prod
bundles where prod
is aggressively stripped of any unnecessary code and minified.
We use process.env.NODE_ENV === 'production'
checks in our code to allow Rollup to evaluate this code and perform dead code elimination.
// Our source code looks like this
if (process.env.NODE_ENV !== 'production') {
console.log(`Hey this is super helpful but also increases file size.`);
} else {
console.log(`Hi.`);
}
// For dev builds, the above code will be outputted as
{
console.log(`Hey this is super helpful but also increases file size.`);
}
// For prod builds, the output is
{
console.log(`Hi.`);
}
You can extend this further to alter the export of a class
Our module can look like:
const ourExport = (process.env.NODE_ENV === 'production') ? slimExport : largeExport;
export default ourExport
Again, Rollup will eliminate dead code and only include the appropriate code that is exported.
You must import files within a package by referencing a specific file, you MUST NOT rely on a modules default / named exports.
For example, this is bad:
import {bar} from 'workbox-foo';
Instead you must reference the specific file that would supply bar
.
import {bar} from 'workbox-foo/bar.mjs';
This is a restriction we have in place to try and reduce unnecessary bloat in builds.
When one Workbox module wants to use another module's code, it will need to reference the code via a normal import.
For example, workbox-routing
wanting to throw a WorkboxError
which is defined in workbox-core
would do the following:
// Inside of a file in workbox-routing
import {WorkboxError} from 'workbox-core/_private/WorkboxError.mjs';
throw new WorkboxError('error-code');
There are a few scenarios to consider in terms of how this works as an ES2015 module and how it works as a browser bundle:
Running as an ES2015 Module: workbox-routing
will need to add workbox-core
as a dependency. Lerna will manage the npm -link
ing of workbox-core
and this is how the ES2015 set up will work (it'll get the code from node_modules).
Running as a browser iife: Our build process will replace the import with the appropriate browser namespace for each module, so for code above Rollup will replace the import with: const WorkboxError = workbox.core._private.WorkboxError;
.
This means we'll have shared code between modules and a more consistent explanation for API's and module code.
If you are curious to learn more regarding the
.mjs
extension please read: https://github.com/nodejs/node-eps/blob/master/002-es-modules.md