+ - 0:00:00
Notes for current slide
  • Who thinks that frontend development has become more complex in the past 5 years?
Notes for next slide
  • People will remember the year of 2015 as the year of the JavaScript Fatigue
1 / 105
  • Who thinks that frontend development has become more complex in the past 5 years?

2015 was the year of
»JavaScript Fatigue«

2 / 105
  • People will remember the year of 2015 as the year of the JavaScript Fatigue
3 / 105
  • Excellent article by Eric Clemmons
  • Published in Dec 2015
  • About the explosion of libraries and tools in the JavaScript ecosystem
   
Custom languages
Linters
Bundlers
Minifiers
Devtools
Task runners
DOM libraries
Routing libraries
State libraries
Package managers
4 / 105

This was in the end of 2015...

5 / 105

This was in the end of 2015...

...but now it's 2016, so we're in the future, right?

6 / 105

Support of new web platform features
in modern browsers1

   

HTTP2

69%

ES2015

67%

Web Components

44%
  1. HTTP2 from caniuse.com, ES2015 from kangax.github.io, Web Components from webcomponents.org.
    All data was collected in July 2016. Please note: Only the most recent version of a browser was taken into account. This does not reflect the actual global distribution. Please note also: The Web Components specs have not been finished yet.
7 / 105
  • There are exciting new features
  • And browser support is getting better
  • How do these new features change the way we work?
  • Will we even need those tools at all?
  • That's the topic of my talk:

About the future
of frontend tooling

Johannes Ewald
Peerigon GmbH
@jhnnns

8 / 105
  • Johannes Ewald
  • Founded a company with my friends called Peerigon
  • Twitter handle: jhnnns

webpack core team

9 / 105

ES2015 modules

10 / 105
ES2015
a.js
export default 42;
main.js
import magicNumber from "./a.js";
11 / 105
ES2015
a.js
export default 42;
main.js
import magicNumber from "./a.js";
CommonJS
a.js
module.exports = 42;
main.js
const magicNumber = require("./a.js");
12 / 105

ES2015 and CommonJS look very similar, but there are two important differences.

13 / 105
CommonJS
Dynamic imports possible
const a = require(pathToA);
// totally valid
ES2015
Only static imports
import a from pathToA;
// throws a SyntaxError
14 / 105
CommonJS
Copied values
a.js
exports.value = 42;
exports.incr = function () {
exports.value++;
};
main.js
let { value, incr } = require("./a");
incr();
console.log(value); // 42
ES2015
Live values
a.js
export let value = 42;
export function incr() {
value++;
}
main.js
import { value, incr } from "./a.js";
incr();
console.log(value); // 43
15 / 105

These properties make ES2015 modules less flexible than CommonJS...

16 / 105

These properties make ES2015 modules less flexible than CommonJS...

...but they're also the foundation for: Tree-shaking

17 / 105
Tree-shaking with ES2015
a.js
export let value = 42;
export function incr() {
value++;
}
export function decr() {
value++;
}
main.js
import { incr } from "./a.js";
incr();
18 / 105
Tree-shaking with ES2015
a.js
let value = 42;
export function incr() {
value++;
}
main.js
import { incr } from "./a.js";
incr();
19 / 105

The static nature of ES2015 modules makes it possible
to trace all the exports that are actually used.

20 / 105

But...

...with a static module system, how do we load things on demand?

( ☉д⊙)

21 / 105

System.import() all the things!

22 / 105

There will be a way to load modules asynchronously:

System.import("some-module")
.then(someModule => {
...
})
.catch(error => {
...
});
23 / 105

But... things aren't finalized yet.

24 / 105

System.import() is very platform-specific and
many things need to be considered.

25 / 105

System.import() is very platform-specific and
many things need to be considered.

That's why it has been excluded from ES2015 and
will be specified as separate "Loader Standard".

26 / 105

So...

...once we can load modules natively in the browser,
do we need tools like browserify and webpack anymore?

ಠಿ_ಠ

27 / 105

Well...

...to answer this question, we should take
a look at another new technology first.

28 / 105

HTTP2

29 / 105
  • I won't talk about all the features of HTTP2 like header compression
  • Just the ones that might have a big impact on our tools

Feature 1:
HTTP2 is a binary protocol

30 / 105

Requests and responses are streams.

31 / 105

Streams are divided into frames.

32 / 105

Frames can be interleaved.

33 / 105

Now we have multiple requests and responses simultaneously on a single TCP connection.

34 / 105

This eliminates HTTP1's problem of head-of-line blocking....
...and questions some of our best practices, like:

  • Bundling multiple resources into one file to avoid requests
  • Domain sharding
35 / 105
  • Head-of-line blocking = With HTTP 1.x we must wait for a response before sending the next request

Great!

So, let's get rid of all the bundlers and just include our development files.

(ノಠ益ಠ)ノ彡┻━┻

36 / 105

...not so fast...

(ヘ・_・)ヘ┳━┳

37 / 105

Problem 1:
Tree-shaking

When there are no bundlers, who is doing the tree-shaking?
We still need a tool that operates on the dependency graph.
38 / 105

Problem 2:
Minification

We still need a tool for HTML, CSS and JS minification.
39 / 105

Problem 3:
Compression

gzip compression is good at removing repetition.
It compresses one big file more effectively than many small files.

See also http://engineering.khanacademy.org/posts/js-packaging-http2.htm

40 / 105

Problem 4:
Roundtrip

The browser can only discover additional dependencies after
the response has been received and parsed.
41 / 105

42 / 105
  • Similar to head-of-line blocking
  • AKA: The AMD problem
  • Server push to the rescue

[Roundtrip Schaubild]

Feature 2:
Server push

43 / 105

With HTTP2 the server is able to push a resource pro-actively to the client.
Now, when the client requests this resource, it becomes instantly available and cached.

44 / 105
  • Server: "I've just sent you index.html, you'll likely also need styles.css and user.jpg"
  • The resources are not directly cached, the client needs to make a request for it

What do we need to provide server push?

45 / 105

A dependency tree for each file:

index.html
{
"/css/app.css": {
"type": "style",
"weight": 1
},
"/js/app.js": {
"type": "script",
"weight": 1
}
}

Google's Push Manifest Proposal

46 / 105

A dependency tree for each file:

index.html
{
"/css/app.css": {
"type": "style",
"weight": 1
},
"/js/app.js": {
"type": "script",
"weight": 1
}
}
app.css
{
"/img/logo.jpg": {
"type": "image",
"weight": 1
}
}

Google's Push Manifest Proposal

47 / 105

How do we get this dependency tree?

48 / 105

How do we get this dependency tree?

  • traffic analysis using the Referer header
  • tools like bundlers which are able to figure out the dependency graph
49 / 105

Great!

So, let's figure out the dependency graph and push everything to the client.

(ノಠ益ಠ)ノ彡┻━┻

50 / 105

...not so fast...

(ヘ・_・)ヘ┳━┳

51 / 105

Problem 1:
Responsive images

We need information about the client because we don't want to
push high-resolution images to small screens.
52 / 105

Problem 2:
Cache

We need to know what the client has already cached,
otherwise we would waste precious bandwidth.

Proposed solution: Cache digests

53 / 105

Problem 3:
Authorization

Don't push confidential resources to the client.
Push basically requires the same authorization flow as requests.
54 / 105

Problem 4:
Third-party servers

Resources from other servers like CDNs
cannot be pushed because we need an initial request.
55 / 105

Problem 5:
Prioritization

Pushing resources with no prioritization actually harms performance.

See https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/preview

56 / 105
<head>
<link href="main.css" ...>
</head>
<body>
<img src="heavy-image-1.jpg">
<img src="heavy-image-2.jpg">
</body>
  • CSS and fonts are render-blocking
  • Images are not
  • Wasting bandwidth on non render-blocking
    resources harms perceived performance
57 / 105

HTTP2 provides a way to:

  • weigh each stream
  • pause, resume and cancel a stream
58 / 105
  • Weigh: "CSS and fonts are way more important than images"
  • Pause and resume: "Just get the image geometry and a small preview first"
  • Cancel: "Already in cache" (but some data has already been sent)

But a "good implementation" that takes everything
into account is very challenging and complex.

59 / 105

With HTTP1, head-of-line blocking actually prevented this kind of wrong prioritization.
We just needed to reference all the assets plus some meta data (like image dimensions) in the intended order.

<head>
<link href="main.css" ...>
<style>
@font-face {
font-family: "MyWebFont";
src: url("myfont.woff2") format("woff2");
}
</style>
</head>
<body>
<img width="1200" height="1000" src="heavy-image-1.jpg">
<img width="1800" height="700" src="heavy-image-2.jpg">
</body>
60 / 105

Web Components

61 / 105

The vision

62 / 105

You can think of Web Components as reusable user interface widgets that are created using open Web technology. They are part of the browser, and so they do not need external libraries like jQuery or Dojo. An existing Web Component can be used without writing code, simply by adding an import statement to an HTML page. https://developer.mozilla.org/en-US/docs/Web/Web_Components

63 / 105

Actually, web components is a fuzzy term
because it refers to 4 different technologies:

  • HTML templates
  • Custom elements
  • Shadow DOM
  • HTML imports
64 / 105

Custom elements, HTML imports and the shadow DOM have already gone
through several revisions which makes finding up-to-date information difficult.

65 / 105

Mozilla and Microsoft even decided to pause development on
HTML imports entirely until the ES loader spec has been finished.

66 / 105

HTML templates

Provide a way to define HTML fragments
that are parsed but not interpreted.
67 / 105
<template id="my-template">
<style>
/* this is not scoped! */
h1 { color: red; }
</style>
<h1>My Template!</h1>
<img src="some-img.jpg" />
<script>
function annoyUser(){
alert("My template is ready!");
}
annoyUser();
</script>
</template>

Templates are inert which means that by default:

  • no markup is displayed
  • no styles are applied
  • no images are loaded
  • no JavaScript is executed
  • the inner contents are invisible to selectors

template.content exposes the content as DocumentFragment which can be imported to get real DOM nodes.

68 / 105

Custom elements

A JavaScript API to register a custom implementation for arbitrary elements.
69 / 105
Current draft

Provides element lifecycle hooks:

class MyButton extends HTMLButtonElement {
constructor() { ... }
connectedCallback() { ... }
disconnectedCallback() { ... }
attributeChangedCallback() { ... }
}
customElements.define("my-button", MyButton);
<my-button></my-button>
70 / 105
Current draft

It is also possible to customize built-in tags:

customElements.define("my-button", MyButton, {
extends: "button"
});
<button is="my-button"></button>
71 / 105

Shadow DOM

Encapsulates and hides elements, styles and events behind a single element.
It also describes how content of the document tree is "transcluded" into the shadow tree.
72 / 105
  • The "heart" of the web components
Current draft
<template id="article-template">
<header>
<slot name="headline"></slot>
</header>
<div>
<slot></slot>
</div>
</template>
<article>
<h2 slot="headline">My Headline</h2>
<p>First paragraph</p>
<p>Second paragraph</p>
</article>
const articles = document
.querySelectorAll("article");
for (const article of articles) {
const root = article.attachShadow({
mode: "open"
});
const shadowTree = document
.importNode(template.content, true);
root.appendChild(shadowTree);
}
73 / 105
  • Children of the shadow host are projected into the slots of the shadow tree

HTML imports

Import other HTML documents into the current one,
including all the templates, styles and scripts.
74 / 105
Current draft
<head>
<link rel="import" href="blog-post.html">
</head>
<body>
...
<script>
const link = document.querySelector('link[rel="import"]');
const post = link.import.querySelector("#blog-post");
document.body.appendChild(post.cloneNode(true));
</script>
</body>
  • Imported styles are applied on the importing document
  • Imported scripts are executed in the importing document's context
  • Imported HTML needs to be appended to the DOM via JavaScript
75 / 105

Great!

Let's get rid of all the frameworks and just write native web components.

(ノಠ益ಠ)ノ彡┻━┻

76 / 105

...not so fast...

(ヘ・_・)ヘ┳━┳

77 / 105

Problem 1:
Data flow

With web components, data is usually provided as
strings via attributes on the shadow host.

This may work for simple components, but not for
more complex ones like higher-order components.

<!-- do we want to write that? -->
<inbox mails="[{ subject: &​quot;Hi there!&​quot;... }]"></inbox>
78 / 105

Problem 2:
Imperative

Web components don't offer a declarative way to
describe DOM manipulations.

Do we really want to go back to manual DOM manipulation?

79 / 105

Problem 3:
Self-contained

While encapsulation is a good thing, true self-contained
web components from different sources may not be desirable.

Or do we like to end up with multiple versions of React,
Angular and Ember.js on the same page?

80 / 105

Problem 4:
Global namespace

With HTML imports, the mistakes of the past are repeated since all the
styles and scripts are just imported into the global namespace.
81 / 105

Problem 5:
Flash of unstyled content

If we fail to deliver the implementation of a custom element fast enough,
the browser will display the custom element as HTMLUnknownElement.
82 / 105

Problem 6:
No progressive enhancement

Web components are defined via JavaScript.
If something goes wrong, our web app will be broken.

This is also true for all SPA frameworks. With universal JavaScript,
however, we can always fall back to server-side rendering.
83 / 105

Conclusion

84 / 105
  • This is biased
  • Based on my personal experience

Will ES2015 modules
change the way we work?

85 / 105

Yes

  • finally a universal module format for JavaScript
  • avoids typical problems like namespace conflicts
  • enables tree-shaking through static analysis
  • encapsulates platform semantics in loader implementations
86 / 105

Will HTTP2 change
the way we work?

87 / 105

Yes

  • binary streams invalidate former best-practices
  • we have a more fine-grained control over optimization
  • server push provides a new way to deliver resources separately
88 / 105

But...

...in order to leverage streams and server push, we need:

  • to weigh and control these streams
  • sophisticated server implementations
  • tools that feed these servers with valuable information about our web app
  • careful and automated testing

And when it doubt, we should stick to old best-practices where appropriate.

89 / 105
  • Valuable information like: Which resources are render-blocking?

Will web components change
the way we work?

90 / 105

Yes

  • they provide new DOM primitives for future frameworks
  • they make the platform itself more customizable
91 / 105

But...

  • they don't provide tools to actually compose a more complex web app
  • they don't provide ways to deliver these components efficiently
  • they can also make the platform more fragile
92 / 105

How will frontend development look
like in the next years?

93 / 105

We will use...

94 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
95 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
96 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
97 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
  • ...and to allow static analysis
98 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
  • ...and to allow static analysis
  • ...languages like JSX that embed other languages into ES2015 modules
99 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
  • ...and to allow static analysis
  • ...languages like JSX that embed other languages into ES2015 modules
  • ...bundlers that compose ES2015 modules
100 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
  • ...and to allow static analysis
  • ...languages like JSX that embed other languages into ES2015 modules
  • ...bundlers that compose ES2015 modules
  • ...and "tree-shake" unused parts
101 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
  • ...and to allow static analysis
  • ...languages like JSX that embed other languages into ES2015 modules
  • ...bundlers that compose ES2015 modules
  • ...and "tree-shake" unused parts
  • ...tools that analyze the critical rendering-path
102 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
  • ...and to allow static analysis
  • ...languages like JSX that embed other languages into ES2015 modules
  • ...bundlers that compose ES2015 modules
  • ...and "tree-shake" unused parts
  • ...tools that analyze the critical rendering-path
  • ...and optimize for the first meaningful paint
103 / 105

We will use...

  • ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs1...
    1. Abstract Syntax Tree
  • ...and provide plugins and presets
  • ...languages with explicit exports/imports to avoid namespace collisions
  • ...and to allow static analysis
  • ...languages like JSX that embed other languages into ES2015 modules
  • ...bundlers that compose ES2015 modules
  • ...and "tree-shake" unused parts
  • ...tools that analyze the critical rendering-path
  • ...and optimize for the first meaningful paint
  • ...server-side rendering as fallback strategy
104 / 105

─=≡Σ((( つ•̀ω•́)つLET’SGO!

105 / 105

2015 was the year of
»JavaScript Fatigue«

2 / 105
  • People will remember the year of 2015 as the year of the JavaScript Fatigue
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
b Toggle blackout mode
f Toggle fullscreen mode
c Clone slideshow
p Toggle presenter mode
w Pause/Resume the presentation
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow