avatarJennifer Fu

Summary

npm 8 was released with no new features but dropped support for old node versions and removed support for require('npm'), while predictions for npm 9 include the possibility of raising the supported versions to include ESM-style modules.

Abstract

npm 8 was released on October 7, 2021, with the main purpose of dropping support for old node versions and removing support for require('npm'). This release does not introduce any new features or breaking changes. Looking ahead, it is predicted that npm 9 might raise the supported versions to include ESM-style modules, as suggested in a Request for Comments (RFC) for npm 8. The article also discusses the differences between CommonJS (CJS) and ES Modules (ESM) and provides an example of how to set up an Express server to deploy a production build.

Bullet points

  • npm 8 was released on October 7, 2021, with no new features but dropped support for old node versions and removed support for require('npm').
  • npm 9 might raise the supported versions to include ESM-style modules.
  • The article discusses the differences between CommonJS (CJS) and ES Modules (ESM).
  • The article provides an example of how to set up an Express server to deploy a production build.

A Quick Glance at npm 8 Features and Predictions for npm 9

A close look at ES Modules (ESM)

Photo by True Agency on Unsplash

npm is the package manager for the node.js JavaScript platform. It puts modules in place so that the node can find them, and manages dependency conflicts intelligently.

npm is configurable to support a variety of use cases to publish, discover, install, and develop node programs. It has a list of powerful commands.

npm 8 was released on October 7, 2021. In this article, we take a look at npm 8, and predict what npm 9 might be.

What’s New In npm 8?

There is nothing new in npm 8. The purpose of this release is to drop support for old node versions and to remove support for require('npm'). There are no other breaking changes. More specifically, these are changes:

  • Drop support for node 10 and 11.
  • Raise support ceiling in node 12 and 14 to LTS (^12.13.0/^14.15.0).
  • Drop support to require('npm').
  • Update some dependencies due to the dropped node10 and node 11 support.

It is simple and clear.

If you want to upgrade to npm 8, make sure that your node.js has been upgraded to version >=12.0.0. nvm is a simple way to manage versions for node and npm.

What Might Be New In npm 9?

A Request for Comments (RFC) is a formal document drafted by the Internet Engineering Task Force (IETF) that describes the specifications for a particular technology. npm 8 is a ratified RFC, currently a formal standard.

RRFC of npm 8 mentioned a suggestion to raise the supported versions to ^12.20.0 || ^14.13.1 || >=16.0.0, which would be a move to the node.js versions that support ESM-style modules. Since it did not make npm 8, it might be a feature in npm 9.

CJS vs. ESM

We have discussed JavaScript module formats, such as CJS, AMD, UMD, ESM, System, and IIFE.

CommonJS (CJS) is the standard that is used by node.js to encapsulate JavaScript in modules. CJS uses require() function and module.exports.

  • require() is a function that can be used to import symbols to the current scope from another module. require statements can be used anywhere in the code, and referred modules are loaded and processed synchronously.
  • module.exports is an object that the current module returns when it is required in another module.

ES Modules (ESM) become the official standard used in JavaScript since ES2015. It is widely used in JavaScript client development. It is also adopted by TypeScript that is a superset with additional types. ESM uses import and export statements to handle modules.

  • The static import directive can be used to bring modules into the current scope. The dynamic import() is available since ES2020 .import statements can be used anywhere in the code. Since imports are loaded asynchronously, it is recommended to put them at the top of the files.
  • The export directive, on the other hand, can be used to explicitly make items public.

CJS is the default for node

As we have mentioned, CJS is the default for node. Following the steps that are described in the production-ready React app, we use the Create React App as an example to explore how node server works.

npx create-react-app react-esm
cd react-esm

Execute the command npm run build, and the generated build directory contains the code to be deployed.

Express is a minimal and flexible Node.js web app framework for web and mobile applications. Express server is a popular choice to deploy the production build.

Since Express is part of the Create React App, there is no need to install it again.

Set up a configuration file for the Express server in server/index.js:

The above code is obviously in CJS format with require statements (line 1 and line 4).

Line 2 creates an Express server.

Lines 5–8 serve the production webpages.

Lines 10–12 start the Express server at port, 8080.

Run node server, and the user interface can be accessed at http://localhost:8080.

Set node to run ESM

Now we change the code to use import instead of require().

Run node server, and we see the following error:

The warning at line 10 provides two solutions:

  • Set "type": "module" in the package.json.
  • Change server/index.js to server/index.mjs, and run node server/index.mjs.

Both solutions work. Here is the modified package.json (line 5):

For files without extensions, they are treated as CJS modules if there is no "type", or the type is set to "commonjs" in the parent package.json. They are treated as ES modules, if the "type" is set to "module".

Additionally, files ending with .cjs are treated as CJS modules, and files ending with .mjs are treated as ES modules.

We set "type" to "module", now the node treats files as ES modules. Run node server again:

It does not complain about import any more. But, what is the __dirname issue?

__dirname is a CJS variable, which is not available in ES modules. It can be replicated via import.meta.url.

The import.meta object exposes context-specific metadata to a JavaScript module. It contains information about the module, like the module's URL.

Modify server/index.js as follows:

Run node server, and the ES module works perfectly.

Alternatively, we can have the node: prefix, in which case it bypasses the require cache. For instance, "node:path" (line 4) and "node:url" (line 5) will always return the built in "path" and "url" modules.

We have seen some differences between CJS and ESM. The following is the list on how to convert CJS files to ES modules:

  • No require, exports or module.exports—Use import or export instead.
  • No __filename or __dirname—Use import.meta.url instead.
  • No JSON Module Loading — Use import.meta.url with fs instead.
  • No Native Module Loading — Use module.createRequire() or process.dlopen instead.
  • No require.resolve—Use new URL('./local', import.meta.url) instead.
  • No NODE_PATH — Use symlinks instead.
  • No require.extensions — Do not use.
  • No require.cache — Do not use.

Conclusion

npm 8 dropped support for node 10 and 11.

What do you think about npm 9? Should it drop support for node versions that do not support ES modules?

After struggling with different syntaxes for JavaScript clients and servers, isn’t it exciting to see that ESM gains streams to be used for both clients and servers?

The time has arrived to use ESM-style modules in node applications.

If you want to check out features of other releases, take a look at the following articles:

Here is a list of Node.js:

Thanks for reading.

Want to Connect?

If you are interested, check out my directory of web development articles.
NPM
Nodejs
JavaScript
Web Development
Programming
Recommended from ReadMedium