layout: true class: slides-centered --- class: theme-whiskey ??? - Who thinks that frontend development has become more complex in the past 5 years? --- class: slides-chapter, theme-whiskey ## 2015 was the year of
»JavaScript Fatigue« ??? - People will remember the year of 2015 as the year of the JavaScript Fatigue --- .slides-content[
] ??? - Excellent article by Eric Clemmons - Published in Dec 2015 - About the explosion of libraries and tools in the JavaScript ecosystem --- .slides-content[ | ------:|------- Custom languages |
Linters |
Bundlers |
Minifiers |
Devtools |
Task runners |
DOM libraries |
Routing libraries |
State libraries |
Package managers |
] --- This was in the end of 2015... -- ### ...but now it's 2016, so we're in the future, right? --- .slides-content[ Support of new web platform features
in modern browsers.slides-footnote-mark[1] | :-------|:----------------
HTTP2
| 69%
ES2015
| 67%
Web Components
| 44% .slides-footnote[ 1. HTTP2 from [caniuse.com](http://caniuse.com/#feat=http2), ES2015 from [kangax.github.io](http://kangax.github.io/compat-table/es6/), Web Components from [webcomponents.org](http://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. ] ] ??? - 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: --- layout: true class: theme-whiskey, slides-left --- name: cover # About the future
of frontend tooling Johannes Ewald
Peerigon GmbH
[@jhnnns](https://twitter.com/jhnnns)
??? - Johannes Ewald - Founded a company with my friends called Peerigon - Twitter handle: jhnnns --- layout: true class: theme-whiskey, slides-centered --- webpack core team
--- class: slides-chapter, theme-whiskey ## ES2015 modules --- layout: true class: slides-centered, theme-whiskey --- .slides-columns.slides-content[ .col[
ES2015
a.js
```javascript export default 42; ```
main.js
```javascript import magicNumber from "./a.js"; ``` ] ] --- .slides-columns.slides-content[ .col[
ES2015
a.js
```javascript export default 42; ```
main.js
```javascript import magicNumber from "./a.js"; ``` ] .col[
CommonJS
a.js
```javascript module.exports = 42; ```
main.js
```javascript const magicNumber = require("./a.js"); ``` ] ] --- ES2015 and CommonJS look very similar, but there are two important differences. --- .slides-content[ .slides-columns[ .col[
CommonJS
Dynamic imports possible
```javascript const a = require(pathToA); // totally valid ``` ] .col[
ES2015
Only static imports
```javascript import a from pathToA; // throws a SyntaxError ``` ] ] ] --- .slides-content[ .slides-columns[ .col[
CommonJS
Copied values
a.js
```javascript exports.value = 42; exports.incr = function () { exports.value++; }; ```
main.js
```javascript let { value, incr } = require("./a"); incr(); console.log(value); // 42 ``` ] .col[
ES2015
Live values
a.js
```javascript export let value = 42; export function incr() { value++; } ```
main.js
```javascript import { value, incr } from "./a.js"; incr(); console.log(value); // 43 ``` ] ] ] --- These properties make ES2015 modules less flexible than CommonJS... -- ...but they're also the foundation for: **Tree-shaking** --- .slides-content[
Tree-shaking with ES2015
a.js
```javascript export let value = 42; export function incr() { value++; } export function decr() { value++; } ```
main.js
```javascript import { incr } from "./a.js"; incr(); ``` ] --- .slides-content[
Tree-shaking with ES2015
a.js
```javascript let value = 42; export function incr() { value++; } ```
main.js
```javascript import { incr } from "./a.js"; incr(); ``` ] --- The static nature of ES2015 modules makes it possible
to trace all the exports that are actually used. --- layout: true class: slides-chapter, theme-danger --- #### But... ...with a static module system, how do we load things on demand?
( ☉д⊙)
--- layout: true class: slides-centered, theme-whiskey --- `System.import()` all the things!
--- .slides-content[ There will be a way to load modules asynchronously: ```javascript System.import("some-module") .then(someModule => { ... }) .catch(error => { ... }); ``` ] --- **But...** things aren't finalized yet.
--- `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"](https://github.com/whatwg/loader). --- layout: true class: slides-chapter, theme-danger --- #### So... ...once we can load modules natively in the browser,
do we need tools like browserify and webpack anymore?
ಠಿ_ಠ
--- layout: true class: slides-centered, theme-whiskey --- #### Well... ...to answer this question, we should take
a look at another new technology first. --- layout: true class: slides-chapter, theme-whiskey --- ## HTTP2 ??? - 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 --- layout: true class: slides-centered, theme-whiskey --- ### Feature 1:
HTTP2 is a binary protocol --- .slides-content[
Requests and responses are streams. ] --- .slides-content[
Streams are divided into frames. ] --- .slides-content[
Frames can be interleaved. ] --- .slides-content[
Now we have multiple requests and responses simultaneously on a single TCP connection. ] --- 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 ??? - Head-of-line blocking = With HTTP 1.x we must wait for a response before sending the next request --- layout: true class: slides-chapter, theme-danger --- #### Great! So, let's get rid of all the bundlers and just include our development files.
(ノಠ益ಠ)ノ彡┻━┻
--- layout: true class: slides-centered, theme-whiskey --- ...not so fast...
(ヘ・_・)ヘ┳━┳
--- #### Problem 1:
Tree-shaking .slides-content[ When there are no bundlers, who is doing the tree-shaking?
We still need a tool that operates on the dependency graph. ] --- #### Problem 2:
Minification .slides-content[ We still need a tool for HTML, CSS and JS minification. ] --- #### Problem 3:
Compression .slides-content[ `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
] --- #### Problem 4:
Roundtrip .slides-content[ The browser can only discover additional dependencies after
the response has been received and parsed. ] ---
??? - Similar to head-of-line blocking - AKA: The AMD problem - Server push to the rescue [Roundtrip Schaubild] --- ### Feature 2:
Server push --- 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. ??? - 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? --- A dependency tree for each file: .slides-columns[ .col[
index.html
```javascript { "/css/app.css": { "type": "style", "weight": 1 }, "/js/app.js": { "type": "script", "weight": 1 } } ``` ] ]
[Google's Push Manifest Proposal](https://github.com/GoogleChrome/http2-push-manifest)
--- A dependency tree for each file: .slides-columns[ .col[
index.html
```javascript { "/css/app.css": { "type": "style", "weight": 1 }, "/js/app.js": { "type": "script", "weight": 1 } } ``` ] .col[
app.css
```javascript { "/img/logo.jpg": { "type": "image", "weight": 1 } } ``` ] ]
[Google's Push Manifest Proposal](https://github.com/GoogleChrome/http2-push-manifest)
--- 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 --- layout: true class: slides-chapter, theme-danger --- #### Great! So, let's figure out the dependency graph and push everything to the client.
(ノಠ益ಠ)ノ彡┻━┻
--- layout: true class: slides-centered, theme-whiskey --- ...not so fast...
(ヘ・_・)ヘ┳━┳
--- #### Problem 1:
Responsive images .slides-content[ We need information about the client because we don't want to
push high-resolution images to small screens. ] --- #### Problem 2:
Cache .slides-content[ We need to know what the client has already cached,
otherwise we would waste precious bandwidth.
Proposed solution: [Cache digests](https://tools.ietf.org/html/draft-ietf-httpbis-cache-digest-00)
] --- #### Problem 3:
Authorization .slides-content[ Don't push confidential resources to the client.
Push basically requires the same authorization flow as requests. ] --- #### Problem 4:
Third-party servers .slides-content[ Resources from other servers like CDNs
cannot be pushed because we need an initial request. ] --- #### Problem 5:
Prioritization .slides-content[ Pushing resources with no prioritization actually **harms** performance.
See https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/preview
] --- ```html
``` - CSS and fonts are render-blocking - Images are not - Wasting bandwidth on non render-blocking
resources harms perceived performance --- HTTP2 provides a way to: - weigh each stream - pause, resume and cancel a stream ??? - 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. --- 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. ```html
``` --- layout: true class: slides-chapter, theme-whiskey --- ## Web Components --- layout: true class: slides-centered, theme-whiskey --- ### The vision --- class: slides-left > .slides-text-left[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.] .slides-quote-ref[https://developer.mozilla.org/en-US/docs/Web/Web_Components] --- Actually, web components is a fuzzy term
because it refers to 4 different technologies: - HTML templates - Custom elements - Shadow DOM - HTML imports --- Custom elements, HTML imports and the shadow DOM have already gone
through several revisions which makes finding up-to-date information difficult. --- Mozilla and Microsoft even decided to pause development on
HTML imports entirely until the ES loader spec has been finished. --- ### HTML templates .slides-content[ Provide a way to define HTML fragments
that are parsed but not interpreted. ] --- .slides-columns[ ```html
My Template!
``` .col[ 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. ] ] --- ### Custom elements .slides-content[ A JavaScript API to register a custom implementation for arbitrary elements. ] ---
Current draft
.slides-content[ Provides element lifecycle hooks: ```javascript class MyButton extends HTMLButtonElement { constructor() { ... } connectedCallback() { ... } disconnectedCallback() { ... } attributeChangedCallback() { ... } } customElements.define("my-button", MyButton); ``` ```html
``` ] ---
Current draft
.slides-content[ It is also possible to customize built-in tags: ```javascript customElements.define("my-button", MyButton, { extends: "button" }); ``` ```html
``` ] --- ### Shadow DOM .slides-content[ 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. ] ??? - The "heart" of the web components ---
Current draft
.slides-content.slides-columns[ ```html
My Headline
First paragraph
Second paragraph
``` ```javascript 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); } ``` ] ??? - Children of the shadow host are projected into the slots of the shadow tree --- ### HTML imports .slides-content[ Import other HTML documents into the current one,
including all the templates, styles and scripts. ] ---
Current draft
.slides-content[ ```html
... ``` - 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 ] --- layout: true class: slides-chapter, theme-danger --- ### Great! Let's get rid of all the frameworks and just write native web components.
(ノಠ益ಠ)ノ彡┻━┻
--- layout: true class: slides-centered, theme-whiskey --- ...not so fast...
(ヘ・_・)ヘ┳━┳
--- #### Problem 1:
Data flow .slides-content[ 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. ```html
``` ] --- #### Problem 2:
Imperative .slides-content[ Web components don't offer a declarative way to
describe DOM manipulations. Do we really want to go back to manual DOM manipulation? ] --- #### Problem 3:
Self-contained .slides-content[ 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? ] --- #### Problem 4:
Global namespace .slides-content[ With HTML imports, the mistakes of the past are repeated since all the
styles and scripts are just imported into the global namespace. ] --- #### Problem 5:
Flash of unstyled content .slides-content[ If we fail to deliver the implementation of a custom element fast enough,
the browser will display the custom element as `HTMLUnknownElement`. ] --- #### Problem 6:
No progressive enhancement .slides-content[ Web components are defined via JavaScript.
If something goes wrong, our web app will be broken. .slides-small[ This is also true for all SPA frameworks. With universal JavaScript,
however, we can always fall back to server-side rendering. ] ] --- layout: true class: slides-chapter, theme-whiskey --- ## Conclusion ??? - This is biased - Based on my personal experience --- layout: true class: slides-chapter, theme-mint --- ### Will ES2015 modules
change the way we work? --- layout: true class: slides-centered, theme-whiskey --- ### Yes .slides-content[ - 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 ] --- layout: true class: slides-chapter, theme-mint --- ### Will HTTP2 change
the way we work? --- layout: true class: slides-centered, theme-whiskey --- ### Yes .slides-content[ - 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 ] --- ### But... .slides-content[ ...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. ] ??? - Valuable information like: Which resources are render-blocking? --- layout: true class: slides-chapter, theme-mint --- ### Will web components change
the way we work? --- layout: true class: slides-centered, theme-whiskey --- ### Yes .slides-content[ - they provide new DOM primitives for future frameworks - they make the platform itself more customizable ] --- ### But... .slides-content[ - 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 ] --- layout: true class: slides-chapter, theme-mint --- ### How will frontend development look
like in the next years? --- layout: true class: slides-centered, theme-whiskey --- We will use... -- - ...tools like Babel, PostCSS and ESLint that expose "hackable" ASTs.slides-footnote-mark[1]...
.slides-footnote[ 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 --- layout: true class: slides-chapter, theme-mint ---
─=≡Σ((( つ•̀ω•́)つLET’SGO!