How to use optional chaining in Node.js 12 - javascript

Optional chaining (obj?.param1?.param2) seems to be a great feature and I really wanted to see it implemented and finally get rid of nested ifs, arbitrary functions and what not for such a simple operation.
But there's a problem, it doesn't work. I updated to Node 12 and I still get an error:
var dude = res?.param?.params[0]
SyntaxError: Unexpected token '.'
or
var dude = res.param?.params[0]
SyntaxError: Unexpected token '.'
What is the problem?
Do I need to change some language config or download a library to enable this feature? Or is it simply not out yet?

Optional chaining is currently not supported in Node.js version 13 and below. It will be supported from Node.js version 14 and most of the browsers as it is moved to Stage 4. Currently, few platforms are supporting it. You can find the list of platforms supporting optional chaining in the given link. You can enable optional using --harmony flag.

The spec for the optional chaining feature was just promoted to Stage 4 (Finished) on December 22, 2019. Node 12 came out before the spec was final - and so did Node 13, for that matter.
According to node.green, optional chaining will be supported starting with Node 14, but will still require the --harmony flag. (This seems to conflict with Node's description of the --harmony flag - V8's shipping features aren't supposed to require the flag - so I'm not sure what to make of that.) Still, whether it needs a flag or not, I wouldn't expect to see the feature until the Node 14 release around April 2020.
If you want to play with optional chaining today, your best bet is to use TypeScript (which added optional chaining in version 3.7) or a preprocessor like Babel.

I was able to use nodejs v13.7.0 with --harmony flag.
node --harmony myCode.js
Dinah
undefined
undefined
//myCode.js
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
};
const catName = adventurer.cat?.name;
console.log(catName);
// expected output: Dinah
const dogName = adventurer.dog?.name;
console.log(dogName);
//expected output: undefined
console.log(adventurer.someNonExistentMethod?.())
//expected output: undefined

Optional Chaining will be implemented with Node.js v14, which will be released on 20/04/2020. By now, you may use Babel with #babel/plugin-proposal-optional-chaining.

If you're still having this issue, check the node version you're using node --version.
If you have nvm, make sure you're using a node version that implements the operator that is giving an error.
e.g.
nvm install 15.8
nvm use 15.8

Related

Enable destructuring objects rest properties with Babel?

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

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

I use gradle to build playframework,but minifyPlayBinaryPlayJavaScript not support ES6

I use gradle to build playframework
like this: https://docs.gradle.org/current/userguide/play_plugin.html
My webpage use webpack,react,redux,ES6,babel.
webpack build is ok.
but,when i run gradle run,
This is the exceptions:
D:\workspace\gm>gradle run
:gm:minifyPlayBinaryPlayJavaScript FAILED
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':gm:minifyPlayBinaryPlayJavaScript'.
Minification failed with the following errors:
JSC_PARSE_ERROR. Parse error. primary expression expected at D:\workspace\gm\app\assets\javascripts\containers\App.js line 15 : 13
ES6_FEATURE. this language feature is only supported in es6 mode: modules. Use --language_in=ECMASCRIPT6 or ECMASCRIPT6_STRICT to enable ES6 features. at D:\workspace\gm\app\assets\javascripts\middleware\middleware.js line 2 : 0
ES6_FEATURE. this language feature is only supported in es6 mode: short function syntax. Use --language_in=ECMASCRIPT6 or ECMASCRIPT6_STRICT to enable ES6 features. at D:\workspace\gm\app\assets\javascripts\middleware\middleware.js line 2 : 15
ES6_FEATURE. this language feature is only supported in es6 mode: short function syntax. Use --language_in=ECMASCRIPT6 or ECMASCRIPT6_STRICT to enable ES6 features. at D:\workspace\gm\app\assets\javascripts\middleware\middleware.js line 2 : 24
I don't know where to set --language_in=ECMASCRIPT6
Please help me - -
(ps:when will gradle support playframework2.5.X)

How Can I Destructure an Argument With a Default?

When I run the following snippet in Chrome, it runs perfectly:
(({foo}={}) => {console.log(foo);})({foo: 'baz'});
// logs "baz"
However, if I run that same snippet in Node I get a:
ReferenceError: Invalid left-hand side in assignment
... despite the fact that I ran Node with both the default and destructuring harmony parameters:
nodejs --harmony --harmony_destructuring --harmony_default_parameters
So, my question is, what magic incantation does Node require to process this (perfectly valid, as far as I can tell) ES6 statement?
As #dvlsg suggested, this is simply a bug in the experimental implementation of these Node features.
However, as #estus suggested, and as indicated by the Node developers themselves here, the soon-to-be-released new version of Node will not only fix this problem, it will also roll the bulk of the ES6 functionality directly in to Node (ie. no more node --harmony_whatever).

ReferenceError: Intl is not defined in Node.js

I'm trying to construct a new Intl.Collator() object in Node.js.
Does anyone know why the Intl object wouldn't be present in a Node runtime?
According to MDN, it is specified as a Namespace by ECMAScript, so I don't see why it wouldn't be there.
Unfortunately node currently (as of version 0.10, at time of writing) does not support the ECMA-402 Intl object unless you perform a custom compile of node, which is documented in the node.js Readme.
With libicu i18n support:
svn checkout --force --revision 214189 \
http://src.chromium.org/svn/trunk/deps/third_party/icu46 \
deps/v8/third_party/icu46
./configure --with-icu-path=deps/v8/third_party/icu46/icu.gyp
make
make install
If compiling a custom build of node is not an option or the idea fills you with dread, a workaround is to use the intl module, a Javascript polyfill which covers much of the EMCA-402 standard, except for the Intl.Collator, the reasons for which are covered in the project Readme file.
Using the module is straight-forward:
npm install intl --save
Then in your node code:
var Intl = require('intl');
console.log(new Intl.NumberFormat("de-DE").format(12345678));
Hope this helps.
Since io.js was merged into Node, it should be possible to use Intl in newer versions of Node (available in io.js from v3.1.0).
intl: Intl support using small-icu is now enabled by default in builds (Steven R. Loomis) #2264.
String#normalize() can now be used for unicode normalization.
The Intl object and various String and Number methods are present, but only support the English locale.
For support of all locales, node must be built with full-icu.
https://github.com/nodejs/node/blob/master/CHANGELOG.md#2015-08-18-version-310-fishrock123
Node 0.12 has included support to Intl, but it comes with only a subset of ICU locales (i.e.: English). You need to build Node with flags for full ICU (or any subset you need). Long instructions for ICU build here: https://github.com/nodejs/node/wiki/Intl
I would recommend reading the FormatJS documentation:
http://formatjs.io/
And especially the Intl Polyfill
https://github.com/andyearnshaw/Intl.js
var areIntlLocalesSupported = require('intl-locales-supported');
var localesMyAppSupports = [
/* list locales here */
];
if (global.Intl) {
// Determine if the built-in `Intl` has the locale data we need.
if (!areIntlLocalesSupported(localesMyAppSupports)) {
// `Intl` exists, but it doesn't have the data we need, so load the
// polyfill and replace the constructors we need with the polyfill's.
require('intl');
Intl.NumberFormat = IntlPolyfill.NumberFormat;
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;
}
} else {
// No `Intl`, so use and load the polyfill.
global.Intl = require('intl');
}
Intl.js does not (and will never) implement Intl.Collator. For this one, you really need to rely on Node 0.12 built with your required locales.

Categories

Resources