I like to write small scripts, but used to suggle when I want to use Javascript
to fetch API data, or use some helper packages. Then I go with Python instead.
But things have changed. With the supports of ES module and fetch
and
node:module
API. It is much easier now since I feel more comfortable using JS.
Unlike normal js
files, node treats mjs
files as ECMAScript modules. So
it means you can use any supported ES-next features w/o a transpiler like Babel.
In the past, to be able to use ES features, we had to set up build and compilation
tools like Webpack and Babel (due to conflicts between common JS require
is
synchronous but import
is asynchronous, NodeJS didn’t support import/export
natively until node 13). Webpack and Babel are not ment to do the jobs of Node.
anymore. We should use them now when we need code bundling and compile some
other language to JS such as JSX or new ES proposals still in staging. And even
worse, sometimes they can even hold you back from using new features added to
Javascripts if you don’t configurate it at latest version. I have suffered so
many times that I can’t use ...
, or Array.at
in my code just because my
project configuration is so outdated, not to mention the over advertised
Typescripts, migrating those tools just to use a natively supported feature is
pain in the a…
For example I want to write a script to quickly check current price of BTC on Binance. Write it to a json file for later if I want to do anything with that data. And we want to do it without installing any packages at all.
First of all, we know we’ll need to write some data, so we need some helps
from Node builtin fs
package.
import fs from 'node:fs/promises'
Here I use node:fs/promises
, new api return promises instead of callbacks.
And because it is builtin package, we don’t need to install like fs
.
Secondly, we need to get data from Binance API at https://api.binance.com/api/v3/ticker/price.
At this point, we have Node 18 released and it added fetch
, the dead simple
api for fetching data has been available in browsers for a long long time.
Other wise we would need to go through these tutorials again to know how to
fetch data with node https://blog.logrocket.com/5-ways-to-make-http-requests-in-node-js/
So our following lines of code look like this.
const response = await fetch('https://api.binance.com/api/v3/ticker/price')
if (response.ok) {
const data = await response.json()
}
Next, I want to find the price of BTC
to USDT
, so let’s loop through the
data and find it.
for (const pair of data) {
if (pair.symbol === 'BTCUSDT') {
console.log(`Current price of BTC is ${pair.price}`)
break
}
}
And finally, let’s backup our data in a file for later.
await fs.writeFile('./price.json', JSON.stringify(data, null, 2))
Let’s put it all together.
import fs from 'node:fs/promises'
const response = await fetch('https://api.binance.com/api/v3/ticker/price')
if (response.ok) {
const data = await response.json()
for (const pair of data) {
if (pair.symbol === 'BTCUSDT') {
console.log(`Current price of BTC is ${pair.price}`)
break
}
}
await fs.writeFile('./price.json', JSON.stringify(data, null, 2))
} else {
console.error('Cannot get BTC price')
process.exit(1)
}
If you save this file as price.js
and try to run it with node price.js
, you
will see the following error.
price.js:1
import fs from 'node:fs/promises'
^^^^^^
SyntaxError: Cannot use import statement outside a module
Because by default, Node treats js
files as Common JS module, so using
import
is not supported. We have three ways to let node know that we want to
run our script as an ES module.
Authors can tell Node.js to use the ECMAScript modules loader via the
.mjs
file extension, thepackage.json
“type” field, or the--input-type
flag.
https://nodejs.org/dist/latest-v18.x/docs/api/esm.html#enabling Without chaning the file name, we can either run this command
cat price.js | node --input-type=module
or create package.json
file
{
"type": "module"
}
and then run
$ node test.js
Current price of BTC is 21726.41000000
But I like the .mjs
the most because it the fastest way.
$ node test.mjs
Current price of BTC is 21716.93000000
In this example I also use top level await
, so much easier than Python
ev.run_until_complete()
.