Javascript Distribution in a galaxy far, far away
@opherv / FrontEnd.IL / Dec 2017
PackWars
And the winner is...
Require.js
SystemJS
Browserify
Webpack
Hi! I'm Opher
I'm a creative developer at Eko
What's packing/bundling and why do we need it?
What if the
were to be built as Web App?
Death Star
<script src="superLaser.js"></script>
<script src="turboLasers.js"></script>
<script src="garbageCompactor.js"></script>
<script src="communication.js"></script>
Loading modules manually
<link rel="stylesheet" href="style/superLaser.css">
<link rel="stylesheet" href="style/turboLaser.css">
<link rel="stylesheet" href="style/garbageCompactor.css">
<link rel="stylesheet" href="style/communication.css">
<link rel="stylesheet" href="style/style.css">
DeathStar.html
@opherv
Loading modules manually - advantages
No new knowledge required
@opherv
You can code like it's 1999
@opherv
Loading modules manually - disadvantages
Module Communication via globals
Huge list to manage in one file
Sorting out dependencies gets difficult
Multiple HTTP calls
@opherv
Doing this might look like a good idea at first...
sometimes they don't turn out like you imagined
Quite Ancient
Can teach us a thing or two
Packs a punch
Uses odd syntax and cryptic messaging
Uncaught Error: Mismatched anonymous define() module: function definition(name, global)
~2009 by James Burke
<script data-main="scripts/DeathStar" src="scripts/require.js"></script>
Using Require.JS
DeathStar.html
require(['SuperLaser'], function(superLaser) {
superLaser.destroyPlanet("Alderaan");
});
DeathStar.js
@opherv
//dependencies
define(['BeamCrystal'], function (beamCrystal) {
...
// private function
function prepareLaser(){
}
// public function
function destroyPlanet(planet){
prepareLaser(beamCrystal);
laser.fire(planet);
}
// exposed public object
return {
destroyPlanet: destroyPlanet
}
});
Anatomy of an AMD Module
SuperLaser.js
@opherv
Multiple HTTP calls
* HTTP/1
@opherv
Multiple HTTP calls
* HTTP/1
@opherv
Require.JS - advantages
sync & async resource loading
Uglifying & optimizing
Require.JS - disadvantages
Long and winding configuration file
Confusing documentation
Giant JS file at the end - downside of bundling
@opherv
You have to write AMD modules
@opherv - follow me on twitter!
GIVEAWAY
TIME
{} + [] =
0
[] + {} =
[Object Object]
Both break down into smaller pieces
Transform one language into another
~2012 by James Halliday
<script src="scripts/bundle.js"></script>
Using Browserify
DeathStar.html
@opherv
Building with Browserify
browserify DeathStar.js -o bundle.js
run
var superLaser = require("SuperLaser");
superLaser.destroyPlanet("Alderaan");
DeathStar.js
bundle.js
--- compiled code ---
@opherv
//dependencies
var beamCrystal = require('BeamCrystal');
...
// private function
function prepareLaser(){
}
// public function
function destroyPlanet(planet){
prepareLaser(beamCrystal);
laser.fire(planet);
}
// exposed public object
module.exports = {
destroyPlanet: destroyPlanet
}
Anatomy of a Common.js Module
SuperLaser.js - AMD
@opherv
//dependencies
define(['BeamCrystal'], function (beamCrystal) {
...
// private function
function prepareLaser(){
}
// public function
function destroyPlanet(planet){
prepareLaser(beamCrystal);
laser.fire(planet);
}
// exposed public object
return {
destroyPlanet: destroyPlanet
}
});
SuperLaser.js - CommonJS
Browserify Transforms
Babelify - turn ES6+ code into vanilla ES5
Cssify - allows you to require CSS files
Uglifyify - minify code
browserify DeathStar.js -o bundle.js -t babelify
run
@opherv
Browserify - advantages
Simple to set up and lightweight
Browserify - advantages
Use NPM modules in both server and client
disadvantages - multiple bundles
@opherv
Browserify - disadvantages
No asynchronous require
Relies on CommonJS packages
Giant JS file / bundles with repeated code
@opherv
Gets the job done, in its own way
Art by TheAdamTaylor
Comes in two flavors - old and new
Shies away from commitment
~2012 by Tobias Koppers
Webpack 1.0
Webpack >=2.0
<script src="scripts/bundle.js"></script>
Using Webpack
DeathStar.html
require("./style.css");
var superLaser = require("SuperLaser");
superLaser.destroyPlanet("Alderaan");
DeathStar.js
@opherv
import styles from "./style.css";
import superLaser from "./SuperLaser";
superLaser.destroyPlanet("Alderaan");
DeathStar.js ES6 (for cool kids)
//dependencies
import beamCrystal from 'BeamCrystal'
...
// private function
function prepareLaser(){
}
// public function
function destroyPlanet(planet){
prepareLaser(beamCrystal);
laser.fire(planet);
}
// exposed public object
export default {
destroyPlanet: destroyPlanet
}
Anatomy of an ES6 Module
SuperLaser.js
@opherv
Building with Webpack
webpack
run
module.exports = {
entry: "./DeathStar.js",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
}
};
webpack.config.js
bundle.js
-- compiled code --
@opherv
Webpack Code Splitting
require.ensure(["SuperLaser"], function(require) {
var superLaser = require("SuperLaser");
superLaser.destroyPlanet("Alderaan");
});
DeathStar.js
webpack
run
bundle.js / bundle.1.js / bundles.2.js ....
@opherv
import('SuperLaser').then(function(SuperLaser) {
superLaser.destroyPlanet("Alderaan");
}).catch(function(err) {
console.log('SuperLaser Malfunction!', err);
});
Static Analysis
@opherv
Webpack - advantages
Loads AMD, CommonJS and ES6
Sync and Async loading
Automatic bundle splitting
Static Analysis
Imports assets (CSS/Images/whatever)
@opherv
Tree Shaking (Webpack >=2.0)
Webpack - disadvantages
Can't load non-webpacked bundles
Documentation feels like it was google-translated from a wiki page in Japanese
(docs on v>=2 are much much better!)
More complex to setup
@opherv
@opherv on Twitter. It is your destiny.
GIVEAWAY TIME
typeof NaN ==
"number"
New to the story
SystemJS
Comes with something that handles packages
Doesn't need your help
~2013 by Guy Bedford
HTTP/2 | SPDY
HTTP/1
@opherv
<script src="https://jspm.io/system.js"></script>
<script>
System.import("github:DarthVader/SuperLaser").then(function(SuperLaser) {
SuperLaser.destroyPlanet("Alderaan");
});
</script>
Using SystemJS
DeathStar.html
jpsm.io CDN allows you to use jspm, github and npm sources
Sources are sent minified over HTTP/2
@opherv
<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
System.import('DeathStar.js');
</script>
Using SystemJS
DeathStar.html
jspm install
run
creates config.js and jspm_packages/system.js
You have the option of bundling, code splitting or using an HTTP/2 CDN
@opherv
SystemJS - advantages
Potentially performant with no bundling needed!
No bundling - no bundle management issues
Can still bundle using JSPM Builder
Load directly from jspm.io/npm/Github
@opherv
Tree shaking (with rollup)
a
SystemJS - disadvantages
Using two package managers (kinda)
Might rely on a polyfill (es6-module-loader)
Requires HTTP/2 support in the browser/server
Requires deeper understanding of packaging/bundling
@opherv
A tiny reminder
I could not possibly cover all features and caveats
Eventually, all of these are tools that get the job done
Pick whatever YOU think is right, and makes you happy
@opherv
Don't be afraid of learning
Title Text
Thanks!
@OpherV
opherv.com
PackWars: JS Distribution in a galaxy far, far away | FrontEnd.IL
By Opher Vishnia
PackWars: JS Distribution in a galaxy far, far away | FrontEnd.IL
- 1,521