package.json exports 字段:入口与封装

本节目标

exports 是现代包的「入口守卫」:它定义「别人 import 'mypkg' 或 import 'mypkg/sub' 时,实际解析到哪个文件」,还能按环境(import/require)分发。

// 运行环境:Node.js 16+ 项目;放进你的包的 package.json
{
  "name": "mypkg",
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/mypkg.mjs",   // ESM 用户 import 走这
      "require": "./dist/mypkg.cjs"   // CJS 用户 require 走这
    },
    "./sub": "./dist/sub.mjs"          // 允许 import 'mypkg/sub'
    // 没列在 exports 里的路径,外部 import 会被拒绝(封装性)
  }
}

名词解释

exports 字段:package.json 里控制「导入映射」的字段。它比老式 main 更强:能按 import/require 分发不同文件、能限制外部只能访问白名单路径(未列出的不可 import,实现封装)、能指定类型文件。它是「现代包正确发双构建(CJS+ESM)」的关键。

课后练习

练习 1:有 exports 后,为什么 import 'mypkg/internal' 可能报错?

答案:exports 是「白名单」——只有列在里面的子路径才允许被外部 import。若没写 "./internal" 映射,mypkg/internal 会被拒绝(即使磁盘上有这文件)。这强制了「封装:内部实现不对外暴露」。

总结

exports 字段是「包的门面设计」,我的观点:发任何库都该写它,而不是只写老式 main。它带来的「按环境分发 CJS/ESM」加「路径白名单封装」,是专业包和玩具包的分水岭。