Enable destructuring objects rest properties with Babel? - javascript

I noticed that Babel wasn't transforming this:
function({ param, ...rest }) {}
This syntax is already supported in the latest popular browsers. However, according to Mozilla (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment), it's not supported in browsers as new as Edge 79 (released this year).
I tried manually enabling some Babel plugins, but it didn't work:
#babel/plugin-transform-destructuring
#babel/plugin-proposal-object-rest-spread
#babel/plugin-syntax-object-rest-spread
#babel/plugin-transform-parameters
Is it possible to transform this syntax with Babel? I need to do testing in older browsers, but I'm getting SyntaxError: invalid property id because of this.

Sometimes babel needs to combine more than one plugins to transform something. In this case I think you would need to combine at least 2 plugins:
#babel/plugin-transform-destructuring
#babel/plugin-transform-parameters
npx babel /path/to/yourFile plugins=#babel/plugin-transform-destructuring,#babel/plugin-transform-parameters
To make life easier, I would suggest to use preset-env instead which supports official ES changes (since it includes all official plugins for you):
npx babel /path/to/yourFile presets=#babel/preset-env

Related

SAFARI : Unexpected token '='. Expected an opening '(' before a method's parameter list

Got this code, that works perfectly in all browsers but not in Safari (Version 11.1.2).
class Account {
accountFields = ['field1', 'field2', 'field3']
}
Getting the following error in Safari debugger:
Unexpected token '='. Expected an opening '(' before a method's
parameter list
So I tried to add () everywhere, around the array, before, after, etc. Nothing works.
You're using a relatively new feature known as public field declarations. It's currently supported by most modern browsers. However, the only Safari versions that support this feature are v14.1 (released April 26th, 2021) and higher. If you need to support older versions of Safari / a wider variety of older browsers you'll need to follow one of the suggestions below.
Instead of using public field declarations, you can use a constructor() method to define the properties for your class instances. Using a constructor does have good browser compatibility (for IE support you can use a constructor function):
class Account {
constructor() {
this.accountFields = ['field1', 'field2', 'field3'];
}
}
As pointed out in the comments by #Baz, you can also use Babel as an alternative solution. Using babel means that you won't have to change your code, which can make things easier on you if you're using public field declarations a lot throughout your project. Babel will transpile/compile your modern JS code into older (ES5 and below) JS code which can be understood by many browsers. You can use this babel plugin like so.
First, install the babel plugin:
npm install --save-dev #babel/plugin-proposal-class-properties
Then add the plugin to your configuration file:
{
"plugins": ["#babel/plugin-proposal-class-properties"]
}
For other installation options (babel CLI, etc), see the usage section of the plugin's docs.
I got a similar issue, in my case it was working with Safari on my Mac, but not on my iPad.
I was using deno and esbuild to build my bundle, I just changed added the --target=safari11 option to esbuild command.
I changed something like this
deno bundle entry.js | esbuild --minify > bundle.js
to this
deno bundle entry.js | esbuild --minify --target=safari11 > bundle.js

es2018 vs es2018.promise vs es2018.regexp

TypeScript compiler has the following options for the --lib cmd line arg:
ES2018
ES2018.Promise
ES2018.RegExp
What is the difference between them? Should I use ES2018 or ES2018.Promise if I need Promisefinally() support only and do NOT care about other ES2018 features?
Also, since what TS version those ES2018 libs are supported? When I try to use them with TS 2.6.2, it throws:
Error: tsconfig.json(16,13): error TS6046: Argument for '--lib' option
must be: 'es5', 'es6', 'es2015', 'es7', 'es2016', 'es2017', 'esnext',
'dom', 'dom.iterable', 'webworker', 'scripthost', 'es2015.core',
'es2015.collection', 'es2015.generator', 'es2015.iterable',
'es2015.promise', 'es2015.proxy', 'es2015.reflect', 'es2015.symbol',
'es2015.symbol.wellknown', 'es2016.array.include', 'es2017.object',
'es2017.sharedmemory', 'es2017.string', 'es2017.intl',
'esnext.asynciterable'.
The lib option only provide typing for these libraries. If you specify ES2018 than you will get ES2018 typing even if you target for ES2015. By default, TypeScript sets some libs depending on which target you specify but it allows you since version 2.0 to manually add more typing.
What is the difference between them?
They are a subset of different families of features.
Should I use ES2018 or ES2018.Promise if I need Promisefinally()
support only and do NOT care about other ES2018 features?
Yes, you are can scope to what you need. However, it won't increase your generated JavaScript if you include more.
Since what TS version those ES2018 libs are supported?
If you are using a target that does not support a feature natively, you may download (npm) a package to Polyfill. It's not related directly to a TS version.

Extending MediaSource with Babel -- how to properly call super()?

I'd like to extend MediaSource. I'm using Babel.
class BradMediaSource extends MediaSource {
constructor() {
super();
}
}
const source = new BradMediaSource();
In Chrome directly, this works fine. In a transpiled build done with Babel, I get the following error:
Uncaught TypeError: Failed to construct 'MediaSource': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
This seems similar to this GitHub issue: https://github.com/babel/babel/issues/1966 I have also tried the following package, but it doesn't seem to apply to my specific situation... makes no difference: https://www.npmjs.com/package/babel-plugin-transform-custom-element-classes
My .babelrc:
{ "presets": [ "es2015" ] }
Is there a way around this problem?
Generally extending builtin types does not work with compiled classes from Babel, so you'd need to configure Babel to not process classes, and limit your application to only browsers that support classes.
Assuming your target browsers all support ES6 class syntax, the easiest approach would be to use babel-preset-env configured for those target environments.
You can also try to use transform-builtin-extend in your Babel config for MediaSource, though that does tend to vary with exactly which things can be extended.

Using async/await in Node 6 with Babel

I'm trying to configure Babel for Node v6.9.2. I want to use async/await constructs.
Because I'm new to Babel and all Node infrastructure, I confused how to configure it properly:
What preset should I use? Node is already implemented most of the ES6 features. So I don't want Babel to transpile features already supported by Node 6.9.x (arrow functions, new import mechanism etc) for performance reasons.
What plugins should I include so I can use async/await? There I also confused, because after some researching I found several plugins: syntax-async-functions, transform-async-to-generator and some more.
Example of .babelrc will help.
Thanks
What preset should I use?
You don't need to use any preset. Presets are just a collection of plugins which makes it easier to use if you want to transpile a set of features (for instance all ES2015 with preset-es2015). But when you want to transpile only a selection of these features, you only include the corresponding plugins.
What plugins should I include so I can use async/await?
Because Node 6 supports generators, you can use transform-async-to-generator with the following .babelrc:
{
"plugins": ["transform-async-to-generator"]
}
And of course you would need to add plugins if you need to transpile more unsupported features.
Alternative babel-preset-env
babel-preset-env automatically determines what plugins you need for the specified environment. This will not include any plugins that are not necessary. To specify your current Node version you would use this .babelrc:
{
"presets": [
["env", {
"targets": {
"node": "current"
}
}]
]
}
Short answer
Use Babel preset for Node 6.x:
https://www.npmjs.com/package/babel-preset-node6
Long answer
To see what ES feature is supported in a given Node version, see:
http://node.green/
For async/await support in particular, see:
http://node.green/#ES2017-features-async-functions
If you use Node v7.x (the current version) then you can use the --harmony flag and use async/await natively without transpilation.
Node v8.x (available as nightly builds) doesn't even need the --harmony flag for that.
But note that Node doesn't support import/export - to know why see:
javascript - Why is there a spec for sync and async modules?
Exporting Node module from promise result

standard babel presets requirements

In order to setup webpack + babel + react, I was told to include following in .babelrc:
"presets": ["latest", "stage-0", "react"]
I want to understand: why should I use babel presets, what do they allow me to do (apart from babel itself)? That's one question. Hope that's not opinion-based (in terms of stackoverflow), it's about how babel works.
As far as I read in the docs, preset-latest combines preset-es2015 + preset-es2016 + preset-es2017. As far as I understand, these are officially accepted features of upcoming ES versions and latest is a shorthand for choosing not only ES2015, but all future versions at one shot. The specs won't change, so it's stable enough to use in production.
But how about stage-0, stage-1, stage-2, stage-3 - do they represent features that are still unofficial proposals of upcoming ECMAScript versions or does that stand for something else? Babel docs is not clear about that. That's second question.
And finally, what is the difference between a plugin and a preset?
...why should I use babel presets, what do they allow me to do...
A Babel preset conveniently defines a group of Babel plugins so that you don't have to explicitly declare you want to use each of them under "plugins" in your .babelrc (or wherever you declare your config).
Take a look at the source code of the es2016 preset and you'll see what I mean... it simply exports an array of plugins: https://github.com/babel/babel/blob/master/packages/babel-preset-es2016/src/index.js
...(apart from babel itself)?
Babel itself is an interface for its plugins. It utilises a sibling program, babylon, a fork of acorn, that provides plugins a particular way of parsing, inspecting, and then manipulating the source code of your program, in order to add the features you want according to the plugins you use.
And finally, what is the difference between a plugin and a preset?
As discussed, a preset itself does not contain features, rather a list of plugins. Together these typically represent some related group of functionality. For example, the stage-0 preset will contain all plugins that implement features of proposals which are at stage zero of the process of submission defined by TC39, ECMAScript's "governing body".
You might have noticed that a preset is a JavaScript file instead of JSON. This is because the list of plugins that a preset defines can be derived from a configuration. Take a look at the env preset, for example: https://github.com/babel/babel-preset-env/blob/master/src/index.js
But how about stage-0, stage-1, stage-2, stage-3 - do they represent features that are still unofficial proposals of upcoming ECMAScript versions or does that stand for something else?
There are no "official" proposals. A proposal can be submitted by anyone. But if what you mean by official is whether the proposal is being seriously considered, that is determined by 1) what stage it is at in the process and 2) general consideration by the community of its worth as a new feature. However you should always take proposals with a pinch of salt in terms of whether they will be accepted, even at the last stage, as we have experienced with Object#observe, which was dropped at the very last minute.
I also didn't understand why "modules": false and why there is an "env" setting and that env has its own preset configuration.
Finally, I found this article What's in our .babelrc? explains it well, e.g
Secondly, we set modules to false to ensure that import statements are
left as is (opposed to transpiling them to require). We're doing this
to give Webpack the ability to statically analyze our code to produce
more efficient bundles.
Lastly, we have an environment specific override for Jest, our testing
framework of choice. Since Jest is run in node, we need to transpile
our imports to requires, and target whatever node runtime we're
currently working in.

Categories

Resources