Master Dynamic Entry Points in Node Packages: main, type, exports & module

This article explains how third‑party library authors can configure package.json fields such as main, type, exports, and module to provide dynamic entry points for both CommonJS and ESModule consumers, while also covering TypeScript's resolution strategy and practical code examples.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
Master Dynamic Entry Points in Node Packages: main, type, exports & module

Introduction

Third‑party library authors need to write appropriate entry files to achieve "dynamic" imports, which also helps bundlers eliminate unused code and reduce bundle size.

main

The main field in package.json is the most common way to specify the entry file.

{
  "name": "@homy/test-entry",
  "version": "1.0.0",
  "description": "",
  "main": "index.js"
}

When a developer imports @homy/test-entry, the entry file resolved is index.js.

type

The type field indicates whether the package should be treated as commonjs or module. If type: "module" is set, .js files are interpreted as ESModules; otherwise they are treated as CommonJS.

{
  "name": "@homy/test-entry",
  "version": "1.0.0",
  "type": "commonjs", // or "module", default is commonjs
  "main": "index.js"
}
type: module works only on Node.js >= 14 and requires import ; require is not supported.

exports

The exports field is a more powerful replacement for main. It can specify different entry points for import (ESM) and require (CJS), and provides a fallback with default.

{
  "name": "@homy/test-entry",
  "main": "index.js",
  "exports": {
    "import": "./index.mjs",
    "require": "./index.cjs",
    "default": "./index.mjs"
  }
}

If a subpath is accessed that is not defined in exports, Node throws an error:

const pkg = require('@homy/test-entry/test.js'); // Error! Package subpath './test.js' is not defined by "exports"

Submodule configuration can be added by defining additional keys:

{
  "exports": {
    ".": "./index.mjs",
    "./mobile": "./mobile.mjs",
    "./pc": "./pc.mjs"
  }
}

// or more detailed
{
  "exports": {
    ".": {
      "import": "./index.mjs",
      "require": "./index.cjs",
      "default": "./index.mjs"
    },
    "./mobile": {
      "import": "./mobile.mjs",
      "require": "./mobile.cjs",
      "default": "./mobile.mjs"
    }
  }
}

The imports field (similar to import maps) can control resolution of non‑relative imports, but in Node it must be prefixed with #.

module

Many bundlers (webpack, rollup, esbuild) also support the module field to specify an ESModule entry point, which aids tree‑shaking.

{
  "name": "@homy/test-entry",
  "module": "index.mjs"
}

TypeScript entry files

TypeScript first checks the main field, then looks for a corresponding declaration file ( lib/index.d.ts). If a types (or typings) field is present, it is used instead of main for type resolution.

{
  "name": "my-package",
  "type": "module",
  "exports": {
    ".": {
      "types": "./types/index.d.ts",
      "import": "./esm/index.js",
      "require": "./commonjs/index.cjs"
    }
  },
  "main": "./commonjs/index.cjs",
  "types": "./types/index.d.ts"
}

In tsconfig.json, the moduleResolution option can be classic (default) or node, affecting how relative and non‑relative imports are resolved.

Relative imports search the current directory for .ts or .d.ts files, while non‑relative imports walk up the directory tree and finally look into node_modules, also considering @types packages.

// relative import example
import { b } from "./moduleB";
// Node resolves to /root/src/folder/moduleB.ts (or .d.ts)

// non‑relative import example
import { b } from "moduleB";
// Node searches upward and then /node_modules/moduleB for .js/.ts/.d.ts etc.

Summary

Node uses main and type to specify the entry file and its module format; exports provides a more flexible alternative.

Bundlers add support for the module field to enable top‑level ESM entry points.

TypeScript prefers the types field, falling back to main and then searching for matching declaration files.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Node.jspackage.jsonCommonJSESMExportsmodule-resolution
Taobao Frontend Technology
Written by

Taobao Frontend Technology

The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.