From 0cc8a0223e3ee16d747d70c7696465ea6d9ba9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Tue, 5 Nov 2019 12:08:42 +0100 Subject: [PATCH] Create 2019-11-05-7.7.0.md (#2120) --- website/blog/2019-11-05-7.7.0.md | 244 +++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 website/blog/2019-11-05-7.7.0.md diff --git a/website/blog/2019-11-05-7.7.0.md b/website/blog/2019-11-05-7.7.0.md new file mode 100644 index 0000000000..1073071cc8 --- /dev/null +++ b/website/blog/2019-11-05-7.7.0.md @@ -0,0 +1,244 @@ +--- +layout: post +title: "7.7.0 Released: Error recovery and TypeScript 3.7" +author: Nicolò Ribaudo +authorURL: https://twitter.com/NicoloRibaudo +date: 2019-11-05 10:00:00 +categories: announcements +share_text: "Babel 7.7.0 Released" +--- + +Today we are releasing Babel 7.7.0! + +This release includes new parser features like top-level await (`await x()`, [Stage 3](https://github.com/tc39/proposal-top-level-await)) and Flow `enum` declarations ([Flow proposal](https://github.com/gkz/enums)). And now, `@babel/parser` has the option of recovering from certain syntax errors! + +We've also added support for [TypeScript 3.7](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc/): Babel can parse and transform private class fields with type annotations, public class fields annotations defined using the `declare` keyword, type assertion function signatures and template literals in `enum` declarations. + +Babel now understands three new configuration files: `babel.config.json`, `babel.config.cjs` and `.babelrc.cjs`, which behave the same as `babel.config.js` and `.babelrc.js` files. + +Lastly, Babel 7.7.0 uses 20% less memory than 7.6.0. + +You can read the whole changelog [on GitHub](https://github.com/babel/babel/releases/tag/v7.7.0). + + + +--- + +Shoutout to [Alejandro Sánchez](https://github.com/alejo90), [Chris Garrett](https://github.com/pzuraq), [彭驰](https://github.com/chris-peng-1244), [Daniel Arthur Gallagher](https://github.com/DanArthurGallagher), [ExE-Boss](https://twitter.com/ExE_Boss), [Eugene Myunster](https://github.com/t0lkman), [Georgii Dolzhykov](https://github.com/thorn0), [Gerald](https://twitter.com/gera2ld), [Linus Unnebäck](https://github.com/LinusU), [Martin Forsgren](https://github.com/dentrado), [Matthew Whitworth](https://github.com/mwhitworth), [Micah Zoltu](https://github.com/MicahZoltu), [Mohammad Ahmadi](https://github.com/m-ahmadi) and [Samuel Kwok](https://github.com/samMeow) for their first PRs! + +This release has also been made possible thanks to collaboration with teams of other open source projects: thanks to [Devon Govett](https://twitter.com/devongovett) ([Parcel](https://parceljs.org/)) for implementing support for `babel.config.json` files, and to [George Zahariev](https://twitter.com/gkzahariev) ([Flow](https://flow.org/)) for adding Flow `enum` declarations to `@babel/parser`! + +Another special thanks goes to [Bloomberg](https://www.techatbloomberg.com/) for organizing an Open Source Hackaton to encourage their engineers to give back to the community! In particular, [Robin Ricard](https://twitter.com/r_ricard) and [Jaideep Bhoosreddy](https://twitter.com/jbhoosreddy) who are actively working on automating the testing of Babel transforms against the [Test262 suite](https://github.com/tc39/test262). + +If you or your company want to support Babel and the evolution of JavaScript, but aren't sure how, you can donate to us on [OpenCollective](https://opencollective.com/babel) and, better yet, work with us on the implementation of [new ECMAScript proposals](https://github.com/babel/proposals) directly! As a volunteer-driven project, we rely on the community's support to both fund our efforts in supporting the wide range of JavaScript users and taking ownership of the code. Reach out to Henry at [henry@babeljs.io](mailto:henry@babeljs.io) if you'd like to talk more! + + +## Highlights + +### Top-level `await` parsing ([#10449](https://github.com/babel/babel/pull/10449)) + +The top-level `await` [proposal](https://github.com/tc39/proposal-top-level-await) allows you to `await` promises in modules as if they were wrapped in a big async function. This is useful, for example, to conditionally load a dependency or to perform app initialization: + +```javascript +// Dynamic dependency path +const strings = await import(`./i18n/${navigator.language}.mjs`); + +// Resource initialization +const connection = await dbConnector(); +``` + +`@babel/parser` has supported using `await` outside of async functions via the `allowAwaitOutsideFunction` option since version 7.0.0. + +Version 7.7.0 introduces a new `topLevelAwait` parser plugin, which has a few key differences: + +- It only allows top-level `await` inside modules and not inside scripts, as the proposal mandates. This is needed because synchronous script-based module systems (like CommonJS) cannot support an async dependency. +- It allows to detect the correct `sourceType` when `sourceType: "unambiguous"` is used. Note that, since `await` is a valid identifier in scripts, many constructs which may seem unambiguously modules are actually ambiguous and Babel will parse them as scripts. + For example, `await -1` could either be an await expression which waits for `-1`, or a difference between `await` and `1`. + +If you are using `@babel/parser` directly, you can enable the `topLevelAwait` plugin: +```javascript +parser.parse(inputCode, { + plugins: ["topLevelAwait"] +}); +``` + +We also created the `@babel/plugin-syntax-top-level-await` package, which you can add to your Babel configuration: +```javascript +// babel.config.js + +module.exports = { + plugins: [ + "@babel/plugin-syntax-top-level-await" + ] +} +``` + +Please note that usage of top-level `await` assumes support within your module bundler. Babel itself isn't doing transformations: if you are using Rollup you can enable the [`experimentalTopLevelAwait`](https://rollupjs.org/guide/en/#experimentaltoplevelawait) option, and webpack 5 supports the [`experiments.topLevelAwait`](https://github.com/webpack/webpack/releases/tag/v5.0.0-alpha.15) option. + +Starting from this release, `@babel/preset-env` will automatically enable `@babel/plugin-syntax-top-level-await` if the `caller` supports it. *Note*: `babel-loader` and `rollup-plugin-babel` don't yet tell Babel that they support this syntax, but we are working on it with the respective maintainers. + +### Parser error recovery ([#10363](https://github.com/babel/babel/pull/10363)) + +Like many other JavaScript parsers, `@babel/parser` throws an error whenever some invalid syntax is encountered. This behavior works well for Babel, since in order to transform a JavaScript program to another program we must first be sure that the input is valid. + +Given Babel's popularity, there are many other tools relying on `@babel/parser`: above all `babel-eslint` and Prettier. For both these tools, a parser which bails out on the first error is suboptimal. + +Consider this code, which is invalid because of the duplicated `__proto__` property: + +```javascript +let a = { + __proto__: x, + __proto__: y +} + +let a = 2; +``` + +The current workflow with ESLint and Prettier is the following: +1. Prettier can't format the file +1. ESLint reports an `Redefinition of __proto__ property` parser error +1. You remove the second `__proto__` property +1. Prettier can't format the file +1. ESLint reports an `Identifier 'a' has already been declared` error +1. You remove the second `let` keyword +1. Prettier formats the file + +Wouldn't it better if it was more like this? +1. Prettier formats the file +1. ESLint reports two errors: `Redefinition of __proto__ property` and `Identifier 'a' has already been declared` +1. You remove the second `__proto__` property and the second `let` keyword + +In this release, we are adding a new option to `@babel/parser`: `errorRecovery`. When it is set to true, the resulting AST will have an `errors` property containing all the errors which `@babel/parser` was able to recover from: + +```javascript +const input = ` +let a = { + __proto__: x, + __proto__: y +} + +let a = 2; +`; + +parser.parse(input); // Throws "Redefinition of __proto__ property" + +const ast = parser.parse(input, { errorRecovery: true }); +ast.errors == [ + SyntaxError: "Redefinition of __proto__ property", + SyntaxError: "Identifier 'a' has already been declared", +]; +``` + +`@babel/parser` can still throw as not every error is currently recoverable. We'll continue to improve these cases! + +### New configuration file extensions ([#10501](https://github.com/babel/babel/pull/10501), [#10599](https://github.com/babel/babel/pull/10599)) + +Babel 6 only supported a single configuration file: `.babelrc`, whose contents must be specified using JSON. + +Babel 7 changed the meaning of `.babelrc`s and introduced two new configuration files: `babel.config.js` and `.babelrc.js` (you can read about the difference between them in the [docs](https://babeljs.io/docs/en/config-files)). We added configuration files with JavaScript to allow defining your own logic when enabling/disabling plugins/options. + +However a big benefit of JSON files is easier _cacheability_. The same JavaScript file can produce different values when called two times, while a JSON file is guaranteed to always evaluate to the same object. Also, JSON configurations are easily serializable, while it's not possible to serialize JavaScript values like functions or JavaScript objects with implicit data or relationships. + +Note that Babel also caches transforms when using JavaScript-based configurations, but the config file must be evaluated (in order to know if the cache is still valid) and the cache [manually configured](https://babeljs.io/docs/en/config-files#apicache). + +For these reasons, Babel 7.7.0 introduces support for a new configuration file: `babel.config.json`, whose behavior is the same as `babel.config.js`. + +We also added support for two different configuration files: `babel.config.cjs` and `.babelrc.cjs`, which must be used when using node's [`"type": "module"`](https://nodejs.org/api/esm.html#esm_code_package_json_code_code_type_code_field) option in `package.json` (because Babel doesn't support ECMAScript modules in config files). Apart from this `"type": "module"` difference, they behave exactly like `babel.config.js` and `.babelrc.js`. + +### TypeScript 3.7 ([#10543](https://github.com/babel/babel/pull/10543), [#10545](https://github.com/babel/babel/pull/10545)) + +[TypeScript 3.7 RC](https://devblogs.microsoft.com/typescript/announcing-typescript-3-7-rc) includes support for optional chaining, nullish coalescing operator, assertion functions, type-only field declarations and many more type-related features. + +Optional chaining (`a?.b`) and nullish coalescing (`a ?? b`) have been supported in Babel since 7.0.0 via `@babel/plugin-proposal-optional-chaining` and `@babel/plugin-proposal-nullish-coalescing-operator`. + +In Babel 7.7.0, you can now use assertion functions and `declare` in class fields: + +```typescript +function assertString(x): assert x is string { + if (typeof x !== "string") throw new Error("It must be a string!"); +} + +class Developer extends Person { + declare usingBabel: boolean; +} +``` + +To avoid breaking changes, we introduced support for `declare` in class fields behind a flag: `"allowDeclareFields"`, supported by both `@babel/plugin-transform-typescript` and `@babel/preset-typescript`. This will likely become default behavior, so it is recommended that you migrate your config to use it: + +```jsonld +{ + "presets": [ + ["@babel/preset-typescript", { + "allowDeclareFields": true + }] + ] +} +``` + +### Use object spread in compiled JSX ([#10572](https://github.com/babel/babel/pull/10572)) + +When using spread properties in JSX elements, Babel injects a runtime helper by default: + +```jsx + + +// 🡇 🡇 🡇 + +function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } + +React.createElement("a", _extends({ + x: true +}, y)); +``` + +In 2016, as support for native ES6 improved, we added the `useBuiltIns` option to `@babel/plugin-transform-react-jsx` which allowed the compiled output to directly use `Object.assign` and removed excess code: + +```jsx + + +// 🡇 🡇 🡇 + +React.createElement("a", Object.assign({ + x: true +}, y)); +``` + +However given the native support for object spread, it allows us to produce even more optimized code: + +```jsx + + +// 🡇 🡇 🡇 + +React.createElement("a", { x: true, ...y }); +``` + +You can enable it using the `useSpread` option with either `@babel/preset-react` or `@babel/plugin-transform-react-jsx`: + +```jsonld +{ + presets: [ + ["@babel/react", { useSpread: true }] + ] +} +``` + +### Memory usage improvements ([#10480](https://github.com/babel/babel/pull/10480)) + +Since the beginning, we have been making efforts ([#433](https://github.com/babel/babel/pull/433), [#3475](https://github.com/babel/babel/pull/3475), [#7028](https://github.com/babel/babel/pull/7028), etc.) to improve performance. Babel 7.7.0 now uses 20% less memory, and transforms large files 8% faster when compared to 7.6.0. + +In order to achieve these results, we optimized different operations done during the lifetime `NodePath` objects (used to wrap every AST node): + +1. We now avoid initializing some rarely used object properties until they are needed, allowing us to avoid an `Object.create(null)` allocation for almost every AST node. + +1. We reduced bookkeeping workload for every single node visit, by replacing a few uncommon properties with getters so that `@babel/traverse` can skip updating them. + +1. We optimized memory usage by compressing several boolean properties used to represent the status of a node traversal (i.e. skipped, stopped or removed) into a [bit array](https://en.wikipedia.org/wiki/Bit_array). + +All these improvements add up to the following difference in transform performance and memory usage: + +| Performance | Memory usage | +|:-----------:|:------------:| +| ![](https://i.imgur.com/bs3DoOX.png) | ![](https://i.imgur.com/n1bQSj1.png) | + +You can also checkout the [raw data](https://docs.google.com/spreadsheets/d/1lFUKviJwJP83SulEG7tHoaHO4bvxPt1u2UrEySrPAXc/edit?usp=sharing) of the charts above. If you want to read more about this topic, you can read [Jùnliàng's detailed write-up](https://hackmd.io/@VQ5Lhi9URomRC0KamZdyvw/ryuUaFGwS) about the changes he made to get those improvements!