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.
Related
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
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
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
Time is flying and now the Node.js ver.10.0.0 have been out for the public. While I'm working with my MERN stack, frequently I have to switch between ES6 import/export syntax for the front-end (React.JS) and the CommonJS module.exports/require syntax in my Node/Express server-side. And I'm really wish the writing style could be unified in import/export shortly without using Babel and get it from the native support.
A good news is since the last year I read James' post on Medium addressing in the difficulty of implementing the ES6 module system in Node.js, the experimental ECMAScript Modules is now in stability 1 for a while, which means it could be enabled by --experimental-modules flag.
However, when I'm trying to use import/export syntax on Node, it is never working. For example, I have try this:
import fs from 'fs';
console.log(typeof fs.readFile);
The above code will throw me error:
(function (exports, require, module, __filename, __dirname) { import fs from 'fs';
^^
SyntaxError: Unexpected identifier
I'm really sure I have enabled the experimental flag calling as $node --experimental-modules, so what should I really do in order to kick the ES6 import/export experimental module working on my Node local server? What am I missed?
Added:
The reason why I want to try this experimental feature is to have consistent coding style in both front and back. And because it is now available natively, so I want to get ready to it. Once it have been reach in stage 2, I then can adapted to import/export quickly and have less pain.
But obviously, Google (ref) and AirBnb(ref) have different view points upon if we should use import/export syntax or not in their code-style guide. And based on Google, I'm still surprising that the semantics of ES6 import/export is not yet finalized while ECMA2019 is on its way. I'm just wonder when I can really use import/export in my project, or what is really need to be finalized?
Updated:
After pointed out by Jaromanda X, if I changed my file name to .mjs then it works. Originally I thought is the module to be loaded have to be named in .mjs extension, but it seems I was wrong. However, if that is the case, which means I will need to renamed all my project file in .mjs... and that is not appealing. Just wonder if there is a way to use this feature it in the traditional .js file? What should I configure?
Right at this point ECMAScript Module is not yet finalized in node.js v10, so it is not recommended to use it in the production environment. Since the use of import/export is standardized in the ECMAScript specification, so no matter how, it is important for node to provide such supports for the community.
The major differences between require() and ECMAScript Module is how node is going to handle its cache. Unlike require(), so far ECMAScript Module have no such API to manipulate the module cache. Also, it is unknown if it would be directly supported in the normal *.js files without a loader, so stay tuned.
The direction right now is try to introduce a new *.mjs file to explicitly showing it used the standard JS module (in accordance with ES6), but if one read the doc closely you actually could see it is also possible to specify your own extension match, including the use of the more traditional *.js. However, it required more configurations and the use of --loader flag to load the extra configuration.
There are 6 different formats are supported, including the one for modules written in C++ (it can also be loaded by require()), which is very powerful. In short, to use *.js file extension, the key setting in the loader is to have:
const JS_EXTENSIONS = new Set(['.js', '.mjs']);
And the loader function will need to check as if the file to be loaded is in JS_EXTENSIONS data set. Here, the key in the loader function is that it should return an object that have two properties: url and format, i.e.:
return {
url: (...), // e.g. './x?n=1234'
format: 'esm', // there are 5 + 1 dynamic formatting
};
It would be recommended to named the loader as custom-loader.mjs, and use it as $node --experimental-modules --loader ./custom-loader.mjs since it was demonstrated in the official doc. Once you have configured the loader correctly (based on what you need), then you should be able to use import/export as if you may used in a front-end react app in your node project.
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.