Introduction 🚀
There's a common misconception that Node.js is outdated. In fact, it’s constantly evolving, with recent updates introducing a plethora of features that modernize its functionality. Let’s dive into these exciting new features and see how they can transform your development experience.
TypeScript Support 🛠️
Node.js now has built-in support for TypeScript, a massive win for developers who prefer static typing. Traditionally, running a TypeScript file in Node.js resulted in parsing errors, but with the latest experimental features, you can run .ts
files using the --experimental-strip-types
flag.
node --experimental-strip-types index.ts
This flag removes TypeScript types, allowing the code to run as standard JavaScript.
(node:5600) ExperimentalWarning: Type Stripping is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
(node:5600) [MODULE_TYPELESS_PACKAGE_JSON] Warning: /NodeJS/amazing-features/index.ts parsed as an ES module because module syntax was detected; to avoid the performance penalty of syntax detection, add "type": "module" to your package.json.
Although the feature is experimental, it works well in most cases. You can further enhance performance by adding "type": "module"
in your package.json
:
{
"name": "amazing-features-of-nodejs",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"typescript": "^5.6.2"
}
}
After adding "type": "module"
, the warning about module syntax will be resolved.
Built-In Test Runner 🧪
One of the most exciting new features is the built-in test runner in Node.js. You can now run tests natively without needing external libraries like Jest. The built-in test runner allows you to create test files using describe
and it
functions directly from Node.js.
Here’s an example of a index.test.js
file for a TypeScript module:
import assert from "node:assert";
import { describe, it } from "node:test";
import { IsAdult } from "./index.ts";
describe("#isAdult", () => {
it("Checks if a user is an adult", () => {
assert(IsAdult(29));
});
});
Make sure to import the TypeScript file with the .ts
extension. Run the test using the following command:
node --experimental-strip-types --test
The output will look like this:
▶ #isAdult
✔ Check if user is an adult (5ms)
ℹ tests 1
ℹ suites 1
ℹ pass 1
ℹ duration 449ms
You can also add test coverage with the --experimental-test-coverage
flag:
node --experimental-strip-types --experimental-test-coverage --test
For even more control, you can modify the test output format by using the --test-reporter
flag.
node --experimental-strip-types --experimental-test-coverage --test-reporter tap --test
Watch Flag ⏳
node --watch --experimental-strip-types --experimental-test-coverage --test-reporter tap --test
The --watch
flag automatically reruns your code whenever files change, eliminating the need for tools like Nodemon. Simply run your tests with the --watch
flag, and Node.js will monitor file changes, re-running tests automatically.
Environment File Support 🌍
Node.js now supports loading environment variables directly from a .env
file using the --env-file
flag, making environment management simpler.
Create a .env
file with your variables:
SECRET_VALUE="your-secret-value"
Access your variables in Node.js like this:
console.log(process.env.SECRET_VALUE); // your-secret-value
Run your app with:
node --experimental-strip-types --env-file=.env index.ts
Promises in Standard Libraries 📜
Node.js is moving towards a promise-based approach across its standard libraries. For example, the fs.readFile
method now supports promises:
import { readFile } from "fs/promises";
const file = await readFile("./index.ts");
console.log(file); // <Buffer 69...>
This change makes asynchronous code cleaner and more manageable by using await
instead of callbacks.
Top-Level Await ⏩
Node.js now supports top-level await, allowing you to use the await
keyword outside of async
functions:
const file = await readFile("./index.ts");
console.log(file);
This feature improves code readability and removes the need for wrapping code in async
functions.
Glob File Search 🔍
You can now search for files using glob patterns directly in Node.js:
import { glob } from "fs/promises";
const testFile = await glob("**/*.test.js").next();
console.log(testFile); // { value: 'index.test.js', done: false }
Built-In Debugger 🐞
Node.js includes a built-in debugger that works seamlessly with Chrome DevTools. To start debugging:
node --experimental-strip-types --env-file=.env --inspect-brk index.ts
WebSocket Support 🌐
Node.js has added built-in support for WebSockets, allowing you to connect to WebSocket servers directly:
new WebSocket("wss://your-websocket-url");
SQLite Support 🗄️
Node.js now offers built-in support for SQLite databases. Here's how to create an in-memory SQLite database and interact with it:
import { DatabaseSync } from "node:sqlite";
const database = new DatabaseSync(":memory:");
database.exec(`CREATE TABLE data(key INTEGER PRIMARY KEY, value TEXT) STRICT`);
const insert = database.prepare("INSERT INTO data (key, value) VALUES (?, ?)");
insert.run(1, "hello");
insert.run(2, "world!");
const query = database.prepare("SELECT * FROM data ORDER BY key");
console.log(query.all()); // [{ key: 1, value: 'hello' }, { key: 2, value: 'world!' }]
To run the code, use:
node --experimental-strip-types --experimental-sqlite index.ts
Conclusion 🎉
Node.js continues to evolve, incorporating features that enhance the developer experience. From built-in TypeScript support to native testing and database integration, these updates make Node.js a modern, powerful tool for web development. Start using these features today to take your projects to the next level!