1
The Road to ES2015 in ProductionJacques Favreau
2What time is it?
Doom time!
3
• Const & Let
• Arrow Functions
• Destructuring
• Backtick/Template Strings
• Default Parameters
💧
Where we are today:
Limited ES2015
4What are we trying to do?
Goals
👼 Best experience for our users.
🤓 Best experience for our developers.
5
🤓 Senior UI Engineer @ Netflix
😅 Squad lead for the Web Core team
😍 Travel
😭 Clever code
Who?
Jacques Favreau
formComplete = function(){ var u = user.getUser(); var ct = 0 + (typeof(u.nickname)==='string' && u.nickname.length>0) + (typeof(u.websiteUrl)==='string' && u.websiteUrl.length>0) + (typeof(u.linkedin)==='string' && u.linkedin.length>0) + (typeof(u.locationString)==='string' && u.locationString.length>0) + (typeof(u.title)==='string' && u.title.length>0) + (typeof(u.bio)==='string' && u.bio.length>0) + (typeof(u.imageUrl)==='string' && u.imageUrl.length>0) + (typeof(u.resume)==='string' && u.resume.length>0) + (u.employerSharing && true); return Math.ceil(ct/0.09);};
6 What’s the future look like?
1.Are we stuck?
2.Rethinking what we ship, and why
3.ES2015 in the browser
4.Balancing UX and DX now and in the future
7With great transpilation comes great…
Hidden Cost
http://enomis94.deviantart.com
8Where we are today
Heavy on DX
Transpiled to ES5 Polyfill ES2015
Modern
Transpiled to ES5Polyfill ES2015Polyfill ES5
Legacy
No Support
Unsupported
9Where we are today
Heavy on DX
🤓🤓 🤓🤓
👼👼 👼👼💧
💧 💧
💧
10Where we are today
Heavy on DX
Transpiled to ES5 Polyfill ES2015
Modern
Transpiled to ES5Polyfill ES2015Polyfill ES5
Legacy
No Support
Unsupported
11
Ok, so let’s go the other way
12We could go the other way
Heavy on UX
ES3
Supported
No Support
Unsupported
ES5ES5 Polyfill
13We could go the other way
Heavy on UX
👼👼 👼👼
💧💧
💧 💧
14
How can we do better?
15 Things change
1.Modern browsers speak ES2015
2.Not all browsers are modern browsers
http://sanlaris.deviantart.com
16 Things change
Is getting ES2015 into the browser a good thing for our users?
17 Things change
20 to 40% over-the-wire payload reduction!
18 Things change
Browsers have varying support.
19Haven’t we done this?
Shoulders of Giants!
We have a long history of polyfilling in the browser
20
ES5 Code
Modern
ES5 CodePolyfill ES5Shim/Shams
Legacy
No Support
Unsupported
Flatten the earth:
Polyfilling
21
• Write expecting features
• Trade some performance for legacy browser support
Flatten the earth:
Polyfilling
22
<script src="//polyfill.io/v2/polyfill.js?features=es6,es5&flags=gated"></script>
Polyfills:
Ship only what you need
Flatten the earth:
Polyfilling
23What if we just shipped everything?
😭
I do not like the cone of shame
I do not like the cone of shame
24
Why is transpilation different?
(It’s not.)
25
👼 Best experience for our users.
🤓 Best experience for our developers.
Goals
26
So here it comes…
27
Netflix will start shipping native ES2015 to eligible browsers.
28
How?
29Our future:
Progressive Transpilation
ES2015
Modern
Legacy
No Support
Unsupported
Transpiled to ES5 Polyfill ES2015
Trailing
Transpiled to ES5 Polyfill ES2015Polyfill ES5
Shims
30Our future:
Progressive Transpilation
👼 Best experience for our users.
🤓 Best experience for our developers.
31Sidebar:
Look for other win opportunities
ES2015
Modern
Legacy
No Support
Unsupported
Transpiled to ES5 Polyfill ES2015Polyfill ES5
Trailing
Transpiled to ES5 Polyfill ES2015Polyfill ES5
Shims
32
ES2015
Modern
Legacy
No Support
Unsupported
Transpiled to ES5 Polyfill ES2015Polyfill ES5
Trailing
Fallback
Sidebar:
We ship fallback to legacy browsers
33Our future:
Progressive Transpilation
👼 Best experience for our users.
🤓 Best experience for our developers.
34
Let’s do it!
35On 🔥
Let’s do this!
Well… There are a few hurdles.
36On 🔥
Let’s do this!
1. Build systems lack support
2. Minifiers don’t work
3. Targeting browsers is hard
4. Browsers are broken and lie
37Issue #1:
Build systems
Issue #1:
Build systems lack ES2015 support
38Issue #1:
Build systems
Issue #1:
Build systems lack ES2015 support
39Issue #1:
Build systems
😞
Issue #1:
Build systems lack ES2015 support
40Issue #1:
Build systems
Solution #1:
There are some build systems that do
support ES2015 as a target!
41
const babelConfig = { modern: { presets: [] }, trailing: { presets: ['es2015'] }};
return gulp.src(glob) // Run babel with the modern config .pipe(babel(babelConfig.modern)) // Save the modern JS version. .pipe(gulp.dest('generated/modern/')) // Run Babel with trailing config. .pipe(babel(babelConfig.trailing)) // Save the trailing JS version. .pipe(gulp.dest('generated/trailing/'));
Just don’t use the
ES2015 preset.
Solutions to issue #1:
Workflows that work
42
{ "compilerOptions": { "module": "amd", "target": "es6" }}ES2015 supported as
a target.
Solutions to issue #1:
Workflows that work
43Issue #2:
Minfiers
Issue #2: Minifiers don’t work
44
Issue #2: Minifiers don’t work
Issue #2:
Minfiers
45Issue #2:
Minfiers
…but they’re working on it!
46Solutions to Issue #2:
Bable as a minifier
While we wait…
babel-preset-minify-es2015
47
It’s still a win!
Solutions to Issue #2:
Bable as a minifier
48Issue #3:
Who gets what?
Issue #3: Targeting browsers is hard
49
We unabashedly use the User Agent string
“[A]n ever-growing pack of lies[…]“
- Patrick H. Lauke
Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136
Solution to Issue #3:
Our old friend, UA
50
On first load, it’s all we have
¯\_( )_/¯
Solution to Issue #3:
Our old friend, UA
51
Select browsers with ES2015 support.
kangax.github.io/compat-table/es6/
At this time, our ES2015 browsers are:
- Chrome 51
- Firefox 49
- Edge 14
- Safari 10
Solution to Issue #3:
Our old friend, UA
52Issue #4:
Browsers lie
Issue #4: Browsers can and do lie.
53Solution to issue #4:
Test for lying browsers
Execute a bit of Javascript
and test for lies.
54
✓ unicode✓ proxies✓ symbols✓ subclassable built-ins✓ promises✓ math + number + string APIs✓ array + object APIs✓ binary and octal literals
Solution to issue #4:
Test for lying browsers
✓ arrows✓ classes✓ enhanced object literals✓ template strings✓ destructuring✓ default + rest + spread✓ let + const✓ iterators + for..of✓ generators
55
class ಠ_ಠ extends Array{ constructor(j = 'a', ...c) { const q = (({u: e}) => { return { [`s${c}`]: Symbol(j) }; })({}); super(j, q, ...c); }}new Promise((f) => { const a = function* (){ return "\u{20BB7}".match(/./u)[0].length === 2 || true; }; for(let vre of a()){ const [uw, as, he, re] = [new Set(), new WeakSet(), new Map(), new WeakMap()]; break; } f(new Proxy({}, {get: (han, h) => h in han ? han[h] : "42".repeat(0o10)}));}).then(bi => new ಠ_ಠ(bi.rd));
Solution to issue #4:
Test for lying browsers
Execute a bit of Javascript
and test for lies.
56
eval( 'class ಠ_ಠ extends Array{constructor(j="a",...c){const q=(({u:e})=>{return{[' + '`s${c}`]:Symbol(j)}})({});super(j,q,...c)}}new Promise(f=>{const a=function' + '*(){return"\u{20BB7}".match(/./u)[0].length===2||true};for(let vre of a()){' + 'const[uw,as,he,re]=[new Set,new WeakSet,new Map,new WeakMap];break} f(new ' + 'Proxy({},{get:(han,h)=>h in han?han[h]:"42".repeat(8)}))}).then(bi=>new ಠ_ಠ(bi.rd));');
Execute a bit of Javascript
and test for lies.
Solution to issue #4:
Test for lying browsers
57
try { eval( 'class ಠ_ಠ extends Array{constructor(j="a",...c){const q=(({u:e})=>{return{[' + '`s${c}`]:Symbol(j)}})({});super(j,q,...c)}}new Promise(f=>{const a=function' + '*(){return"\u{20BB7}".match(/./u)[0].length===2||true};for(let vre of a()){' + 'const[uw,as,he,re]=[new Set,new WeakSet,new Map,new WeakMap];break} f(new ' + 'Proxy({},{get:(han,h)=>h in han?han[h]:"42".repeat(8)}))}).then(bi=>new ಠ_ಠ(bi.rd));' );} catch (e) {
}
Execute a bit of Javascript
and test for lies.
Solution to issue #4:
Test for lying browsers
58
try { eval( 'class ಠ_ಠ extends Array{constructor(j="a",...c){const q=(({u:e})=>{return{[' + '`s${c}`]:Symbol(j)}})({});super(j,q,...c)}}new Promise(f=>{const a=function' + '*(){return"\u{20BB7}".match(/./u)[0].length===2||true};for(let vre of a()){' + 'const[uw,as,he,re]=[new Set,new WeakSet,new Map,new WeakMap];break} f(new ' + 'Proxy({},{get:(han,h)=>h in han?han[h]:"42".repeat(8)}))}).then(bi=>new ಠ_ಠ(bi.rd));' );} catch (e) { document.cookie = 'esSupportLevel=5; expires=' + (new Date((new Date()).getTime() + 2678400000)).toGMTString() + '; path=/ ;domain=netflix.com'; if(location.reload){location.reload(true);}else{location.href = location.href;}}
Execute a bit of Javascript
and test for lies.
Solution to issue #4:
Test for lying browsers
59
<script> try { eval( 'class ಠ_ಠ extends Array{constructor(j="a",...c){const q=(({u:e})=>{return{[' + '`s${c}`]:Symbol(j)}})({});super(j,q,...c)}}new Promise(f=>{const a=function' + '*(){return"\u{20BB7}".match(/./u)[0].length===2||true};for(let vre of a()){' + 'const[uw,as,he,re]=[new Set,new WeakSet,new Map,new WeakMap];break} f(new ' + 'Proxy({},{get:(han,h)=>h in han?han[h]:"42".repeat(8)}))}).then(bi=>new ಠ_ಠ(bi.rd));' ); } catch (e) { document.cookie = 'esSupportLevel=5; expires=' + (new Date((new Date()).getTime() + 2678400000)).toGMTString() + '; path=/ ;domain=netflix.com'; if(location.reload){location.reload(true);}else{location.href = location.href;} }</script>
Execute a bit of Javascript
and test for lies.
Solution to issue #4:
Test for lying browsers
60 What we’re doing (for now)
1. Build Babel as a transpiler.
2. Minifiers Babel plugins > babel-minify
3. Targeting User Agent to target supporting browsers
4. Lies Evaluated ES2015 to test; cookie fallback
61Our future:
Progressive Transpilation
ES2015
Modern
Legacy
No Support
Unsupported
Transpiled to ES5 Polyfill ES2015
Trailing
Fallback
62Mission accomplished
Goals balanced ⚖
*For now
*
👼 Best experience for our users.
🤓 Best experience for our developers.
63
Jem Young @jemyoung
Jacques Favreau @betaorbust
Questions?
Come ask us!