Rationales: Side Effects
All our packages are side effect free due to the fact that es modules are always side effect free even when changing other es modules. Only code which accesses browser globals like window
, console
in the root of the module will be treated a side effect and always included.
Everything else can be tree shaken by rollup.
Example
In this example we will define a function to override an es module export.
👉 main.js
import { somethingElse, overlays } from './overlays.js';
console.log(somethingElse);
👉 overlays.js
class OverlayManager {}
export let overlays = new OverlayManager();
export function setOverlays(newOverlays) {
overlays = newOverlays;
}
export const somethingElse = 'something else';
Example Result
However having this function alone does not mean a side effect as rollup can tree shake it.
See the code in rollup repl.
const somethingElse = 'something else';
console.log(somethingElse);
Example Override
Let's add an es module which uses that override.
👉 main.js
import { somethingElse, overlays } from './overlays.js';
import './override.js';
console.log(somethingElse);
// this will trigger loading of full overlays.js & override.js code
// console.log(overlays.list);
👉 override.js
import { setOverlays } from './overlays.js';
setOverlays(new Object());
Example Override Result
It will still be fully tree shaken.
See the code in rollup repl.
const somethingElse = 'something else';
console.log(somethingElse);
// this will trigger loading of full overlays.js & override.js code
// console.log(overlays.list);
Example Override Result Accessing
ONLY if you actually access overlays
it will include overlays.js
& override.js
.
class OverlayManager {}
let overlays = new OverlayManager();
function setOverlays(newOverlays) {
overlays = newOverlays;
}
const somethingElse = 'something else';
setOverlays(new Object());
console.log(somethingElse);
// this will trigger loading of full overlays.js & override.js code
console.log(overlays.list);
Comprehensive Example
This time we have a separate controller which also accesses the overlays
.
👉 main.js
import { somethingElse, setOverlays, overlays } from './overlays.js';
import { OverlayController, somethingElse2 } from './OverlayController.js';
// the following code will tree shake overlays away hence overlays is side effect free
setOverlays(new Object());
console.log(somethingElse);
console.log(somethingElse2);
//** The following will toggle importing of overlays */
// 1. import overlays directly and access it
// console.log(overlays.list);
// 2. create an OverlayController which internally accesses overlays
// const ctrl = new OverlayController();
// console.log(ctrl.manager.list);
👉 overlays.js
class OverlayManager {
constructor() {
this.list = [];
}
add(a) {
this.list.push(a);
}
}
export let overlays = new OverlayManager();
export function setOverlays(newOverlays) {
overlays = newOverlays;
}
export const somethingElse = 'something else';
// the following line is a side effect as it always will be included
console.log('overlays side effect');
👉 OverlayController.js
import { overlays } from './overlays.js';
export class OverlayController {
constructor(config = {}, manager = overlays) {
this.manager = manager;
this.manager.add(this);
}
}
export const somethingElse2 = 'something else';
Comprehensive Example Result
Even with all these intertwined code rollup can tree shake it fully away.
Again if you access the overlays
or you start instantiating an OverlaysController
it will include all the needed code.
Be sure to see it for yourself in the rollup repl.
const somethingElse = 'something else';
// the following line is a side effect as it always will be included
console.log('overlays side effect');
const somethingElse2 = 'something else';
console.log(somethingElse);
console.log(somethingElse2);
//** The following will toggle importing of overlays */
// 1. import overlays directly and access it
// console.log(overlays.list);
// 2. create an OverlayController which internally accesses overlays
// const ctrl = new OverlayController();
// console.log(ctrl.manager.list);