SlideShare a Scribd company logo
Artem
Yavorsky
Kyiv
Artem Yavorsky
"@babel/core": "7.x"
hellyeah
🌞
🌞
🌘
🌘
eslint-plugin-compat
🌘
Артем Яворский "@babel/core": "7.x"
🌘
🌘
It was October…
It was October…
It was October…
First PR
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
И че? Зачем это?
- Тратишь от 2 до ∞ часов в неделю
минусы
Тратить время на OSS
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
минусы
Тратить время на OSS
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
минусы
Тратить время на OSS
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
минусы
Тратить время на OSS
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
минусы
Тратить время на OSS
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
- Все равно этим занимаешься
минусы
Тратить время на OSS
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
- Все равно этим занимаешься
минусы-
Тратить время на OSS
✓ Получаешь от 2 до ∞ часов опыта
плюсы
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
- Все равно этим занимаешься
минусы
Тратить время на OSS
✓ Получаешь от 2 до ∞ часов опыта
✓ Легко обьяснить интервьюверу
плюсы
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
- Все равно этим занимаешься
минусы
Тратить время на OSS
✓ Получаешь от 2 до ∞ часов опыта
✓ Легко обьяснить интервьюверу
✓ Легко обьяснить новому клиенту
плюсы
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
- Все равно этим занимаешься
минусы
Тратить время на OSS
✓ Получаешь от 2 до ∞ часов опыта
✓ Легко обьяснить интервьюверу
✓ Легко обьяснить новому клиенту
✓ Ведьмак 3 так и не пройден
плюсы
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
- Все равно этим занимаешься
минусы
Тратить время на OSS
✓ Получаешь от 2 до ∞ часов опыта
✓ Легко обьяснить интервьюверу
✓ Легко обьяснить новому клиенту
✓ Ведьмак 3 так и не пройден
✓ Есть шанс выйти на opencollective
плюсы
- Тратишь от 2 до ∞ часов в неделю
- Сложно обьяснить девушке
- Сложно обьяснить друзьям
- Ведьмак 3 так и не пройден
- Материальное разочарование
- Все равно этим занимаешься
минусы
Тратить время на OSS
✓ Получаешь от 2 до ∞ часов опыта
✓ Легко обьяснить интервьюверу
✓ Легко обьяснить новому клиенту
✓ Ведьмак 3 так и не пройден
✓ Есть шанс выйти на opencollective
✓ Все равно этим занимаешься
плюсы
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
JavaScript компилятор
class User {
async load() {
await fetch('user');
}
}
es6
class User {
async load() {
await fetch('user');
}
}
function _instanceof(left, right) { if (right != null && typeof
Symbol !== "undefined" && right[Symbol.hasInstance]) { return
right[Symbol.hasInstance](left); } else { return left instanceof
right; } }
function _asyncToGenerator(fn) { return function () { var self =
this, args = arguments; return new Promise(function (resolve,
reject) { var gen = fn.apply(self, args); function step(key,
arg) { try { var info = gen[key](arg); var value = info.value; }
catch (error) { reject(error); return; } if (info.done)
{ resolve(value); } else { Promise.resolve(value).then(_next,
_throw); } } function _next(value) { step("next", value); }
function _throw(err) { step("throw", err); } _next(); }); }; }
function _classCallCheck(instance, Constructor) { if (!
_instanceof(instance, Constructor)) { throw new
TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i <
props.length; i++) { var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true; if ("value" in descriptor)
descriptor.writable = true; Object.defineProperty(target,
descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if
(protoProps) _defineProperties(Constructor.prototype,
protoProps); if (staticProps) _defineProperties(Constructor,
staticProps); return Constructor; }
var User =
/*#__PURE__*/
function () {
function User() {
es6
es5
40
👍
👍
👍
class User {
async load() {
await fetch('user');
}
}
Sept 28
Babel Turns Three
🎂
110000 websites using transform-classes
Артем Яворский "@babel/core": "7.x"
Babel on opencollective!
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
opencollective.com/babel
Артем Яворский "@babel/core": "7.x"
@
"@ /core": "7.x"
Артем Яворский "@babel/core": "7.x"
Все babel пакеты теперь scoped
Артем Яворский "@babel/core": "7.x"
✓ Не надо добавлять каждого участника для каждого
пакета
✓ Только команда может паблишить пакеты в
определенный scope
✓ Легче отличить “официальные” пакеты от остальных.
✓ Удобно группируются в node_modules
✓ Не надо добавлять каждого участника для каждого
пакета
✓ Только команда может паблишить пакеты в
определенный scope
✓ Не надо добавлять каждого участника для каждого
пакета
✓ Только команда может паблишить пакеты в
определенный scope
✓ Легче отличить “официальные” пакеты от остальных.
✓ Не надо добавлять каждого участника для каждого
пакета
✓ Только команда может паблишить пакеты в
определенный scope
✓ Легче отличить “официальные” пакеты от остальных.
✓ Удобно группируются в node_modules
Артем Яворский "@babel/core": "7.x"
babel-core
babel-preset-env
babel-plugin-proposal-class-properties
babel-plugin-transform-typescript
babel-runtime
@babel/core
@babel/preset-env
@babel/plugin-proposal-class-properties
@babel/plugin-transform-typescript
@babel/runtime
babel-core
babel-preset-env
babel-plugin-proposal-class-properties
babel-plugin-transform-typescript
babel-runtime
npm info @babel/core version
7.0.0-beta.32
Остановка поддержки node:
< 6 для разработки
< 4 для пользователей
ESNext -> ES5
github.com/babel/proposals
github.com/tc39/proposals
Идея как улучшить javascript
Артем Яворский "@babel/core": "7.x"
Stage 0
встреча TC39
Stage 1: Proposal
встреча TC39
Stage 2: Draft
встреча TC39
Stage 3: Candidate
встреча TC39
Stage 4: Finished
Stage 4: Finished
Stage 4: Finished
github.com/babel/proposals
Babylon PR New babel plugin
@babel/preset-stage[0-3]
@babel/preset-stage[0-3]
изменения в
Class Fields &
Static Properties
Private Fields
Class Fields Declarations
class A {
static b = 'foo';
c = ‘bar';
}
class A {
constructor() {
this.c = 'bar';
}
};
A.b = 'foo';
stage 3: @babel/plugin-proposal-class-properties
class A {
static b = 'foo';
c = ‘bar';
}
class A {
constructor() {
this.c = 'bar';
}
};
A.b = 'foo';
stage 3: @babel/plugin-proposal-class-properties
Артем Яворский "@babel/core": "7.x"
class Point {
#x = 0;
getFoo() {
return this.#x;
}
}
var _x;
class Foo {
constructor() {
_x.set(this, 0);
}
getFoo() {
return _x.get(this);
}
}
_x = new WeakMap();
PR #6120
class Point {
#x = 0;
getFoo() {
return this.#x;
}
}
var _x;
class Foo {
constructor() {
_x.set(this, 0);
}
getFoo() {
return _x.get(this);
}
}
_x = new WeakMap();
PR #6120
class Point {
#x = 0;
getFoo() {
return this.#x;
}
}
var _x;
class Foo {
constructor() {
_x.set(this, 0);
}
getFoo() {
return _x.get(this);
}
}
_x = new WeakMap();
PR #6120
class Point {
private x;
constructor(x) {
this.x = x;
}
}
const point = new Point(2);
b.x = 5; // TypeError ?
Why not `private foo` ?
stage 3: @babel/plugin-proposal-object-rest-spread
const symbol = Symbol(1);
const obj = {
[symbol]: 1,
two: 2
};
const {[symbol]: one, ...rest} = obj;
console.log(one); // 1
console.log(rest); // { two: 2 }
rest
stage 3: @babel/plugin-proposal-unicode-property-regex
var regex = /p{Emoji}/u;
regex.test('😊') // true
regex.test('hi') // false
github.com/mathiasbynens/regexpu-core/blob/master/property-
escapes.md
stage 3: @babel/plugin-proposal-optional-catch-binding
try {
throw 0;
} catch {
doSomething();
}
stage 3: @babel/plugin-proposal-optional-catch-binding
try {
throw 0;
} catch {
doSomething();
}
stage 3: @babel/plugin-proposal-optional-catch-binding
try {
throw 0;
} catch {
doSomething();
}
try {
throw 0;
} catch (_unused) {
doSomething();
}
stage 3: @babel/plugin-syntax-dynamic-import
import('my-script.js').then(data => {
console.log(data);
});
const data = await import('my-script.js');
stage 3: @babel/plugin-proposal-numeric-separator
100_000_000 // digit
0xA0_B0_C0 // hexadecimal
0o_11_55_21 // octal
0b_11_01 // binary
stage 3: @babel/plugin-proposal-numeric-separator
100_000_000 // digit
0xA0_B0_C0 // hexadecimal
0o_11_55_21 // octal
0b_11_01 // binary
100000000 // digit
0xA0B0C0 // hexadecimal
0o115521 // octal
0b1101 // binary
stage 3: @babel/plugin-proposal-numeric-separator
(0_0) ^0_0^ (0_0)
stage 3: @babel/plugin-proposal-numeric-separator
(0_0) ^0_0^ (0_0)
0
stage 2: @babel/plugin-proposal-decorators
// no parameter decorators (a separate proposal)
class Foo {
constructor(@foo x) {}
}
// no decorators on object methods
var o = {
@baz
foo() {}
}
// decorator cannot be attached to the export
@foo
export default class {}
что теперь нельзя
// no parameter decorators (a separate proposal)
class Foo {
constructor(@foo x) {}
}
// no decorators on object methods
var o = {
@baz
foo() {}
}
// decorator cannot be attached to the export
@foo
export default class {}
что теперь нельзя
// no parameter decorators (a separate proposal)
class Foo {
constructor(@foo x) {}
}
// no decorators on object methods
var o = {
@baz
foo() {}
}
// decorator cannot be attached to the export
@foo
export default class {}
что теперь нельзя
// decorators with a call expression
@foo('bar')
class A {
// decorators on computed methods
@autobind
[method](arg) {}
// decorators on generator functions
@deco
*gen() {}
// decorators with a member expression
@a.b.c(e, f)
m() {}
}
// exported decorator classes
export default @foo class {}
что можно
// decorators with a call expression
@foo('bar')
class A {
// decorators on computed methods
@autobind
[method](arg) {}
// decorators on generator functions
@deco
*gen() {}
// decorators with a member expression
@a.b.c(e, f)
m() {}
}
// exported decorator classes
export default @foo class {}
что можно
// decorators with a call expression
@foo('bar')
class A {
// decorators on computed methods
@autobind
[method](arg) {}
// decorators on generator functions
@deco
*gen() {}
// decorators with a member expression
@a.b.c(e, f)
m() {}
}
// exported decorator classes
export default @foo class {}
что можно
// decorators with a call expression
@foo('bar')
class A {
// decorators on computed methods
@autobind
[method](arg) {}
// decorators on generator functions
@deco
*gen() {}
// decorators with a member expression
@a.b.c(e, f)
m() {}
}
// exported decorator classes
export default @foo class {}
что можно
// decorators with a call expression
@foo('bar')
class A {
// decorators on computed methods
@autobind
[method](arg) {}
// decorators on generator functions
@deco
*gen() {}
// decorators with a member expression
@a.b.c(e, f)
m() {}
}
// exported decorator classes
export default @foo class {}
что можно
stage 1: @babel/plugin-coffeescript-in-js
stage 1: @babel/plugin-optional-chaining
stage 1: @babel/plugin-poposal-optional-chaining
a?.b?.[value].c?.()
a == null
? void 0
: a.b == null
? void 0
: a.b[value].c == null
? void 0
: a.b[value].c.call(a.b[value].c);
Артем Яворский "@babel/core": "7.x"
interface Props {
name: any;
enthusiasmLevel?: any;
}
const props: Props = {};
const props = {};
awesome-typescript-loader ts-loader
awesome-typescript-loader ts-loader
awesome-typescript-loader
ts-loader
useBabel: true
awesome-typescript-loader
ts-loader
module: {
rules: [{
test: /.ts(x?)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: babelOptions
},
{
loader: 'ts-loader'
}
]
}, {
test: /.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: babelOptions
}
]
}]
},
useBabel: true
@babel/plugin-transform-typescript
awesome-typescript-loader
ts-loader
Артем Яворский "@babel/core": "7.x"
{
"plugins": ["@babel/plugin-transform-typescript"]
}
{
"presets": [“@babel/preset-typescript"]
}
.babelrc
или
>babel index.ts index.js
>webpack index.ts index.js
или
@babel/preset-env
> npm install babel-preset-es2015
> npm install babel-preset-es2015
WARN deprecated babel-preset-latest@6.24.1: We're super 😸 excited that
you're trying to use ES2017+ syntax, but instead of making more yearly
presets 😭 , Babel now has a better preset that we recommend you use
instead: npm install babel-preset-env --save-dev. preset-env without
options will compile ES2015+ down to ES5 just like using all the presets
together and thus is more future proof. It also allows you to target
specific browsers so that Babel can do less work and you can ship native
ES2015+ to user 😎 ! We are also in the process of releasing v7, so
please give http://babeljs.io/blog/2017/09/12/planning-for-7.0 a read
and help test it out in beta! Thanks so much for using Babel 🙏, please
give us a follow on Twitter @babeljs for news on Babel, join
slack.babeljs.io for discussion/development and help support the project
at opencollective.com/babel
{
presets: [['env', {
targets: {
browsers: "chrome 63, safari 11"
},
}]]
}
autoprefixer для Babel
class User {
async load() {
await fetch('user');
}
}
function _instanceof(left, right) { if (right != null && typeof Symbol !==
"undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance]
(left); } else { return left instanceof right; } }
function _asyncToGenerator(fn) { return function () { var self = this, args =
arguments; return new Promise(function (resolve, reject) { var gen =
fn.apply(self, args); function step(key, arg) { try { var info = gen[key]
(arg); var value = info.value; } catch (error) { reject(error); return; } if
(info.done) { resolve(value); } else { Promise.resolve(value).then(_next,
_throw); } } function _next(value) { step("next", value); } function
_throw(err) { step("throw", err); } _next(); }); }; }
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance,
Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length;
i++) { var descriptor = props[i]; descriptor.enumerable =
descriptor.enumerable || false; descriptor.configurable = true; if ("value"
in descriptor) descriptor.writable = true; Object.defineProperty(target,
descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps)
_defineProperties(Constructor.prototype, protoProps); if (staticProps)
_defineProperties(Constructor, staticProps); return Constructor; }
var User =
/*#__PURE__*/
function () {
function User() {
_classCallCheck(this, User);
}
…
w3schools.com/browsers
92.7% 7.3%
…
function _instanceof(left, right) { if (right != null && typeof Symbol !==
"undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance]
(left); } else { return left instanceof right; } }
function _asyncToGenerator(fn) { return function () { var self = this, args =
arguments; return new Promise(function (resolve, reject) { var gen =
fn.apply(self, args); function step(key, arg) { try { var info = gen[key]
(arg); var value = info.value; } catch (error) { reject(error); return; } if
(info.done) { resolve(value); } else { Promise.resolve(value).then(_next,
_throw); } } function _next(value) { step("next", value); } function
_throw(err) { step("throw", err); } _next(); }); }; }
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance,
Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length;
i++) { var descriptor = props[i]; descriptor.enumerable =
descriptor.enumerable || false; descriptor.configurable = true; if ("value"
in descriptor) descriptor.writable = true; Object.defineProperty(target,
descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps)
_defineProperties(Constructor.prototype, protoProps); if (staticProps)
_defineProperties(Constructor, staticProps); return Constructor; }
var User =
/*#__PURE__*/
function () {
function User() {
_classCallCheck(this, User);
}
В 9 из 10 раз клиенты получают это
а было бы неплохо
class User {
async load() {
await fetch('user');
}
}
medium.com/dev-channel/the-cost-of-javascript-84009f51e99e
The Cost of JavaScript
tl;dr: less code = less parse/compile + less transfer + less to decompress
tl;dr: less code = less parse/compile + less transfer + less to decompress
Артем Яворский "@babel/core": "7.x"
stage 3 plugins
with `shippedProposals: true`
before compilation after compilation
for await 22kb 220kb
object rest
spread
21kb 65kb
optional-catch-
binding
23kb 26kb
unicode-property-
regex
21kb 140kb
Compilation result size
Артем Яворский "@babel/core": "7.x"
polyfills based on
code analysis
with
useBuiltIns: "usage"
.babelrc.js
const envOptions = { targets: {} };
if (process.env.NODE_ENV === 'development') {
envOptions.targets.browsers = 'safari TP';
} else {
envOptions.targets.browsers = '>1%';
}
const presets = ['env', envOptions];
export default {
presets,
}
.babelrc.js
const envOptions = { targets: {} };
if (process.env.NODE_ENV === 'development') {
envOptions.targets.browsers = 'safari TP';
} else {
envOptions.targets.browsers = '>1%';
}
const presets = ['env', envOptions];
export default {
presets,
}
.babelrc.js
const envOptions = { targets: {} };
if (process.env.NODE_ENV === 'development') {
envOptions.targets.browsers = 'safari TP';
} else {
envOptions.targets.browsers = '>1%';
}
const presets = ['env', envOptions];
export default {
presets,
}
.babelrc.js
const envOptions = { targets: {} };
if (process.env.NODE_ENV === 'development') {
envOptions.targets.browsers = 'safari TP';
} else {
envOptions.targets.browsers = '>1%';
}
const presets = ['env', envOptions];
export default {
presets,
}
.babelrc.js
const envOptions = { targets: {} };
if (process.env.NODE_ENV === 'development') {
envOptions.targets.browsers = 'safari TP';
} else {
envOptions.targets.browsers = '>1%';
}
const presets = ['env', envOptions];
export default {
presets,
}
.babelrc.js
> time babel src --out-dir lib
1.21s
> time NODE_ENV=production babel src --out-dir lib
2.31s
bundle-utils
Static server
Static server
Static server
useragent
useragent
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"
Static server
📦
ES6
Static server
useragent
Артем Яворский "@babel/core": "7.x"
Static server
📦
ES5
useragent
👍
👍 🤞
[
"> 1%",
"last 3 chrome versions, last 1 edge version",
"last 1 chrome version, last 1 safari version"
]
.browsers
export default {
entry: [
‘app/index.js'
],
output: {
path: path.join(‘dist’, id),
…
},
module: {rules: [{
loader: 'babel-loader',
query: {
"presets": [“env”]
}
}]}
};
webpack.config.js
export default mapConfigToTargets(({ id, browsers }) => {
entry: [
‘app/index.js'
],
output: {
path: path.join('dist', id),
…
},
module: {rules: [{
loader: 'babel-loader',
query: {
"presets": [["env", {
targets: {
browsers
},
}
}
}]}
});
webpack.config.js
export default mapConfigToTargets(({ id, browsers }) => {
entry: [
‘app/index.js'
],
output: {
path: path.join(‘dist’, id),
…
},
module: {rules: [{
loader: 'babel-loader',
query: {
"presets": [["env", {
targets: {
browsers
},
}
}
}]}
});
webpack.config.js
export default mapConfigToTargets(({ id, browsers }) => {
entry: [
‘app/index.js'
],
output: {
path: path.join(‘dist’, id),
…
},
module: {rules: [{
loader: 'babel-loader',
query: {
"presets": [["env", {
targets: {
browsers
},
}
}
}]}
});
webpack.config.js
export default mapConfigToTargets(({ id, browsers }) => {
entry: [
‘app/index.js'
],
output: {
path: path.join(‘dist’, id),
…
},
module: {rules: [{
loader: 'babel-loader',
query: {
"presets": [["env", {
targets: {
browsers
},
}
}
}]}
});
webpack.config.js
export default mapConfigToTargets(({ id, browsers }) => {
entry: [
‘app/index.js'
],
output: {
path: path.join(‘dist’, id),
…
},
module: {rules: [{
loader: 'babel-loader',
query: {
"presets": [["env", {
targets: {
browsers
},
}
}
}]}
});
webpack.config.js
-.. 1 (> 1%)
| /.. main.js
-.. 2 (last 3 chrome versions, last 1 edge version)
| /.. main.js
/.. 3 (last 1 chrome version, last 1 safari version)
/.. main.js
-.. 1 (> 1%)
| /.. main.js 192KB
-.. 2 (last 3 chrome versions, last 1 edge version)
| /.. main.js 68KB
/.. 3 (last 1 chrome version, last 1 safari version)
/.. main.js 44KB
index.js
app.get('*', function response(req, res) {
const bundleId = getBundleIdByUseragent(req.useragent);
const fullPath = path.join(__dirname, 'dist', bundleId, req.url)
res.write(fs.readFileSync(path.join(fullPath)));
res.end();
}
index.js
app.get('*', function response(req, res) {
const bundleId = getBundleIdByUseragent(req.useragent);
const fullPath = path.join(__dirname, 'dist', bundleId, req.url)
res.write(fs.readFileSync(path.join(fullPath)));
res.end();
}
res.header('Vary', 'User-Agent');
не забываем
-.. 0 (> 1%) 196K
-.. 1 (last 3 chrome versions, last 1 edge version) 72K
/.. 2 (last 1 chrome version, last 1 safari version) 48K
-.. 0 (> 1%) 196K
-.. 1 (last 3 chrome versions, last 1 edge version) 72K
/.. 2 (last 1 chrome version, last 1 safari version) 48K
60
-.. 0 (> 1%) 196K
-.. 1 (last 3 chrome versions, last 1 edge version) 72K
/.. 2 (last 1 chrome version, last 1 safari version) 48K
60
🚷
📦
60
72KB
📦
TP
48KB
📦
11
196KB
bundle-utils
Спасибо
Artem
Yavorsky
twitter.com/yavorsky_
github.com/yavorsky

More Related Content

Артем Яворский "@babel/core": "7.x"

  • 10. 🌘
  • 20. - Тратишь от 2 до ∞ часов в неделю минусы Тратить время на OSS
  • 21. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке минусы Тратить время на OSS
  • 22. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям минусы Тратить время на OSS
  • 23. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден минусы Тратить время на OSS
  • 24. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование минусы Тратить время на OSS
  • 25. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование - Все равно этим занимаешься минусы Тратить время на OSS
  • 26. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование - Все равно этим занимаешься минусы- Тратить время на OSS ✓ Получаешь от 2 до ∞ часов опыта плюсы
  • 27. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование - Все равно этим занимаешься минусы Тратить время на OSS ✓ Получаешь от 2 до ∞ часов опыта ✓ Легко обьяснить интервьюверу плюсы
  • 28. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование - Все равно этим занимаешься минусы Тратить время на OSS ✓ Получаешь от 2 до ∞ часов опыта ✓ Легко обьяснить интервьюверу ✓ Легко обьяснить новому клиенту плюсы
  • 29. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование - Все равно этим занимаешься минусы Тратить время на OSS ✓ Получаешь от 2 до ∞ часов опыта ✓ Легко обьяснить интервьюверу ✓ Легко обьяснить новому клиенту ✓ Ведьмак 3 так и не пройден плюсы
  • 30. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование - Все равно этим занимаешься минусы Тратить время на OSS ✓ Получаешь от 2 до ∞ часов опыта ✓ Легко обьяснить интервьюверу ✓ Легко обьяснить новому клиенту ✓ Ведьмак 3 так и не пройден ✓ Есть шанс выйти на opencollective плюсы
  • 31. - Тратишь от 2 до ∞ часов в неделю - Сложно обьяснить девушке - Сложно обьяснить друзьям - Ведьмак 3 так и не пройден - Материальное разочарование - Все равно этим занимаешься минусы Тратить время на OSS ✓ Получаешь от 2 до ∞ часов опыта ✓ Легко обьяснить интервьюверу ✓ Легко обьяснить новому клиенту ✓ Ведьмак 3 так и не пройден ✓ Есть шанс выйти на opencollective ✓ Все равно этим занимаешься плюсы
  • 38. class User { async load() { await fetch('user'); } } es6
  • 39. class User { async load() { await fetch('user'); } } function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); } else { return left instanceof right; } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _next(value) { step("next", value); } function _throw(err) { step("throw", err); } _next(); }); }; } function _classCallCheck(instance, Constructor) { if (! _instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var User = /*#__PURE__*/ function () { function User() { es6 es5
  • 40. 40 👍 👍 👍 class User { async load() { await fetch('user'); } }
  • 41. Sept 28 Babel Turns Three 🎂
  • 42. 110000 websites using transform-classes
  • 55. @
  • 58. Все babel пакеты теперь scoped
  • 60. ✓ Не надо добавлять каждого участника для каждого пакета ✓ Только команда может паблишить пакеты в определенный scope ✓ Легче отличить “официальные” пакеты от остальных. ✓ Удобно группируются в node_modules
  • 61. ✓ Не надо добавлять каждого участника для каждого пакета ✓ Только команда может паблишить пакеты в определенный scope
  • 62. ✓ Не надо добавлять каждого участника для каждого пакета ✓ Только команда может паблишить пакеты в определенный scope ✓ Легче отличить “официальные” пакеты от остальных.
  • 63. ✓ Не надо добавлять каждого участника для каждого пакета ✓ Только команда может паблишить пакеты в определенный scope ✓ Легче отличить “официальные” пакеты от остальных. ✓ Удобно группируются в node_modules
  • 67. npm info @babel/core version 7.0.0-beta.32
  • 68. Остановка поддержки node: < 6 для разработки < 4 для пользователей
  • 84. github.com/babel/proposals Babylon PR New babel plugin @babel/preset-stage[0-3]
  • 86. Class Fields & Static Properties Private Fields Class Fields Declarations
  • 87. class A { static b = 'foo'; c = ‘bar'; } class A { constructor() { this.c = 'bar'; } }; A.b = 'foo'; stage 3: @babel/plugin-proposal-class-properties
  • 88. class A { static b = 'foo'; c = ‘bar'; } class A { constructor() { this.c = 'bar'; } }; A.b = 'foo'; stage 3: @babel/plugin-proposal-class-properties
  • 90. class Point { #x = 0; getFoo() { return this.#x; } } var _x; class Foo { constructor() { _x.set(this, 0); } getFoo() { return _x.get(this); } } _x = new WeakMap(); PR #6120
  • 91. class Point { #x = 0; getFoo() { return this.#x; } } var _x; class Foo { constructor() { _x.set(this, 0); } getFoo() { return _x.get(this); } } _x = new WeakMap(); PR #6120
  • 92. class Point { #x = 0; getFoo() { return this.#x; } } var _x; class Foo { constructor() { _x.set(this, 0); } getFoo() { return _x.get(this); } } _x = new WeakMap(); PR #6120
  • 93. class Point { private x; constructor(x) { this.x = x; } } const point = new Point(2); b.x = 5; // TypeError ? Why not `private foo` ?
  • 94. stage 3: @babel/plugin-proposal-object-rest-spread const symbol = Symbol(1); const obj = { [symbol]: 1, two: 2 }; const {[symbol]: one, ...rest} = obj; console.log(one); // 1 console.log(rest); // { two: 2 } rest
  • 95. stage 3: @babel/plugin-proposal-unicode-property-regex var regex = /p{Emoji}/u; regex.test('😊') // true regex.test('hi') // false
  • 97. stage 3: @babel/plugin-proposal-optional-catch-binding try { throw 0; } catch { doSomething(); }
  • 98. stage 3: @babel/plugin-proposal-optional-catch-binding try { throw 0; } catch { doSomething(); }
  • 99. stage 3: @babel/plugin-proposal-optional-catch-binding try { throw 0; } catch { doSomething(); } try { throw 0; } catch (_unused) { doSomething(); }
  • 100. stage 3: @babel/plugin-syntax-dynamic-import import('my-script.js').then(data => { console.log(data); }); const data = await import('my-script.js');
  • 101. stage 3: @babel/plugin-proposal-numeric-separator 100_000_000 // digit 0xA0_B0_C0 // hexadecimal 0o_11_55_21 // octal 0b_11_01 // binary
  • 102. stage 3: @babel/plugin-proposal-numeric-separator 100_000_000 // digit 0xA0_B0_C0 // hexadecimal 0o_11_55_21 // octal 0b_11_01 // binary 100000000 // digit 0xA0B0C0 // hexadecimal 0o115521 // octal 0b1101 // binary
  • 106. // no parameter decorators (a separate proposal) class Foo { constructor(@foo x) {} } // no decorators on object methods var o = { @baz foo() {} } // decorator cannot be attached to the export @foo export default class {} что теперь нельзя
  • 107. // no parameter decorators (a separate proposal) class Foo { constructor(@foo x) {} } // no decorators on object methods var o = { @baz foo() {} } // decorator cannot be attached to the export @foo export default class {} что теперь нельзя
  • 108. // no parameter decorators (a separate proposal) class Foo { constructor(@foo x) {} } // no decorators on object methods var o = { @baz foo() {} } // decorator cannot be attached to the export @foo export default class {} что теперь нельзя
  • 109. // decorators with a call expression @foo('bar') class A { // decorators on computed methods @autobind [method](arg) {} // decorators on generator functions @deco *gen() {} // decorators with a member expression @a.b.c(e, f) m() {} } // exported decorator classes export default @foo class {} что можно
  • 110. // decorators with a call expression @foo('bar') class A { // decorators on computed methods @autobind [method](arg) {} // decorators on generator functions @deco *gen() {} // decorators with a member expression @a.b.c(e, f) m() {} } // exported decorator classes export default @foo class {} что можно
  • 111. // decorators with a call expression @foo('bar') class A { // decorators on computed methods @autobind [method](arg) {} // decorators on generator functions @deco *gen() {} // decorators with a member expression @a.b.c(e, f) m() {} } // exported decorator classes export default @foo class {} что можно
  • 112. // decorators with a call expression @foo('bar') class A { // decorators on computed methods @autobind [method](arg) {} // decorators on generator functions @deco *gen() {} // decorators with a member expression @a.b.c(e, f) m() {} } // exported decorator classes export default @foo class {} что можно
  • 113. // decorators with a call expression @foo('bar') class A { // decorators on computed methods @autobind [method](arg) {} // decorators on generator functions @deco *gen() {} // decorators with a member expression @a.b.c(e, f) m() {} } // exported decorator classes export default @foo class {} что можно
  • 116. stage 1: @babel/plugin-poposal-optional-chaining a?.b?.[value].c?.() a == null ? void 0 : a.b == null ? void 0 : a.b[value].c == null ? void 0 : a.b[value].c.call(a.b[value].c);
  • 118. interface Props { name: any; enthusiasmLevel?: any; } const props: Props = {}; const props = {};
  • 122. awesome-typescript-loader ts-loader module: { rules: [{ test: /.ts(x?)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: babelOptions }, { loader: 'ts-loader' } ] }, { test: /.js$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: babelOptions } ] }] }, useBabel: true
  • 126. >babel index.ts index.js >webpack index.ts index.js или
  • 128. > npm install babel-preset-es2015
  • 129. > npm install babel-preset-es2015 WARN deprecated babel-preset-latest@6.24.1: We're super 😸 excited that you're trying to use ES2017+ syntax, but instead of making more yearly presets 😭 , Babel now has a better preset that we recommend you use instead: npm install babel-preset-env --save-dev. preset-env without options will compile ES2015+ down to ES5 just like using all the presets together and thus is more future proof. It also allows you to target specific browsers so that Babel can do less work and you can ship native ES2015+ to user 😎 ! We are also in the process of releasing v7, so please give http://babeljs.io/blog/2017/09/12/planning-for-7.0 a read and help test it out in beta! Thanks so much for using Babel 🙏, please give us a follow on Twitter @babeljs for news on Babel, join slack.babeljs.io for discussion/development and help support the project at opencollective.com/babel
  • 130. { presets: [['env', { targets: { browsers: "chrome 63, safari 11" }, }]] } autoprefixer для Babel
  • 131. class User { async load() { await fetch('user'); } } function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance] (left); } else { return left instanceof right; } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function step(key, arg) { try { var info = gen[key] (arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _next(value) { step("next", value); } function _throw(err) { step("throw", err); } _next(); }); }; } function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var User = /*#__PURE__*/ function () { function User() { _classCallCheck(this, User); } …
  • 134. function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance] (left); } else { return left instanceof right; } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function step(key, arg) { try { var info = gen[key] (arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _next(value) { step("next", value); } function _throw(err) { step("throw", err); } _next(); }); }; } function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var User = /*#__PURE__*/ function () { function User() { _classCallCheck(this, User); } В 9 из 10 раз клиенты получают это
  • 135. а было бы неплохо class User { async load() { await fetch('user'); } }
  • 136. medium.com/dev-channel/the-cost-of-javascript-84009f51e99e The Cost of JavaScript tl;dr: less code = less parse/compile + less transfer + less to decompress
  • 137. tl;dr: less code = less parse/compile + less transfer + less to decompress
  • 139. stage 3 plugins with `shippedProposals: true`
  • 140. before compilation after compilation for await 22kb 220kb object rest spread 21kb 65kb optional-catch- binding 23kb 26kb unicode-property- regex 21kb 140kb Compilation result size
  • 142. polyfills based on code analysis with useBuiltIns: "usage"
  • 144. const envOptions = { targets: {} }; if (process.env.NODE_ENV === 'development') { envOptions.targets.browsers = 'safari TP'; } else { envOptions.targets.browsers = '>1%'; } const presets = ['env', envOptions]; export default { presets, } .babelrc.js
  • 145. const envOptions = { targets: {} }; if (process.env.NODE_ENV === 'development') { envOptions.targets.browsers = 'safari TP'; } else { envOptions.targets.browsers = '>1%'; } const presets = ['env', envOptions]; export default { presets, } .babelrc.js
  • 146. const envOptions = { targets: {} }; if (process.env.NODE_ENV === 'development') { envOptions.targets.browsers = 'safari TP'; } else { envOptions.targets.browsers = '>1%'; } const presets = ['env', envOptions]; export default { presets, } .babelrc.js
  • 147. const envOptions = { targets: {} }; if (process.env.NODE_ENV === 'development') { envOptions.targets.browsers = 'safari TP'; } else { envOptions.targets.browsers = '>1%'; } const presets = ['env', envOptions]; export default { presets, } .babelrc.js
  • 148. const envOptions = { targets: {} }; if (process.env.NODE_ENV === 'development') { envOptions.targets.browsers = 'safari TP'; } else { envOptions.targets.browsers = '>1%'; } const presets = ['env', envOptions]; export default { presets, } .babelrc.js
  • 149. > time babel src --out-dir lib 1.21s > time NODE_ENV=production babel src --out-dir lib 2.31s
  • 161. 👍
  • 163. [ "> 1%", "last 3 chrome versions, last 1 edge version", "last 1 chrome version, last 1 safari version" ] .browsers
  • 164. export default { entry: [ ‘app/index.js' ], output: { path: path.join(‘dist’, id), … }, module: {rules: [{ loader: 'babel-loader', query: { "presets": [“env”] } }]} }; webpack.config.js
  • 165. export default mapConfigToTargets(({ id, browsers }) => { entry: [ ‘app/index.js' ], output: { path: path.join('dist', id), … }, module: {rules: [{ loader: 'babel-loader', query: { "presets": [["env", { targets: { browsers }, } } }]} }); webpack.config.js
  • 166. export default mapConfigToTargets(({ id, browsers }) => { entry: [ ‘app/index.js' ], output: { path: path.join(‘dist’, id), … }, module: {rules: [{ loader: 'babel-loader', query: { "presets": [["env", { targets: { browsers }, } } }]} }); webpack.config.js
  • 167. export default mapConfigToTargets(({ id, browsers }) => { entry: [ ‘app/index.js' ], output: { path: path.join(‘dist’, id), … }, module: {rules: [{ loader: 'babel-loader', query: { "presets": [["env", { targets: { browsers }, } } }]} }); webpack.config.js
  • 168. export default mapConfigToTargets(({ id, browsers }) => { entry: [ ‘app/index.js' ], output: { path: path.join(‘dist’, id), … }, module: {rules: [{ loader: 'babel-loader', query: { "presets": [["env", { targets: { browsers }, } } }]} }); webpack.config.js
  • 169. export default mapConfigToTargets(({ id, browsers }) => { entry: [ ‘app/index.js' ], output: { path: path.join(‘dist’, id), … }, module: {rules: [{ loader: 'babel-loader', query: { "presets": [["env", { targets: { browsers }, } } }]} }); webpack.config.js
  • 170. -.. 1 (> 1%) | /.. main.js -.. 2 (last 3 chrome versions, last 1 edge version) | /.. main.js /.. 3 (last 1 chrome version, last 1 safari version) /.. main.js
  • 171. -.. 1 (> 1%) | /.. main.js 192KB -.. 2 (last 3 chrome versions, last 1 edge version) | /.. main.js 68KB /.. 3 (last 1 chrome version, last 1 safari version) /.. main.js 44KB
  • 172. index.js app.get('*', function response(req, res) { const bundleId = getBundleIdByUseragent(req.useragent); const fullPath = path.join(__dirname, 'dist', bundleId, req.url) res.write(fs.readFileSync(path.join(fullPath))); res.end(); }
  • 173. index.js app.get('*', function response(req, res) { const bundleId = getBundleIdByUseragent(req.useragent); const fullPath = path.join(__dirname, 'dist', bundleId, req.url) res.write(fs.readFileSync(path.join(fullPath))); res.end(); }
  • 175. -.. 0 (> 1%) 196K -.. 1 (last 3 chrome versions, last 1 edge version) 72K /.. 2 (last 1 chrome version, last 1 safari version) 48K
  • 176. -.. 0 (> 1%) 196K -.. 1 (last 3 chrome versions, last 1 edge version) 72K /.. 2 (last 1 chrome version, last 1 safari version) 48K 60
  • 177. -.. 0 (> 1%) 196K -.. 1 (last 3 chrome versions, last 1 edge version) 72K /.. 2 (last 1 chrome version, last 1 safari version) 48K 60 🚷