This content originally appeared on DEV Community 👩💻👨💻 and was authored by Matt Angelosanto
Written by Stanley Ulili✏️
Node.js has been a popular JavaScript runtime since its release in 2009. But the advent of two new runtimes, Deno and Bun, has brought a lot of hype for the new features they present in contrast to Node.
From afar, it may seem like Node.js is stagnating and nothing exciting is happening — but the reality is different. Two recent Node.js releases, v18 and v19, came with a lot of significant features:
- Experimental support for browser APIs, such as Fetch and the web streams API
- An experimental, inbuilt test runner
- Support for the recent version of Chromium's V8 engine
- Experimental support for
watch
mode, which replaces a tool like nodemon
In this tutorial, we will explore the following cool new features in Node.js v18 and v19:
- Node.js v18 features
- Inbuilt Fetch API
- Inbuilt test runner mode
- Web Streams API support
- Building binaries with the snapshot feature
- V8 engine upgraded to v10.1
-
watch
mode and other Node.js v19 features- HTTP(S)/1.1 KeepAliveby default
Node.js v18 features
Node.js v18 was released on April 19, 2022, and became a current release through October 2022, when Node.js v19 was released. A current release means that the version gains non-breaking features from a newer version of Node.js.
Node.js v18 gained the watch
mode feature, which was backported in Node v18 when v19 was released. On October 25, 2022, Node.js v18 was promoted to LTS (long-term support) and will continue receiving support until 2025.
The following are some of the features that are available in Node.js v18.
Inbuilt Fetch API
Before Node.js v18, you had to install node-fetch or Axios to request a resource from a server. With Node.js v18, you no longer need to install either package thanks to v18’s experimental Fetch API, which is available globally.
Let's look at how to use the Fetch API in Node.js v18. First, create a getData.js
file and add the following function that sends a request to an API:
async function fetchData() {
const response = await fetch(
"https://random-data-api.com/api/name/random_name"
);
if (response.ok) {
const data = await response.json();
console.log(data);
}
}
fetchData();
Save the file contents, then run the file with the node
command:
node getData.js
When the command runs, the output will look like the following:
(node:29835) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
{
id: 6638,
uid: '75026571-e272-4298-b2c0-c3e9e6363437',
name: 'Candy Kane',
...
prefix: 'Rep.',
initials: 'LBS'
}
In the output, Node.js logs a warning that the Fetch API is experimental. After the warning, we see the JSON data that the API returned.
Inbuilt test runner module
Developers typically use unit testing to test software components. From the early releases of Node.js, we could write simple tests with the assert
library. But as our tests grew larger, so did our need to organize tests and write descriptive messages.
As a solution, test runners such as Jest, Jasmine, and Mocha emerged, and have been the go-to tools for unit testing.
With the release of Node.js v18, a test runner is now included in Node.js and can be accessed with:
import test from 'node:test';
Note that we are using the node:
scheme to import the module. You can also use CommonJS:
const test = require('node:test')
Let's learn how to use it. First, initialize npm with the following:
npm init -y
In your package.json
file, enable the ES modules:
{
...
"license": "ISC"
"type": "module",
}
Next, create a math.js
file and add a function that returns the result of adding two numbers:
const sum = (a, b) => {
return a + b;
};
export default sum;
To test the function with the Node.js test runner, create a test.js
file with the following content:
import test from "node:test";
import assert from "assert/strict";
import sum from "./math.js";
test("Sum function", async (t) => {
await t.test("It should add two numbers", () => {
assert.equal(sum(2, 2), 4);
});
await t.test("It should not subtract numbers", () => {
assert.notEqual(sum(3, 2), 1);
});
});
In the first line, we import the test runner. In the second line, we import the assert
library, and subsequently, the sum()
function in the math.js
file.
After that, we create a test case that has two subtests, which test if the sum()
function works properly.
Now, run the tests:
node test.js
Your output will look like the following:
TAP version 13
# Subtest: Sum function
# Subtest: It should add two numbers
ok 1 - It should add two numbers
---
duration_ms: 1.171389
...
# Subtest: It should not subtract numbers
ok 2 - It should not subtract numbers
---
duration_ms: 0.279246
...
1..2
ok 1 - Sum function
---
duration_ms: 5.522232
...
1..1
# tests 1
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
In the output, we can see that Node.js has description messages of the tests that run.
Web Streams API support
The Web Streams API is an experimental feature in Node.js that lets you break a large file, like a video or text file, into smaller chunks that can be consumed gradually. This helps avoid memory issues. In older versions of Node.js, you could use Node.js streams to consume large files. But this functionality wasn't available for JavaScript apps in the browser. Later, WHATWG defined the Web Streams API, which has now become the standard for streaming data in JavaScript apps.
Node.js didn't support this API until v18. With v18, all of the Streams API objects, such as ReadableStream
, WritableStream
, and TransformStream
, are available. To learn more about how to use the Streams API, check out the documentation.
Building binaries with the snapshot feature
Another exciting feature is the ability to build a single-executable Node.js binary. Before Node.js v18, the only way to build a Node.js binary was to use a third-party package, like pkg.
But now, you can make use of the experimental snapshot flag --node-snapshot-main
to build a binary. For more details on how this feature works, see this tutorial.
V8 engine upgraded to v10.1
Node.js is built on top of the V8 engine, created by Google and maintained for Chromium to execute JavaScript. With each release, it introduces new features and some performance improvements, which end up in Node.js.
Google released V8 10.1, which introduced some new array methods, such as findLast()
and findLastIndex()
, as well as Intl.supportedValuesOf(code)
. The V8 engine also added new methods to the Intl.Locale
API, and optimized the class fields and private methods.
watch
mode and other Node.js v19 features
Node.js v19 was released on October 18, 2022. Since 19 is an odd number, it will never be promoted to LTS, but will continue receiving support until April 2023, when a new, even-numbered Node.js version is released.
While Node.js v19 has not released a lot of features in comparison to Node.js v18, it has shipped one of the most requested features to past Node versions as well: watch
mode.
When you create and start a server in Node.js, then later make changes to the file, Node.js doesn't pick up the new changes automatically. You either need to restart the server or use a tool like nodemon, which automatically reruns a file when it detects new changes.
With the release of Node.js v19, this is no longer necessary. Node v19, as well as Node ≥ v 18.11.0, is now able to automatically restart a process when it detects new changes using the node --watch
feature, which is currently experimental.
To run a file in watch mode, use the --watch
flag:
node --watch index.js
When you edit the index.js
file, you will see that the process automatically restarts and the new changes are reflected without stopping the server. As mentioned, this feature has also been backported to Node.js ≥ v18.11.0, which means you don't have to use Node.js v19 if this is the only feature you need.
HTTP(S)/1.1 KeepAlive
by default
Node.js uses an http.globalAgent
for outgoing HTTP connections and https.globalAgent
for outgoing HTTPS connections. These agents ensure TCP connection persistence as well as that HTTP clients can reuse the connections for multiple requests.
You can configure the agents to reuse connections by setting the HTTP 1.1 keepAlive
option to true
; otherwise, set it to false
to avoid reusing connections, which makes things slower.
For Node.js version ≤18, outgoing connections for HTTP/HTTPS have the keepAlive
option set to fal
se
, so connections are not reused for multiple requests, leading to slower performance. With Node.js v19, the keepAlive
option is now set to true
, which means your outgoing connections will be faster without doing any configurations.
Let's verify this. Assuming you are using nvm, you can install Node.js ≤ v18 and temporarily switch to it:
nvm install v18.12.1
node -v
// Output
// v18.12.1
Create a checkHttpAlive.js
file and add the following code to inspect the http.globalAgent
:
const http = require('node:http');
console.log(http.globalAgent);
Your output will look as follows:
// Output
Agent {
...
keepAliveMsecs: 1000,
keepAlive: false, // this is the keepAlive option
...
}
In the output, you will notice that keepAlive
is set to false
by default on Node v18.
Let's compare it with Node.js v19. Switch the Node.js version to v19 with nvm:
nvm install v19.0.1
node -v
// output:
// v19.0.1
Run the checkHttpAlive.js
file again:
node checkHttpAlive.js
The output will match the following:
// output
Agent {
...
keepAliveMsecs: 1000,
keepAlive: true,
...
}
In the output, you can see the keepAlive
option is set to true
by default in Node.js v19.
V8 engine upgrade to 10.7
The V8 Engine for Node.js v19 has been upgraded to version 10.7. It did not ship with a lot of features — it only added the Intl.NumberFormat
feature to the JavaScript API.
The Intl.NumberFormat
internationalizes a number as a currency. An example:
> new Intl.NumberFormat('en-US', { style: 'currency', currency: 'GBP' }).format(3392.10)
'£3,392.10' // output
Conclusion
In this article, we explored cool features in Node.js v18 and v19. First, we looked at the new features in v18, which include the inbuilt Fetch API, a new test runner and snapshot feature, watch
mode, and support for the Web Streams API. We then looked at new features in Node v19, which includes watch
mode, and the HTTP 1.1 keepAlive
feature.
As exciting as the new Node.js features are, most of these features already exist in Bun and Deno. The runtimes also include useful features, such as native TypeScript support, web sockets API, and execute faster than Node.js.
If you are not sure which Node.js version to use, I would recommend v18. Its support will last until 2025, unlike Node v19, whose support will end next year. If you want to learn about these features in more depth, refer to the documentation page.
200’s only ✔️ Monitor failed and slow network requests in production
Deploying a Node-based web app or website is the easy part. Making sure your Node instance continues to serve resources to your app is where things get tougher. If you’re interested in ensuring requests to the backend or third party services are successful, try LogRocket.
LogRocket is like a DVR for web apps, recording literally everything that happens on your site. Instead of guessing why problems happen, you can aggregate and report on problematic network requests to quickly understand the root cause.
LogRocket instruments your app to record baseline performance timings such as page load time, time to first byte, slow network requests, and also logs Redux, NgRx, and Vuex actions/state. Start monitoring for free.
This content originally appeared on DEV Community 👩💻👨💻 and was authored by Matt Angelosanto
Matt Angelosanto | Sciencx (2022-12-06T20:23:17+00:00) Exploring competitive features in Node.js v18 and v19. Retrieved from https://www.scien.cx/2022/12/06/exploring-competitive-features-in-node-js-v18-and-v19/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.