Custom languages | ![]() |
Linters | ![]() |
Bundlers | ![]() |
Minifiers | ![]() |
Devtools | ![]() |
Task runners | ![]() |
DOM libraries | ![]() |
Routing libraries | ![]() |
State libraries | ![]() |
Package managers | ![]() |
This was in the end of 2015...
This was in the end of 2015...
Support of new web platform features
in modern browsers1
HTTP2 |
69% |
ES2015 |
67% |
Web Components |
44% |
webpack core team
export default 42;
import magicNumber from "./a.js";
export default 42;
import magicNumber from "./a.js";
module.exports = 42;
const magicNumber = require("./a.js");
ES2015 and CommonJS look very similar, but there are two important differences.
const a = require(pathToA);// totally valid
import a from pathToA;// throws a SyntaxError
exports.value = 42;exports.incr = function () { exports.value++;};
let { value, incr } = require("./a");incr();console.log(value); // 42
export let value = 42;export function incr() { value++;}
import { value, incr } from "./a.js";incr();console.log(value); // 43
These properties make ES2015 modules less flexible than CommonJS...
These properties make ES2015 modules less flexible than CommonJS...
...but they're also the foundation for: Tree-shaking
export let value = 42;export function incr() { value++;}export function decr() { value++;}
import { incr } from "./a.js";incr();
let value = 42;export function incr() { value++;}
import { incr } from "./a.js";incr();
The static nature of ES2015 modules makes it possible
to trace all the exports that are actually used.
...with a static module system, how do we load things on demand?
( ☉д⊙)
System.import()
all the things!
There will be a way to load modules asynchronously:
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.
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".
...once we can load modules natively in the browser,
do we need tools like browserify and webpack anymore?
ಠಿ_ಠ
...to answer this question, we should take
a look at another new technology first.
Requests and responses are streams.
Streams are divided into frames.
Frames can be interleaved.
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:
So, let's get rid of all the bundlers and just include our development files.
(ノಠ益ಠ)ノ彡┻━┻
...not so fast...
(ヘ・_・)ヘ┳━┳
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
[Roundtrip Schaubild]
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.
What do we need to provide server push?
A dependency tree for each file:
{ "/css/app.css": { "type": "style", "weight": 1 }, "/js/app.js": { "type": "script", "weight": 1 }}
Google's Push Manifest Proposal
A dependency tree for each file:
{ "/css/app.css": { "type": "style", "weight": 1 }, "/js/app.js": { "type": "script", "weight": 1 }}
{ "/img/logo.jpg": { "type": "image", "weight": 1 }}
Google's Push Manifest Proposal
How do we get this dependency tree?
How do we get this dependency tree?
Referer
headerSo, let's figure out the dependency graph and push everything to the client.
(ノಠ益ಠ)ノ彡┻━┻
...not so fast...
(ヘ・_・)ヘ┳━┳
We need to know what the client has already cached,
otherwise we would waste precious bandwidth.
Proposed solution: Cache digests
Pushing resources with no prioritization actually harms performance.
See https://docs.google.com/document/d/1K0NykTXBbbbTlv60t5MyJvXjqKGsCVNYHyLEXIxYMv0/preview
<head> <link href="main.css" ...> </head> <body> <img src="heavy-image-1.jpg"> <img src="heavy-image-2.jpg"> </body>
HTTP2 provides a way to:
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.
<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>
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
Actually, web components is a fuzzy term
because it refers to 4 different technologies:
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.
<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:
template.content
exposes the content as DocumentFragment
which can be imported to get real DOM nodes.
Provides element lifecycle hooks:
class MyButton extends HTMLButtonElement { constructor() { ... } connectedCallback() { ... } disconnectedCallback() { ... } attributeChangedCallback() { ... }}customElements.define("my-button", MyButton);
<my-button></my-button>
It is also possible to customize built-in tags:
customElements.define("my-button", MyButton, { extends: "button"});
<button is="my-button"></button>
<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);}
<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>
Let's get rid of all the frameworks and just write native web components.
(ノಠ益ಠ)ノ彡┻━┻
...not so fast...
(ヘ・_・)ヘ┳━┳
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: "Hi there!"... }]"></inbox>
Web components don't offer a declarative way to
describe DOM manipulations.
Do we really want to go back to manual DOM manipulation?
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?
HTMLUnknownElement
.Web components are defined via JavaScript.
If something goes wrong, our web app will be broken.
...in order to leverage streams and server push, we need:
And when it doubt, we should stick to old best-practices where appropriate.
We will use...
We will use...
We will use...
We will use...
We will use...
We will use...
We will use...
We will use...
We will use...
We will use...
We will use...
─=≡Σ((( つ•̀ω•́)つLET’SGO!
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 |