Wrapping your js

Making your scripts digestible for the browser

Maurizio Lupo (@sithmel)

Global namespace

Browser Javascript

Different scripts communicate using the

wrap the scope using a closure, but only within the same script

Browser Javascript

Javascript allows to

It is not always updated

(we currently support es5)

Browser Javascript

Browser Javascript

Issues:

Polluting global scope

Bundle more modules together

Provide old browser compatibility

Bundling

First solution: wrap a group of scripts within a closure

(function () {

  ... script1 ...

  ... script2 ...

  ... script3 ...

  ...

}());

Bundling

AMD

define('react', function () {
 ...
 return react;
});

define('jquery', function () {
 ...
 return $;
});

define('myapp', ['jquery', 'react'], function ($, react) {
 ...
});

Can run natively in the browser (horribly slow)

To fix performance uses bundling step

Bundling

commonjs

--- react.js
...
module.exports = react;

--- file jquery.js
...
module.exports = jquery;

--- file app.js
var jquery = require('jquery');
var react = require('react');
...

Can't run natively in the browser

Rely on a bundling step

Cross compatible with node.js

Bundling

commonjs

var _get = require('lodash/get');

Allows to cherry pick what you need!

Please do not import a gorilla to get a banana

Bundling

ES2015 modules

--- react.js
...
export default react;

--- file jquery.js
...
export default jquery;

--- file app.js
import jquery from 'jquery';
import react from 'react';
...

Can't run natively in the browser

Rely on a bundling step

Can be transpiled to common.js

Its semantic allows "treeshaking" (with webpack 2 and rollup)

How it works: Browserify

A loader is inserted in each bundle

Every module is wrapped within a closure

If a module rely on any node.js feature, this is added: __dirname, process, buffer etc.

Compatible with commonjs: ES2015 must be converted by babel

How it works: Browserify

The module is happended to a object

The keys of the object are the name or path in the require

if you use the "fullPath" option the keys are absolute paths (very bad)

If you use the bundle-collapser module keys are converted in integers

How it works: Browserify

if you use the "debug" option, sourcemaps are appended to the file

How it works: Webpack 2

A loader is inserted in each bundle

Every module is wrapped within a closure

If a module rely on any node.js feature, this is added: __dirname, process, buffer etc.

Compatible with AMD, commonjs, ES2015

How it works: Webpack 2

Modules are happended to a object

The keys of the object is a number

Any non js require is treated accordingly to its loader

How it works: Webpack 2

Using ES2015 imports, unused modules are stripped (treeshaking)

But you have to configure babel to not transpile es2015 modules:

presets: [['es2015', {modules: false}], 'react']

How it works: Webpack 2

What about third party modules?

You have to add the module field to the package.json

{
  "name": "my-package",
  "version": "0.1.0",
  "main": "dist/my-package.umd.js",
  "module": "dist/my-package.es2015.js"
}

How it works: Rollup

No loader required

No closures, it renames conflicting variables

If a module rely on any node.js feature, this is added: __dirname, process, buffer etc. (work in progress)

A bit immature but:

Treeshaking is similar to webpack

It uses ES2015 natively and requires a plugin for commonjs

Second part: transpilation

Babel

Transpilation

const a = 10;

To

From

var a = 10;

It only requires the appropriate preset

For ES use babel-preset-env

Babel

Polyfilling

babel-polyfill.js

It includes:

polyfills in the global namespace

Regenerator runtime: used in conjunction with transpiled generators

It throws an exception if imported more than once and it is massive!!!

Babel

Polyfilling

runtime-transform

It is a plugin and includes:

polyfills in the private namespace (core-js)

Regenerator runtime: used in conjunction with transpiled generators

It doesn't include polyfills for existing built-ins: .includes .contains etc.

Babel

Polyfilling

core-js

It is a collection of polyfills, they can be cherry picked

regenerator-runtime

for using generators

Babel

babel-preset-env has a plugin to automatically import individual corejs imports as required by target environment!

Always check what you are importing:

  • does it need a global polyfill? (axios)
  • does it need transpiling?

Be careful to import a module designed for the server:

  • does it uses commonjs or es2015?
  • does it need transpiling?
  • is it importing more than necessary?

Checklist

Thanks!

Wrapping your js

By Maurizio Lupo

Wrapping your js

Making your script digestible for the browser

  • 461