preface

Recently, I have participated in business abstraction, planned to create general components and release them into NPM packages for the construction of subsequent projects, and learned some knowledge points about package.json that I did not know before.

Here, we introduce some of the fields used by Node.js in package.json. The following Nodejs versions are v14.14.0.

  • Name – defines the name when imported as a package, and it determines its unique name on the NPM source.
  • Type – specifies that.js files under the package are loaded by Node.js as CommonJS Modules or ECMAScript Modules.
  • Exports-sets the export of package.
  • Main – Specifies the default entry file to load the package.

name

{
  "name": "package-name"
}
Copy the code

The “name” field defines the name of your package. When you publish the package to the NPM source, remember that the name needs to meet the specification.

When the package you downloaded is in node_modules, you can import it using the following methods:

const pkg = require("package-name");
// import pkg from 'package-name';
Copy the code

type

The two most influential module specifications in the JS world are CommonJS Modules and ECMAScript Modules. Fortunately, Nodejs has supported them all since V12. .js. CJS files are executed as CommonJS Modules by default, while.mjs is executed as ECMAScript Modules by default.

The presence of the “type” field, which has two values: “module” and “commonjs”, makes it easier to determine which module specification the.js file will be executed by.

{
  "type": "commonjs"
}
Copy the code

When you set it to “commonjs”,.js. CJS files that have package.json as the nearest parent config file will default to CommonJS Modules. If you want to implement ECMAScript Modules, You have to change the suffix to.mjs

{
  "type": "module"
}
Copy the code

Similarly, when you set it to “module”,.js. MJS files that have this package.json as their closest parent are executed by default as ECMAScript Modules. If you want to implement CommonJS Modules, You have to change the suffix to.cjs

exports

Referencing a package using its name, the “exports” field allows you to define the import files of the package by self-referencing a package using its name. For example:

// package.json
{
  "name": "pkg"."exports": {
    ".": "./main.mjs"."./foo": "./foo.js"}}Copy the code

The above can be read as:

  "exports": {
    "pkg": "pkg/main.mjs"."pkg/foo": "pkg/foo.js"
  }
Copy the code
import { something } from "pkg"; // from "pkg/main.mjs"
Copy the code
const { something } = require("pkg/foo"); // require("pkg/foo.js")
Copy the code

It has been supported since Node.js V12 as an alternative to the “main” field (see the next section for details).

One of its biggest features is Conditional Exports. When the package is imported, it can determine the module environment in which it is imported and execute different files. In short, if we use the import command, The entry loads ECMAScript Modules, or CommonJS Modules if require is used.

Let’s find out. The directory structure is as follows:

├ ─ ─ mod │ ├ ─ ─ mod. Js │ ├ ─ ─ mod. The CJS │ ├ ─ ─ package. The json │ ─ ─ app. Js └ ─ ─ app. MJSCopy the code

As a native package, the mod’s package.json is defined as follows:

{
  "name": "mod"."main": "index.js"."type": "module"."exports": {
    "require": "./mod.cjs"."import": "./mod.js"}}Copy the code

And it provides two scripts that do the same thing for different module environments:

// mod.cjs
exports.name = "cjs";
Copy the code
// mod.js
export const name = "mjs";
Copy the code

The file that calls this module is as follows:

// app.js
const { name } = require("mod");

console.log(name);
Copy the code
// app.mjs
import { name } from "mod";

console.log(name);
Copy the code

All this is not enough because the mod is now a local package, which is neither downloaded from NPM nor in the node_modules directory and cannot be imported as package name.

There is always a way to associate a local package without formally publishing to an NPM source by using package Link.

Run yarn Link in the./mod directory.

success Registered "mod".
info You can now run `yarn link "mod"` in the projects where you want to use this package and it will be used instead.
Copy the code

In the root directory of the project, run yarn Link “mod” :

success Using linked package for "mod".
Copy the code

Finally, verify that our “exports” field works:

$ node app.js
$ cjs
$ node app.mjs
$ mjs
Copy the code

The results confirm that different script files are executed in different module environments.

Note that all paths defined in “exports” must be absolute paths. Which is of the form./.

main

{
  "main": "./main.js"
}
Copy the code

The “main” field defines the entry file to use when importing the package directory, as an example:

const pkg = require("package-name");
Copy the code

Due to node_modules’ lookup mechanism, this is resolved to the following path:

const pkg = require("./node_modules/package-name");
Copy the code

There is only one directory imported here, it is not a concrete module, but with the help of main, the entry file, the file path is eventually resolved as:

const pkg = require("./node_modules/package-name/main.js");
Copy the code

Note that when a package has both “exports” and “main” fields, exports takes precedence when imported as package name.

Reference for this article: Modules: Packages