Slide 1

Slide 1 text

Building Modern, Modular JavaScript Applications Netcentric Summit 2016

Slide 2

Slide 2 text

Erik Grijzen Senior Frontend Developer @ Netcentric @ErikGrijzen www.erikgrijzen.com

Slide 3

Slide 3 text

What is a module?

Slide 4

Slide 4 text

Single purpose Do one thing and do one thing well - Unix philosophy

Slide 5

Slide 5 text

It can live on it’s own. Independent

Slide 6

Slide 6 text

Self contained Encapsulated private implementation.

Slide 7

Slide 7 text

Public interface Exposes functionality for others to consume.

Slide 8

Slide 8 text

Interchangeable Plug and play.

Slide 9

Slide 9 text

Why do we need to write modular code?

Slide 10

Slide 10 text

The rise of Web Apps Increasing frontend code complexity.

Slide 11

Slide 11 text

Better reusability Don’t reinvent the wheel.

Slide 12

Slide 12 text

Copying code Project A Project B js

Slide 13

Slide 13 text

Better maintainability Updating a small, self-contained and independent module is much easier.

Slide 14

Slide 14 text

Better testability Testing a small, self-contained and independent module is much easier.

Slide 15

Slide 15 text

The global namespace Global namespace pollution and naming conflicts.

Slide 16

Slide 16 text

Improved dependency management More explicit control over your dependencies.

Slide 17

Slide 17 text

Script tag vomit

Slide 18

Slide 18 text

Updating external libraries

Slide 19

Slide 19 text

Included third party libraries into source control

Slide 20

Slide 20 text

Optimized deployment An easy way to deploy your code.

Slide 21

Slide 21 text

Libraries where you don’t use all its functionality

Slide 22

Slide 22 text

Manual custom builds

Slide 23

Slide 23 text

Modules allow us to build more complex, large-scale and robust applications.

Slide 24

Slide 24 text

The evolution of JavaScript modules

Slide 25

Slide 25 text

Grouping code var myApp = window.myApp || {}; myApp.myModule = { init: function() { ... } }; myApp.myModule.init();

Slide 26

Slide 26 text

(function(){ // Private scope })(); Encapsulation

Slide 27

Slide 27 text

(function($) { // Global import })(jQuery); Encapsulation

Slide 28

Slide 28 text

var Counter = (function () { var counter = 0; function increment() { counter++; } return { increment: increment, }; })(); Counter.increment(); Exposing a public interface

Slide 29

Slide 29 text

var Counter = (function () { var counter = 0; function increment() { counter++; } return { increment: increment, }; })(); Counter.increment(); Exposing a public interface Private implementation

Slide 30

Slide 30 text

var Counter = (function () { var counter = 0; function increment() { counter++; } return { increment: increment, }; })(); Counter.increment(); Exposing a public interface Public interface Private implementation

Slide 31

Slide 31 text

// counter.js var counter = 0; function increment(){ counter++; } module.exports = { increment: increment } CommonJS

Slide 32

Slide 32 text

// counter.js var counter = 0; function increment(){ counter++; } module.exports = { increment: increment } CommonJS // main.js var counter = require("./counter.js"); counter.increment();

Slide 33

Slide 33 text

CommonJS ● Standard for NodeJS ● Synchronous ● Build step required for browser support

Slide 34

Slide 34 text

// counter.js define('counter', function() { var counter = 0; function increment() { counter++; } return { increment: increment }; }); Asynchronous Module Definition (AMD)

Slide 35

Slide 35 text

// counter.js define('counter', function() { var counter = 0; function increment() { counter++; } return { increment: increment }; }); Asynchronous Module Definition (AMD) // main.js define('main', ['counter'], function(counter) { counter.increment(); });

Slide 36

Slide 36 text

AMD ● Mostly for browsers ● Asynchronous ● No build step ● Lazy loading

Slide 37

Slide 37 text

Module system fragmentation.

Slide 38

Slide 38 text

Supporting all module formats.

Slide 39

Slide 39 text

(function (root, factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.returnExports = factory(); } }(this, function () { var counter = 0; return { increment: function() { counter++; }; } })); Universal Module Definition (UMD)

Slide 40

Slide 40 text

(function (root, factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.returnExports = factory(); } }(this, function () { var counter = 0; return { increment: function() { counter++; }; } })); Universal Module Definition (UMD) AMD

Slide 41

Slide 41 text

(function (root, factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.returnExports = factory(); } }(this, function () { var counter = 0; return { increment: function() { counter++; }; } })); Universal Module Definition (UMD) AMD CJS

Slide 42

Slide 42 text

(function (root, factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.returnExports = factory(); } }(this, function () { var counter = 0; return { increment: function() { counter++; }; } })); Universal Module Definition (UMD) AMD CJS Global

Slide 43

Slide 43 text

(function (root, factory) { if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.returnExports = factory(); } }(this, function () { var counter = 0; return { increment: function() { counter++; }; } })); Universal Module Definition (UMD) AMD CJS Global Module

Slide 44

Slide 44 text

There must be a better way!

Slide 45

Slide 45 text

A new way of writing JavaScript code.

Slide 46

Slide 46 text

ES2015 Modules

Slide 47

Slide 47 text

Modules are stored in files. JS

Slide 48

Slide 48 text

Code is executed once it’s loaded.

Slide 49

Slide 49 text

All code stays local to the module.

Slide 50

Slide 50 text

Modules can import functionality.

Slide 51

Slide 51 text

Modules can export functionality.

Slide 52

Slide 52 text

One module per file.

Slide 53

Slide 53 text

One file per module.

Slide 54

Slide 54 text

Modules are singletons.

Slide 55

Slide 55 text

A brief overview of the ES2015 module syntax

Slide 56

Slide 56 text

Import & Export

Slide 57

Slide 57 text

// counter.js var counter = 0; function increment() { return counter++; } function reset() { counter = 0; } Multiple named exports

Slide 58

Slide 58 text

// counter.js var counter = 0; export function increment() { return counter++; } export function reset() { counter = 0; } Multiple named exports

Slide 59

Slide 59 text

// counter.js var counter = 0; export function increment() { return counter++; } export function reset() { counter = 0; } Named import // app.js import { increment } from 'counter'; increment(); // 1

Slide 60

Slide 60 text

// counter.js var counter = 0; export function increment() { return counter++; } export function reset() { counter = 0; } Namespace import // app.js import * as counter from 'counter'; counter.increment(); // 1 counter.reset(); // 0

Slide 61

Slide 61 text

// func.js export default function() { ··· } Single default export

Slide 62

Slide 62 text

// func.js export default function() { ··· } Default import // app.js import myFunc from 'func'; myFunc();

Slide 63

Slide 63 text

Benefits over CJS and AMD? ● Cleaner syntax ● Sync and async ● Multiple exports ● Cyclic dependencies ● Static module structure

Slide 64

Slide 64 text

Static module structure

Slide 65

Slide 65 text

// Error if (someBooleanValue) { import myModule from 'module1'; } else { import myModule from 'module2'; } Static imports & exports

Slide 66

Slide 66 text

Benefits of a static module structure? ● Dead code elimination ● Variable checking ● Type checking

Slide 67

Slide 67 text

Module syntax IDE support

Slide 68

Slide 68 text

Browser support:

Slide 69

Slide 69 text

What now?!?

Slide 70

Slide 70 text

Instead of waiting on browser adoption...

Slide 71

Slide 71 text

Transpiler allow us to use the future syntax today!

Slide 72

Slide 72 text

What are transpilers?

Slide 73

Slide 73 text

ES2015 ES5 compile

Slide 74

Slide 74 text

ES2015 ES5 compile CommonJS

Slide 75

Slide 75 text

ES2015 ES5 compile AMD

Slide 76

Slide 76 text

ES2015 ES5 compile Other

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

Module Loader API

Slide 79

Slide 79 text

Module Loader API (not part of ES2015)

Slide 80

Slide 80 text

System.import('counter') .then(function(counter) { counter.increment(); }) .catch(function() { ··· }); Loader API

Slide 81

Slide 81 text

JS JS JS JS JS JS JS Module Loader JS

Slide 82

Slide 82 text

In the future HTTP/2 will be able to load all modules asynchronously in production.

Slide 83

Slide 83 text

Until then, we have to bundle our modules into one single file.

Slide 84

Slide 84 text

Module bundling.

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

Modern module bundlers have a transpiler built-in.

Slide 87

Slide 87 text

How does bundling work?

Slide 88

Slide 88 text

Traversing the dependency tree. main.js bundle.js JS JS JS JS JS JS JS

Slide 89

Slide 89 text

Mixing different module systems. main.js bundle.js AMD CJS ES2015 JS JS JS JS

Slide 90

Slide 90 text

Easy code splitting for lazy loading. bundle1.js AMD CJS ES2015 bundle2.js bundle3.js JS JS JS JS

Slide 91

Slide 91 text

Bundling common code together. bundle1.js AMD CJS ES2015 bundle2.js bundle3.js common.js JS JS JS JS

Slide 92

Slide 92 text

Tree-shaking

Slide 93

Slide 93 text

Normal bundling behavior. counter.js increment() { … } reset() { … }

Slide 94

Slide 94 text

Normal bundling behavior. import { increment } from ‘counter’; increment(); counter.js main.js increment() { … } reset() { … }

Slide 95

Slide 95 text

Normal bundling behavior. counter.js increment() { … } reset() { … } import { increment } from ‘counter’; increment(); main.js bundle.js increment() { … } reset() { … } increment();

Slide 96

Slide 96 text

Removing unused exports. counter.js increment() { … } reset() { … } import { increment } from ‘counter’; increment(); main.js bundle.js increment() { … } reset() { … } increment();

Slide 97

Slide 97 text

Removing unused exports. import { increment } from ‘counter’; increment(); counter.js main.js bundle.js increment() { … } reset() { … } increment() { … } increment();

Slide 98

Slide 98 text

Modularization

Slide 99

Slide 99 text

Third party modules.

Slide 100

Slide 100 text

Package Managers

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

NPM - The biggest package manager on earth!

Slide 103

Slide 103 text

www.modulecounts.com

Slide 104

Slide 104 text

What is a package?

Slide 105

Slide 105 text

A folder containing a program. Package index.js

Slide 106

Slide 106 text

This program is described by a package.json file. Package index.js package.json

Slide 107

Slide 107 text

{ "name": "test-package", "version": "1.0.0", "main": "index.js", "repository": { "type": "git", "url": "git+https://github.com/..." }, "author": "Erik Grijzen" } package.json

Slide 108

Slide 108 text

Ideal workflow: Two step approach

Slide 109

Slide 109 text

1). Installing a package. > npm install angular --save Terminal

Slide 110

Slide 110 text

{ "name": "test-package", "version": "1.0.0", "main": "index.js", "dependencies": { "angular": "1.4.9", }, "author": "Erik Grijzen" } package.json

Slide 111

Slide 111 text

2). Import a package. import angular from 'angular'; index.js

Slide 112

Slide 112 text

Package installation folder. Package /node_modules index.js package.json

Slide 113

Slide 113 text

Excluding installed packages from source control. Package /node_modules index.js package.json .gitignore

Slide 114

Slide 114 text

Semantic versioning.

Slide 115

Slide 115 text

1.0.0 Published packages Not everyone is following this rule

Slide 116

Slide 116 text

1.0.1 Patch release Bug fixes and patches.

Slide 117

Slide 117 text

1.2.0 Minor release New features that don’t break existing features.

Slide 118

Slide 118 text

2.0.0 Major release Changes that break backwards compatibility.

Slide 119

Slide 119 text

Useful version ranges.

Slide 120

Slide 120 text

~1.0.0 Installs: 1.0.8 Automatic bugfix updates.

Slide 121

Slide 121 text

^1.0.0 Installs: 1.4.9 Automatic bugfix and feature updates.

Slide 122

Slide 122 text

Don’t blindly trust all published packages.

Slide 123

Slide 123 text

Modern component-based architecture

Slide 124

Slide 124 text

Most modern frameworks support component-based development.

Slide 125

Slide 125 text

Composing your application into smaller components. Component

Slide 126

Slide 126 text

Modularized components.

Slide 127

Slide 127 text

Component

Slide 128

Slide 128 text

One entry point. JS

Slide 129

Slide 129 text

Importing other assets. JS HTML CSS PNG JS

Slide 130

Slide 130 text

Importing other assets. JS JADE SCSS PNG JS

Slide 131

Slide 131 text

Component-based project structure

Slide 132

Slide 132 text

Self-contained components. Component component.js component.css component.html component.test.js image.png

Slide 133

Slide 133 text

import styles from './component.css'; import template from './component.html'; import image from './logo.png'; var img = document.createElement('img'); img.src = image; Importing other assets

Slide 134

Slide 134 text

Inlining all static assets. Component Component Component Component bundle.js

Slide 135

Slide 135 text

Create separate bundles. Component Component Component Component bundle.js bundle.css logo.png

Slide 136

Slide 136 text

Creating common bundles. Component Component Component Component bundle.js bundle.css logo.png common.css

Slide 137

Slide 137 text

Easily removing components. Component Component Component Component bundle.js bundle.css

Slide 138

Slide 138 text

Easily removing components. Component Component Component bundle.js bundle.css

Slide 139

Slide 139 text

Developer experience

Slide 140

Slide 140 text

We are all familiar with browser syncing.

Slide 141

Slide 141 text

What about module syncing?

Slide 142

Slide 142 text

Hot module loaders

Slide 143

Slide 143 text

Live editing experience.

Slide 144

Slide 144 text

Frameworks and libraries are moving to ES2015.

Slide 145

Slide 145 text

Focus on learning the new JavaScript standards.

Slide 146

Slide 146 text

The future is bright, let’s start using ES2015 today!

Slide 147

Slide 147 text

Thank you! Senior Frontend Developer @ Netcentric @ErikGrijzen www.erikgrijzen.com