File: 2019-03-19-core-js-3-babel-and-a-look-into-the-future.md

package info (click to toggle)
node-core-js 3.33.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 18,828 kB
  • sloc: javascript: 87,204; makefile: 13
file content (467 lines) | stat: -rw-r--r-- 38,509 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
# core-js@3, babel and a look into the future

After more than 1.5 years of development, dozens of pre-releases, many sleepless nights, **[`core-js@3`](https://github.com/zloirock/core-js)** is finally released. It's the largest set of changes in `core-js` and polyfilling-related **[`babel`](https://babeljs.io)** features of all time.

What is `core-js`?
- It is a polyfill of the JavaScript standard library, which supports:
  - The latest ECMAScript standard.
  - ECMAScript standard library proposals.
  - Some WHATWG / W3C standards (cross-platform or closely related ECMAScript).
- It is maximally modular: you can easily choose to load only the features you will be using.
- It can be used without polluting the global namespace.
- It is [tightly integrated with `babel`](#Babel): this allows many optimizations of `core-js` import.

It's the most universal and [the most popular](https://npmtrends.com/airbnb-js-shims-vs-core-js-vs-es5-shim-vs-es6-shim-vs-js-polyfills-vs-polyfill-library-vs-polyfill-service) way to polyfill JavaScript standard library, but a big part of developers just don't know that they use `core-js` indirectly 🙂

## Contributing

`core-js` is my own hobby project and it does not bring me any profit. It takes too much time and it is really costly: to finish work on `core-js@3`, I had left my job some months ago. This project facilitates the life of many people and companies. For these reasons, it makes sense to start raising funds to support the maintenance of `core-js`.

If you are interested in the `core-js` project or use it in your day-to-day work, you can become a sponsor on **[Open Collective](https://opencollective.com/core-js#sponsor)** or **[Patreon](https://www.patreon.com/zloirock)**.

You can propose [me](http://zloirock.ru/) a good job where I will be able to work on something related.

Or you can contribute in another way: you can help improve code, tests or documentation (currently, `core-js` documentation is terrible!).

## What changed in `core-js@3`?

### Changes in JavaScript standard library content

Because of the following two reasons, this release is rich with new JavaScript polyfills:
- `core-js` only has breaking changes in major releases, even if it is needed to reflect a change in a proposal.
- `core-js@2` entered feature freeze 1.5 years ago; all new features were added only to the `core-js@3` branch.

#### Stable ECMAScript features

Stable ECMAScript features had already been almost completely supported by `core-js` for a long time, however, `core-js@3` introduced some new features:
- Added support of [`@@isConcatSpreadable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/isConcatSpreadable) and [`@@species`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/species) well-known symbols, introduced in ECMAScript 2015, to all the methods which use them.
- Added [`Array.prototype.flat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat) and [`Array.prototype.flatMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap) methods from ECMAScript 2018 (`core-js@2` provided a polyfill for an old version of this proposal with `Array.prototype.flatten`).
- Added [`Object.fromEntries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries) method, introduced in ECMAScript 2019.
- Added [`Symbol.prototype.description`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/description) accessor, introduced ECMAScript 2019.

Some features that have already been available for a long time as proposals have been accepted in ES2016-ES2019 and are now marked as stable:
- [`Array.prototype.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) and [`%TypedArray%.prototype.includes`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/includes) methods (ECMAScript 2016)
- [`Object.values`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values) and [`Object.entries`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) methods (ECMAScript 2017)
- [`Object.getOwnPropertyDescriptors`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors) method (ECMAScript 2017)
- [`String.prototype.padStart`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart) and [`String.prototype.padEnd`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd) methods (ECMAScript 2017)
- [`Promise.prototype.finally`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally) method (ECMAScript 2018)
- [`Symbol.asyncIterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator) well-known symbol (ECMAScript 2018)
- [`Object.prototype.__define(Getter|Setter)__`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/__defineGetter__) and [`Object.prototype.__lookup(Getter|Setter)__`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/__lookupGetter__) methods (ECMAScript 2018)
- [`String.prototype.trim(Start|End|Left|Right)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trimStart) methods (ECMAScript 2019)

Added many fixes for browsers bugs/issues. For example, [Safari 12.0 `Array.prototype.reverse` bug](https://bugs.webkit.org/show_bug.cgi?id=188794) has been fixed.

#### ECMAScript proposals

In addition to supported before, `core-js@3` now supports the following ECMAScript proposals:
- [`globalThis`](https://github.com/tc39/proposal-global) stage 3 proposal - before, we had `global` and `System.global`
- [`Promise.allSettled`](https://github.com/tc39/proposal-promise-allSettled) stage 2 proposal
- [New `Set` methods](https://github.com/tc39/proposal-set-methods) stage 2 proposal:
  - `Set.prototype.difference`
  - `Set.prototype.intersection`
  - `Set.prototype.isDisjointFrom`
  - `Set.prototype.isSubsetOf`
  - `Set.prototype.isSupersetOf`
  - `Set.prototype.symmetricDifference`
  - `Set.prototype.union`
- [New collections methods](https://github.com/tc39/proposal-collection-methods) stage 1 proposal, which includes many new useful methods:
  - `Map.groupBy`
  - `Map.keyBy`
  - `Map.prototype.deleteAll`
  - `Map.prototype.every`
  - `Map.prototype.filter`
  - `Map.prototype.find`
  - `Map.prototype.findKey`
  - `Map.prototype.includes`
  - `Map.prototype.keyOf`
  - `Map.prototype.mapKeys`
  - `Map.prototype.mapValues`
  - `Map.prototype.merge`
  - `Map.prototype.reduce`
  - `Map.prototype.some`
  - `Map.prototype.update`
  - `Set.prototype.addAll`
  - `Set.prototype.deleteAll`
  - `Set.prototype.every`
  - `Set.prototype.filter`
  - `Set.prototype.find`
  - `Set.prototype.join`
  - `Set.prototype.map`
  - `Set.prototype.reduce`
  - `Set.prototype.some`
  - `WeakMap.prototype.deleteAll`
  - `WeakSet.prototype.addAll`
  - `WeakSet.prototype.deleteAll`
- [`String.prototype.replaceAll`](https://github.com/tc39/proposal-string-replace-all) stage 1 proposal
- [`String.prototype.codePoints`](https://github.com/tc39/proposal-string-prototype-codepoints) stage 1 proposal
- [`Array.prototype.last(Item|Index)`](https://github.com/keithamus/proposal-array-last) stage 1 proposal
- [`compositeKey` and `compositeSymbol` methods](https://github.com/bmeck/proposal-richer-keys/tree/master/compositeKey) stage 1 proposal
- [`Number.fromString`](https://github.com/tc39/proposal-number-fromstring) stage 1 proposal
- [`Math.seededPRNG`](https://github.com/tc39/proposal-seeded-random) stage 1 proposal
- [`Promise.any` (with `AggregateError`)](https://github.com/tc39/proposal-promise-any) stage 0 proposal

Some proposals have been largely changed, and `core-js` was updated accordingly:
- [`String.prototype.matchAll`](https://github.com/tc39/proposal-string-matchall) stage 3 proposal
- [`Observable`](https://github.com/tc39/proposal-observable) stage 1 proposal

#### Web standards

Many useful features have been added to this category.

The most important one is support for [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) and [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). It was [one of the most popular feature requests](https://github.com/zloirock/core-js/issues/117). Adding `URL` and `URLSearchParams`, making maximally spec-compliant, supporting any environment keeping their source code small compact was [one of the hardest tasks](https://github.com/zloirock/core-js/pull/454/files) in the `core-js@3` development.

`core-js@3` includes *a standard* method to create microtasks in JavaScript: [`queueMicrotask`](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#microtask-queuing). `core-js@2` provided the `asap` function which did the same thing and was an old ECMAScript proposal. `queueMicrotask` is defined in the HTML standard and it is already available in modern engines like Chromium or NodeJS.

Another popular feature request was support for the [`.forEach` method on DOM collection](https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach). Since `core-js` already polyfilled iterators of DOM collections, why not add also `.forEach` to `NodeList` and `DOMTokenList`?

#### Removed obsolete features:

- `Reflect.enumerate` because it's removed from the spec
- `System.global` and `global` since now they are replaced by `globalThis`
- `Array.prototype.flatten` since it's replaced by `Array.prototype.flat`
- `asap` since it's replaced by `queueMicrotask`
- `Error.isError` has withdrawn a long time ago
- `RegExp.escape` rejected a long time ago
- `Map.prototype.toJSON` and `Set.prototype.toJSON` also rejected a long time ago
- Unnecessary `CSSRuleList`, `MediaList`, `StyleSheetList` iteration methods which were added mistakenly


#### No more non-standard non-proposed features

Many years ago, I started writing a library which I needed as the core of my JavaScript applications: this library contained polyfills and some utilities for common needs. After some time, it was published as `core-js`. I think that at this moment most `core-js` users do not use non-standard `core-js` features. Almost all of them were removed in previous releases, and it's time to remove all the remaining ones from `core-js`. Starting from this release, `core-js` can be finally called a polyfill.

### Packages, entry points and modules names

A popular issue was a big size (~2MB) of the `core-js` package and duplication of many of its files. For this reason, `core-js` was split into three packages:
- [`core-js`](https://www.npmjs.com/package/core-js), which defines global polyfills. (~500KB, [40KB minified and gzipped](https://bundlephobia.com/result?p=core-js@3.0.0-beta.20))
- [`core-js-pure`](https://www.npmjs.com/package/core-js-pure), which provides polyfills without pollution the global environment. It's the equivalent of `core-js/library` from `core-js@2`. (~440KB)
- [`core-js-bundle`](https://www.npmjs.com/package/core-js-bundle): a bundled version of `core-js` which defines global polyfills.

In previous versions of `core-js`, modules with polyfills for stable ECMAScript features and ECMAScript proposals were prefixed with `es6.` and `es7.` respectively. It was a decision taken in 2014 when all the features which could be after ES6 were considered as ES7. In `core-js@3` all stable ECMAScript features are prefixed with `es.`, while ECMAScript proposals with `esnext.`.

Almost all CommonJS entry points were changed. In `core-js@3` there are many more entry points than there were in `core-js@2`: they bring maximum flexibility, making it possible to include only the polyfills needed by your application.

Here are some examples of how the new entry points can be used:
```js
// polyfill all `core-js` features:
import "core-js";
// polyfill only stable `core-js` features - ES and web standards:
import "core-js/stable";
// polyfill only stable ES features:
import "core-js/es";

// if you want to polyfill `Set`:
// all `Set`-related features, with ES proposals:
import "core-js/features/set";
// stable required for `Set` ES features and features from web standards
// (DOM collections iterator in this case):
import "core-js/stable/set";
// only stable ES features required for `Set`:
import "core-js/es/set";
// the same without global namespace pollution:
import Set from "core-js-pure/features/set";
import Set from "core-js-pure/stable/set";
import Set from "core-js-pure/es/set";

// if you want to polyfill just required methods:
import "core-js/features/set/intersection";
import "core-js/stable/queue-microtask";
import "core-js/es/array/from";

// polyfill reflect metadata proposal:
import "core-js/proposals/reflect-metadata";
// polyfill all stage 2+ proposals:
import "core-js/stage/2";
```

### Some other important changes

It's now possible to [configure the aggressiveness](https://github.com/zloirock/core-js/blob/master/README.md#configurable-level-of-aggressiveness) of `core-js` polyfills. If you think that `core-js` feature detection is too aggressive in some cases and that the native implementation is correct enough for your use-case, or if an incorrect implementation isn't detected by `core-js` as such, you can change the `core-js` default behavior.

If a feature can't be implemented following the specification in every detail, `core-js` adds a `.sham` property to the polyfill. For example, in IE11 `Symbol.sham` is `true`.

No more LiveScript! When I started the `core-js` project, I mainly used [LiveScript](http://livescript.net/); after some time, I rewrote all the polyfills in JavaScript. Tests and helper tools in `core-js@2` still used LiveScript: it is a very interesting CoffeeScript-like language with powerful syntax sugar which allows writing very compact code, but now it's almost dead. Other than that, it was an additional barrier for contributing to `core-js` because most `core-js` users do not know this language. `core-js@3` tests and tools use modern ES syntax: it could be a good moment to start contributing to `core-js` 🙂

For almost all users, for optimization of `core-js` import, I recommend using [`babel`](#Babel). However, [`core-js-builder`](https://npmjs.com/package/core-js-builder) is still useful in some cases. Now it supports the `targets` argument which takes a [`browserslist`](https://github.com/browserslist/browserslist) query with target engines - you can create a bundle which contains only required for target engines polyfills. For cases like this, I made the [`core-js-compat`](https://www.npmjs.com/package/core-js-compat) package, more info about it you could find in [`@babel/preset-env` part of this article](#babelpreset-env).

---

This is just the tip of the iceberg, much more changes were done internally. You can find more info about `core-js` changes in the [changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md#300).

## Babel

As mentioned above, `babel` and `core-js` are tightly integrated: `babel` gives the possibility of optimizing the `core-js` import as much as possible. A serious part of work on `core-js@3` was improving `core-js`-related `babel` features (see [this PR](https://github.com/babel/babel/pull/7646)). Those changes are published in [Babel 7.4.0](https://babeljs.io/blog/2019/03/19/7.4.0).

### `@babel/polyfill`

[`@babel/polyfill`](https://babeljs.io/docs/en/next/babel-polyfill.html) is a wrapper package which only includes imports of stable `core-js` features (in Babel 6 it also included proposals) and `regenerator-runtime/runtime`, needed by transpiled generators and async functions. This package doesn't make it possible to provide a smooth migration path from `core-js@2` to `core-js@3`: for this reason, it was decided to deprecate `@babel/polyfill` in favor of separate inclusion of required parts of `core-js` and `regenerator-runtime`.

Instead of
```js
import "@babel/polyfill";
```
you should use those 2 lines:
```js
import "core-js/stable";
import "regenerator-runtime/runtime";
```

Don't forget install those dependencies directly!

```sh
npm i --save core-js regenerator-runtime
```

### `@babel/preset-env`

[`@babel/preset-env`](https://babeljs.io/docs/en/next/babel-preset-env#usebuiltins) has 2 different modes, which can be enabled with the `useBuiltIns` option: `entry` and `usage`, which optimize imports of `core-js` in different ways.

Babel 7.4.0 introduces both changes commons to the two modes and specific to each mode.

Since `@babel/preset-env` now supports `core-js@2` and `core-js@3`, `useBuiltIns` requires setting a new option, `corejs`, which specifies the used version (`corejs: 2` or `corejs: 3`). If it isn't directly set, `corejs: 2` will be used by default and it will show a warning.

To make it possible for Babel to support new `core-js` features introduced in future minor versions, you also can specify the minor `core-js` version used in your project. For example, if you want to use `core-js@3.1` and take advantage of new features added in that version, you can set the `corejs` option to `3.1`: `corejs: '3.1'` or `corejs: { version: '3.1' }`.

One of the most important parts of `@babel/preset-env` was the source providing data about the features supported by different target engines, to understand whether something needs to be polyfilled by `core-js` or not. [`caniuse`](https://caniuse.com/), [`mdn`](https://developer.mozilla.org/en-US/) and [`compat-table`](http://kangax.github.io/compat-table/es6/) are good educational resources but aren't really meant to be used as data sources for developer tools: only the `compat-table` contains a good set of ES-related data and it is used by `@babel/preset-env`, but it has some limitations:
- it contains data only about ECMAScript features and proposals, but not about web platform features like `setImmediate` or DOM collections iterators. So, up to now, `@babel/preset-env` added all web platform features from `core-js` even for targets where they are supported.
- it does not contain any information about (even serious) bugs in engines: for example, already mentioned `Array#reverse` broken in Safari 12 but it isn't marked as unsupported by `compat-table`. On the other hand, `core-js` correctly fixes broken implementations, but with `compat-table` this capability wasn't taken advantage of.
- it contains only some basic and naive tests, which do not check that features work as they should in real-world cases. For example, old Safari has broken iterators without `.next` method, but `compat-table` shows them as supported because it just checks that `typeof` of methods which should return iterators is `"function"`. Some features like typed arrays are almost completely not covered.
- `compat-table` is not designed for providing data for tools. I'm one of the `compat-table` maintainers, but [some of the other maintainers are against maintaining this functionality](https://github.com/kangax/compat-table/pull/1312).

For this reason, I created the [`core-js-compat`](https://github.com/zloirock/core-js/tree/master/packages/core-js-compat) package: it provides data about the necessity of `core-js` modules for different target engines. When using `core-js@3`, `@babel/preset-env` will use that new package instead of `compat-table`. [Please help us with testing and providing data and mappings for missing engines! 😊](https://github.com/zloirock/core-js/blob/master/CONTRIBUTING.md#updating-core-js-compat-data)

Until Babel 7.3, `@babel/preset-env` had some problems related to the order polyfills were injected. Starting from version 7.4.0, `@babel/preset-env` will add the polyfills only when it knows which of them is required and in the recommended order.

#### `useBuiltIns: entry` with `corejs: 3`

When using this option, `@babel/preset-env` replaces direct imports of `core-js` with imports of only the specific modules required for a target environment.

Before those changes, `@babel/preset-env` replaced only `import '@babel/polyfill'` and `import 'core-js'`, they were synonyms and used for polyfilling all stable JavaScript features.

Since `@babel/polyfill` is now deprecated, `@babel/preset-env` doesn't transpile it when `corejs` is set to `3`.

An equivalent replacement for `@babel/polyfill` with `core-js@3` is
```js
import "core-js/stable";
import "regenerator-runtime/runtime";
```

When targeting `chrome 72`, it will be transformed by `@babel/preset-env` to
```js
import "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/es.object.from-entries";
import "core-js/modules/web.immediate";
```

when targeting `chrome 73` (which completely support ES2019 standard library), it will just become a single smaller import:
```js
import "core-js/modules/web.immediate";
```

Since now `@babel/polyfill` is deprecated in favor of separate `core-js` and `regenerator-runtime` inclusion, we can optimize `regenerator-runtime` import. For this reason, `regenerator-runtime` import will be removed from the source code when targeting browsers that support generators natively.

Now, `@babel/preset-env` in `useBuiltIns: entry` mode transpile **all available** `core-js` entry points and their combinations. This means that you can customize it as much as you want, by using different `core-js` entry points, and it will be optimized for your target environment.

For example, when targeting `chrome 72`,
```js
import "core-js/es";
import "core-js/proposals/set-methods";
import "core-js/features/set/map";
```
will be replaced with
```js
import "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/es.object.from-entries";
import "core-js/modules/esnext.set.difference";
import "core-js/modules/esnext.set.intersection";
import "core-js/modules/esnext.set.is-disjoint-from";
import "core-js/modules/esnext.set.is-subset-of";
import "core-js/modules/esnext.set.is-superset-of";
import "core-js/modules/esnext.set.map";
import "core-js/modules/esnext.set.symmetric-difference";
import "core-js/modules/esnext.set.union";
```

#### `useBuiltIns: usage` with `corejs: 3`

When using this option, `@babel/preset-env` adds at the top of each file imports of polyfills only for features used in the current and not supported by target environments.

For example,
```js
const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);
```

when targeting an old browser like `ie 11`, will be transformed to
```js
import "core-js/modules/es.array.includes";
import "core-js/modules/es.array.iterator";
import "core-js/modules/es.object.to-string";
import "core-js/modules/es.set";

const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);
```

when targeting, for example, `chrome 72` no imports will be injected, since those polyfills not required for this target:
```js
const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);
```

Until Babel 7.3, `useBuiltIns: usage` was unstable and not fully reliable: many polyfills were not included, and many others were added without their required dependencies. In Babel 7.4, I tried to make it understand every possible usage pattern.

I improved the techniques used to determine which polyfills should be added on property accesses, object destructuring, `in` operator, global object property accesses.

`@babel/preset-env` now injections polyfills required for syntax features: iterators when using `for-of`, destructuring, spread and `yield` delegation; promises when using dynamic `import`, async functions and generators, etc.

Babel 7.4 supports injecting proposals polyfills. By default, `@babel/preset-env` does not inject them, but you can opt-in using the `proposals` flag: `corejs: { version: 3, proposals: true }`.

### `@babel/runtime`

When used with `core-js@3`, [`@babel/transform-runtime`](https://babeljs.io/docs/en/next/babel-plugin-transform-runtime#corejs) now injects polyfills from `core-js-pure`: a version of `core-js` that doesn't pollute the global namespace.

`core-js@3` and `@babel/runtime` have been integrated together by adding a `corejs: 3` option to `@babel/transform-runtime` and creating the `@babel/runtime-corejs3` package. But what advantages did this bring?

One of the most popular issue with `@babel/runtime` was that it did not support instance methods. Starting from `@babel/runtime-corejs3`, this problem has resolved. For example,
```js
array.includes(something);
```
will be transpiled to
```js
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";

_includesInstanceProperty(array).call(array, something);
```

Another notable change is the support of ECMAScript proposals. By default, `@babel/plugin-transform-runtime` does not inject polyfills for proposals and use entry points which do not include them but, exactly as you can do in `@babel/preset-env`, you can set the `proposals` flag to enable them: `corejs: { version: 3, proposals: true }`.

Without `proposals` flag,
```js
new Set([1, 2, 3, 2, 1]);
string.matchAll(/something/g);
```
is transpiled to:
```js
import _Set from "@babel/runtime-corejs3/core-js-stable/set";

new _Set([1, 2, 3, 2, 1]);
string.matchAll(/something/g);
```
when proposals are enabled, it becomes:
```js
import _Set from "@babel/runtime-corejs3/core-js/set";
import _matchAllInstanceProperty from "@babel/runtime-corejs3/core-js/instance/match-all";

new _Set([1, 2, 3, 2, 1]);
_matchAllInstanceProperty(string).call(string, /something/g);
```

Some other old issues have been fixed. For example, this quite popular pattern didn't work when using `@babel/runtime-corejs2` but it is supported with `@babel/runtime-corejs3`.

```js
myArrayLikeObject[Symbol.iterator] = Array.prototype[Symbol.iterator];
```
Although previous versions of `@babel/runtime` did not work with instance methods, iterables (both `[Symbol.iterator]()` calls and its presence) were supported using some custom helper functions. Extracting the `[Symbol.iterator]` method was not supported, but now it works.

As a cheap bonus, `@babel/runtime` now supports IE8-, with some limitations. For example, since IE8- does not support accessors, modules transform should be used in loose mode and `regenerator-runtime` (which internally uses some ES5+ built-ins) needs to be transpiled by this plugin.

## Look into the future

Much work has been done, but `core-js` is still far from perfect. How can the library and tools be improved in the future and how do language changes can affect it?

### Old engines support

At this moment, `core-js` tries to support all possible engines and platforms where we can test it: it even supports IE8- or, for example, early Firefox versions. While it is useful for some users, only a small part of developers using `core-js` need it. For many other users, it can cause some problems like bigger bundle size or slower runtime execution.

The main problem comes from supporting ES3 engines (above all, IE8-): most modern ES features are based on ES5 features, which aren't available in those very old browsers.

The biggest missing important feature is property descriptors: when they aren't available, some features can't be polyfilled because they either are accessors (like `RegExp.prototype.flags` or `URL` properties setters) or are accessors-based (like typed arrays polyfill). In order to workaround this lack, we need to use different workarounds (for example, to keep `Set.prototype.size` updated). Maintenance of those workarounds sometimes is too painful, and removing them would highly simplify many polyfills.

However, descriptors are just a part of this problem. The ES5 standard library contains many other features that can be considered as the basis of modern JavaScript: `Object.keys`, `Object.create`, `Object.getPrototypeOf`, `Array.prototype.forEach`, `Function.prototype.bind`, etc. Unlike the most modern features, `core-js` internally relies on them and [in order to implement even a simple modern function, `core-js` needs to load implementations of some of those "building blocks"](https://github.com/babel/babel/pull/7646#discussion_r179333093). It is a problem for users who want to create [a maximally minimalistic bundle](https://github.com/zloirock/core-js/issues/388) and only import just a few `core-js` polyfills.

In some countries, IE8 still is quite popular, but browsers should disappear at some point to allow the web to move forward. IE8 was released 19-03-2009; today it is 19-03-2019: it's the 10th birthday of IE8. IE6 is about to turn 18: I stopped testing new `core-js` versions in IE6 some months ago.

We should drop IE8- and other engines without basic ES5 support in `core-js@4`.

### ECMAScript modules

`core-js` use `CommonJS` modules. It has been the most popular JavaScript modules format for a long time, but now ECMAScript provides its own modules format. Many engines already support them; some bundlers (like `rollup`) are based on them, and some other bundlers provide them as an alternative to `CommonJS`. It would make sense to provide an alternative version of `core-js` which uses ECMAScript modules format.

### Extended web standards support?

`core-js` is currently focused on ECMAScript support, but it also supports a few web standards features which are available cross-platform and closely related to ECMAScript. Adding polyfills for web standards like `fetch` is a very popular feature request.

The main reason why `core-js` doesn’t include them was that it would have seriously increased bundles size and it would have forced `core-js` users to load features which might not have been needed. Now `core-js` is maximally modular, user can include only some chosen features, there are tools like `@babel/preset-env` and `@babel/runtime` which helps to get rid of unused or unnecessary polyfills.

Maybe it's time to revisit this old decision?

### `@babel/runtime` for target environment

Currently, we can't set the target environment as `@babel/runtime` like we can do for `@babel/preset-env`. That means that `@babel/runtime` injects all possible polyfills even when targeting modern engines: it unnecessarily increases the size of the final bundle.

Since `core-js-compat` contains all the necessary data, in the future, it will be possible to add support for compiling for a target environment to `@babel/runtime` and to add a `useBuiltIns: runtime` option to `@babel/preset-env`.

### Better optimization of polyfill loading

As explained above, Babel plugins give us different ways of optimizing `core-js` usage, but they are not perfect: we can improve them.

`@babel/preset-env` with `useBuiltIns: usage` now should work much better than before, but it could still fail in some uncommon cases: when the code can't be statically analyzed. For that case, we need to find a way for library developers to specify which polyfills are required by their library instead of directly loading them: some kind of metadata, which will be used to inject polyfills when creating the final bundle.

Another issue of `useBuiltIns: usage` is the duplication of polyfills import. `useBuiltIns: usage` can inject dozens of `core-js` imports in each file. But what if our project has thousands of files or even tenths of thousands? In this case, we will have more lines of code with `import "core-js/..."` than lines of code in `core-js` itself: we need a way to collect all imports to one file so that they can be deduplicated.

Almost every `@babel/preset-env` user which targets old engines like IE11 uses a single bundle for every browser. That means that even modern engines with full ES2019 support will be loading the unnecessary polyfills only required by IE11. Sure, we can create different bundles for different targets and use, for example, the `type=module` / `nomodules`  attributes: one bundle for modern engines with modules support, another for legacy engines. Unfortunately, it’s not a complete solution to this problem: a service that bundles polyfills for the required target based on the user agent would be really useful. And we already have one - [`polyfill-service`](https://github.com/Financial-Times/polyfill-service). Although it is an interesting and popular service, polyfills quality leaves much to be desired. It’s not as bad as it was some years ago: the team of this project is actively working to improve it, but I wouldn't recommend using polyfills from this project if you want them to match native implementations. Some years ago was an attempt to use `core-js` as a polyfills source for this project, but it hadn't been possible because `polyfill-service` relies on files concatenation instead of modules (like `core-js` in the first few months after it was published 😊).

A service like this one integrated with a good polyfills source like `core-js`, which only loads the needed polyfills by statically analyzing the source like Babel's `useBuiltIns: usage` option does could cause a revolution in the way we think about polyfills.

### New features proposals from TC39 and possible problems for `core-js`

TC39 is working really hard to improve ECMAScript: you can see the progress by looking at all the new proposals implemented in `core-js`. However, I think that some features of some proposals could cause serious problems for polyfilling / transpiling. There would be enough to say about this topic to write a whole new post, but I'll try to summarize my thoughts here.

#### Standard library proposal, stage 1

At this moment, TC39 is considering adding to ECMAScript [built-in modules](https://github.com/tc39/proposal-javascript-standard-library): a modular standard library. It would be a great addition to JavaScript, and `core-js` is the best place where it could be polyfilled. With the techniques used in `@babel/preset-env` and `@babel/runtime`, we could theoretically inject polyfills for required built-in modules in a very simple way. However, the current version of this proposal causes some serious problems which don't make it as straightforward.

Polyfilling of built-in modules, [as stated by the authors of the proposal](https://github.com/tc39/proposal-javascript-standard-library/issues/2), only means falling back to layered APIs or import maps. This means that if a native module will be missing, it will be possible to load a polyfill from a provided URL. That's absolutely not what polyfills need, and it is incompatible with the architecture of `core-js` and every other popular polyfill project. Import maps shouldn't be the only way to polyfill built-in modules.

We will be able to get a built-in module just by using ES modules syntax with a special prefix. This syntax haven't any equal based on the previous version of the language - transpiled modules will not be able to interact with not transpiled in modern engines - it will cause problems for package distribution.

More other, it will work asynchronously. It's a critical problem for feature detection - scripts will not wait when you'll detect a feature and load a polyfill - feature detection should be done synchronously.

[The first implementation of built-in modules without a proper way of transpiling / polyfilling already available](https://developers.google.com/web/updates/2019/03/kv-storage). If it will not be revised, built-in modules will not be able to be polyfilled in the current `core-js` format. The proposed way of polyfilling will seriously complicate the lives of developers.

The issue with the standard library can be solved by adding a new global (maybe it will be the last one?): a registry of built-in modules which will allow getting and setting them synchronously, like
```js
StandardLibraryRegistry.get(moduleName);
StandardLibraryRegistry.set(moduleName, value);
```

Asynchronous fallbacks like layered APIs should be used only after this global registry.

As a bonus point, it would simplify transpiling native modules import to old syntax.

#### Decorators proposal, new iteration, stage 2

[In the new iteration](https://github.com/tc39/proposal-decorators) of this proposal, it has been seriously reworked. Decorator definitions aren't a syntax sugar anymore and, like with built-in modules, we will not be able to write a decorator in an old version of the language and use it as a native decorator. Other than that, decorators are not just usual identifiers - they live in a parallel lexical scope: this means that transpiled decorators can't interact with native decorators.

The proposal authors recommend distributing packages with untranspiled decorators and leaving to the library consumers the choice to transpile their dependencies. However, it's not possible in different scenarios. This approach could prevent `core-js` from polyfilling new built-in decorators when they will be added to the JS standard library.

Decorators should be just an alternative way of applying functions on something, they should only be syntax sugar for wrappers. Why complicate things?

---

If a new language feature does not introduce to the language something fundamentally new, an alternative for what couldn't be implemented in a previous version of the language, we should be able to transpile and/or polyfill it, and transpiled/polyfilled code should be able to interact with the native feature in engines which supports this feature natively.

I hope for the wisdom of the authors of those proposals and of the committee, that these proposals will be adapted so that it will be possible to properly transpile or polyfill them.

---

If you are interested in the `core-js` project or use it in your day-to-day work, you can become a sponsor on **[Open Collective](https://opencollective.com/core-js#sponsor)** or **[Patreon](https://www.patreon.com/zloirock)**. `core-js` isn't backed by a company: its future depends on you.

---

**Feel free to add comments to this article [here](https://github.com/zloirock/core-js/discussions/963).**

**[Denis Pushkarev](https://github.com/zloirock)**, **19-03-2019**, *thanks [Nicolò Ribaudo](https://github.com/nicolo-ribaudo) for redaction*