package.json 中模块入口字段详解

package.json 中模块入口字段详解

在 Node.js 和前端生态系统中,package.json 中的入口字段决定了模块如何被不同环境加载。这些字段的合理配置对模块的兼容性和性能至关重要。

一、核心字段对比

字段 适用场景 加载器 典型用途
main 通用 CommonJS/Node 传统Node.js模块入口
module 现代打包工具 ES Module 提供ESM版本以支持Tree Shaking
browser 浏览器环境 打包工具 提供浏览器专用版本或替换Node模块
exports Node 12+ 条件加载 现代多环境入口配置

二、字段详解与配置示例

2.1 main 字段

作用:定义CommonJS模块的主入口文件,是Node.js和传统打包工具的默认入口。

json 复制代码
{
  "main": "dist/index.cjs.js"
}

特点

  • Node.js 原生支持
  • Webpack/Rollup 默认回退字段
  • 必须使用CommonJS模块语法

加载逻辑

graph TD A[require('pkg')] --> B{是否有main字段?} B -->|是| C[加载main指定文件] B -->|否| D[尝试加载index.js]

2.2 module 字段

作用:指定ES Module格式的入口文件,供支持ESM的打包工具使用。

json 复制代码
{
  "module": "dist/index.esm.js"
}

优势

  • 支持Tree Shaking
  • 静态分析优化
  • 现代打包工具优先使用

打包工具处理顺序

  1. 检查module字段
  2. 不存在则回退到main
  3. 最后尝试index.js

2.3 browser 字段

作用:定义浏览器专用入口或替换特定模块。

json 复制代码
{
  "browser": {
    "./lib/node.js": "./lib/browser.js",
    "fs": false
  }
}

使用场景

  1. 替换Node.js特有API的浏览器实现
  2. 禁用某些不能在浏览器使用的模块
  3. 提供轻量级浏览器版本

示例工作流程

graph LR A[浏览器构建] --> B[检测browser字段] B -->|路径映射| C[替换为浏览器版本] B -->|false| D[移除该模块]

2.4 exports 字段 (Node 12+)

作用:提供更精细的入口控制,支持条件导出。

json 复制代码
{
  "exports": {
    ".": {
      "import": "./dist/index.esm.js",
      "require": "./dist/index.cjs.js",
      "default": "./dist/index.umd.js"
    },
    "./features": {
      "import": "./features/index.mjs",
      "require": "./features/index.cjs"
    },
    "./package.json": "./package.json"
  }
}

高级特性

  • 条件导出(根据环境自动选择)
  • 子路径导出(限制可访问路径)
  • 默认回退(default)
  • 封装性(未列出的路径不可访问)

条件导出支持的环境

  • import - ESM加载
  • require - CJS加载
  • browser - 浏览器环境
  • node - Node.js环境
  • default - 通用回退

三、字段优先级与解析规则

3.1 现代打包工具解析顺序

graph TD A[import/require模块] --> B{是否有exports字段?} B -->|是| C[按条件选择对应入口] B -->|否| D{是否有module字段?} D -->|是| E[使用ESM版本] D -->|否| F[使用main字段] F -->|无main| G[查找index.js]

3.2 Node.js 不同版本行为

Node版本 默认行为
< 12 仅识别main
12-13 实验性支持exports
≥ 14 完整支持exports

四、最佳实践配置

4.1 通用库配置示例

json 复制代码
{
  "name": "my-library",
  "main": "dist/index.cjs.js",
  "module": "dist/index.esm.js",
  "browser": "dist/index.umd.js",
  "exports": {
    ".": {
      "import": "./dist/index.esm.js",
      "require": "./dist/index.cjs.js",
      "browser": "./dist/index.umd.js"
    },
    "./lite": {
      "import": "./dist/lite.esm.js",
      "require": "./dist/lite.cjs.js"
    }
  },
  "types": "dist/index.d.ts"
}

4.2 多环境适配策略

  1. ESM 和 CJS 双输出

    bash 复制代码
    src/
    ├── index.ts       # 源代码
    dist/
    ├── index.cjs.js   # CommonJS 版本
    ├── index.esm.js   # ES Module 版本
    └── index.umd.js   # 通用浏览器版本
  2. 构建脚本示例

    json 复制代码
    {
      "scripts": {
        "build:cjs": "tsc --module commonjs --outDir dist/cjs",
        "build:esm": "tsc --module esnext --outDir dist/esm",
        "build:umd": "rollup -c rollup.config.js",
        "build": "npm run build:cjs && npm run build:esm && npm run build:umd"
      }
    }

五、常见问题解决方案

5.1 向后兼容问题

问题 :老版本Node.js无法识别exports

解决方案

json 复制代码
{
  "main": "dist/legacy.js",
  "exports": {
    ".": {
      "node": {
        "require": "./dist/modern.cjs.js",
        "import": "./dist/modern.mjs"
      },
      "default": "./dist/modern.umd.js"
    }
  }
}

5.2 子路径访问控制

限制 :使用exports后所有子路径必须显式声明

json 复制代码
{
  "exports": {
    ".": "./index.js",
    "./features": "./features/index.js",
    "./package.json": "./package.json"
  }
}

此时require('pkg/utils')将报错,除非在exports中声明

5.3 类型定义配合

推荐配置

json 复制代码
{
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "import": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.mjs"
      },
      "require": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.cjs"
      }
    }
  }
}

六、进阶用法

6.1 条件导出扩展

json 复制代码
{
  "exports": {
    ".": {
      "development": "./dev/index.js",
      "production": "./prod/index.js",
      "test": "./test/index.js",
      "default": "./dist/index.js"
    }
  }
}

6.2 嵌套条件逻辑

json 复制代码
{
  "exports": {
    ".": {
      "node": {
        "import": "./node.mjs",
        "require": "./node.cjs"
      },
      "browser": {
        "import": "./browser.mjs",
        "require": "./browser.cjs"
      },
      "default": "./index.js"
    }
  }
}

七、工具支持情况

7.1 打包工具支持度

工具 exports module browser
Webpack 5 ✔️ ✔️ ✔️
Rollup ✔️ ✔️ ✔️
Parcel 2 ✔️ ✔️ ✔️
esbuild ✔️ ✔️ ✔️
Vite ✔️ ✔️ ✔️

7.2 Node.js版本支持

特性 引入版本
基础exports 12.0.0
条件导出 12.16.0
模式匹配 14.13.0
导入属性 18.0.0

八、迁移指南

8.1 从传统配置升级

旧版

json 复制代码
{
  "main": "index.js",
  "browser": "browser.js"
}

现代化改造

json 复制代码
{
  "main": "./index.cjs",
  "module": "./index.mjs",
  "exports": {
    ".": {
      "require": "./index.cjs",
      "import": "./index.mjs",
      "browser": "./browser.js"
    }
  }
}

8.2 逐步迁移策略

  1. 先保持main字段确保兼容性
  2. 添加module字段支持现代打包工具
  3. 逐步引入exports条件导出
  4. 最后考虑移除旧字段(需测试)

总结

  1. 演进趋势 :从mainexports是模块定义的发展方向
  2. 兼容策略:新老字段组合使用确保平滑过渡
  3. 最大优势exports提供了最精细的控制能力
  4. 发布检查 :使用pkg-exports工具验证配置正确性

正确配置这些字段可以:

  • 显著提升Tree Shaking效率
  • 优化浏览器和Node.js的不同构建
  • 提供更好的类型提示
  • 增强模块封装性和安全性

对于新项目,推荐优先使用exports字段;对于已有项目,可以逐步迁移到现代配置方案。

相关推荐
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax