前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库package.json exports 条件导出解析
JavaScript模块与语言机制

package.json 的 exports 字段怎么控制包的入口?条件导出按什么顺序匹配?

exports 是包的「对外出口清单」:导入 pkg 或 pkg/xxx 时,Node.js 只按这张清单找文件,没列出的路径直接报 ERR_PACKAGE_PATH_NOT_EXPORTED。条件导出让同一个路径按 import、require 等条件指向不同文件,按书写顺序取第一个命中的。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#模块与语言机制
先看核心答案读代码示例
理解线索

`exports` 的三种写法

  1. 子路径"." 是包本身,"./utils" 对应 pkg/utils
  2. 通配子路径"./utils/*" 批量映射一整个目录
  3. 条件导出同一路径下按 import、require、node、default 选文件

条件的匹配顺序看的是你在对象里写的顺序,不是 Node.js 规定的某个优先级。把 default 写在 require 前面,require 条件永远不会被用到。

核心回答

先记住这个答案

exports 字段声明了一个包对外暴露的所有入口。有了它,别人导入 pkg 或 pkg/子路径 时,Node.js 只查这张表,没写进去的路径一律报 ERR_PACKAGE_PATH_NOT_EXPORTED,包的内部文件就被封装起来了。每个入口还可以写成条件对象,比如 import 条件给 ESM 文件、require 条件给 CommonJS 文件。Node.js 按对象里的书写顺序逐个检查条件,用第一个命中的,所以顺序很重要。

  • 定义了 exports 后,没列出的子路径都不能导入
  • 条件按对象里的书写顺序匹配,第一个命中就用
  • default 放最后兜底,types 放最前面
  • exports 存在时优先于 main

一个同时发布 ESM 和 CommonJS 的包

这是库作者最常写的配置,同时暴露了主入口、一个工具目录和 package.json 本身。

子路径加条件导出JSON
{
  "name": "pkg",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs",
      "default": "./dist/index.mjs"
    },
    "./utils/*": "./dist/utils/*.mjs",
    "./package.json": "./package.json"
  }
}

有了这份配置,import a from "pkg" 拿到 index.mjs,require("pkg") 拿到 index.cjs。import f from "pkg/utils/format" 会通过通配规则映射到 dist/utils/format.mjs。而 import x from "pkg/dist/internal.mjs" 会报 ERR_PACKAGE_PATH_NOT_EXPORTED,哪怕这个文件实际存在。 "./package.json" 那一行不是多余的。有些工具需要读取包的 package.json,没导出它就会读取失败。

条件为什么要讲顺序

Node.js 拿到条件对象后,从上往下看每个键,当前环境满足哪个条件就用哪个,找到第一个就停。它不会把所有条件放在一起比较优先级。

把 default 写错位置
我实测过一份配置,把 "default" 写在 "require" 前面,结果 require("pkg") 拿到的是 default 指向的 ESM 文件,require 条件形同虚设。default 在任何环境下都匹配,所以它只能放在最后兜底。 同样的道理,TypeScript 解析类型时要求 types 放在第一位,放在后面可能先被 import 条件截走,找不到类型声明。 常见的条件有这几个:import 和 require 看导入方式,node 表示 Node.js 环境,default 兜底。browser、development、production 这些是社区约定,打包器会识别,Node.js 里可以用 --conditions=development 这类参数启用自定义条件。
回答前,多想一步

容易答错的地方

加上 exports 以为只是多了一个选择
加上 exports 是一个破坏性改动。以前用户可以随便导入 pkg/lib/xxx.js,加上以后这些路径全部失效。所以很多库是在大版本升级时才加这个字段。
以为有了 exports 还会看 main
在支持 exports 的 Node.js 里,两者同时存在时只用 exports。保留 main 只是为了照顾不认识 exports 的老工具。
双格式包的状态被复制两份
同一个包的 import 和 require 入口是两个不同的文件,也就是两个模块实例。如果应用里一部分代码 import 它,另一部分 require 它,包里的单例、缓存就会有两份。这叫双包风险,常见的规避办法是让 ESM 入口只做一层包装,实际状态都放在 CommonJS 那份里。
试着用自己的话回答

面试官还会怎么问?

包内部怎么用简短路径引用自己的文件?

用 imports 字段,键必须以 # 开头,比如 "#utils/*": "./src/utils/*.js",包内代码写 import x from "#utils/format.js"。它只对包自己可见,外部导入不到。

打包器也认 exports 吗?

Webpack 5、Vite、Rollup 的 Node 解析插件都支持,而且会额外匹配 browser、module 等条件。条件的书写顺序在打包器里同样生效。

包能不能导入自己的公开路径?

可以,这叫自引用。包里写 import x from "pkg/utils/format",只要包定义了 exports,Node.js 就会按包自己的 exports 解析,和外部用户看到的结果一致。

从一道题,走向一组知识

把知识连起来

模块与语言机制

用 type="module" 加 nomodule 给老浏览器降级,要注意哪些坑?

条件导出在 Node.js 里给不同环境不同入口,nomodule 在浏览器里给新旧浏览器不同脚本,思路相通。

模块与语言机制

export ... from 再导出有哪几种写法?默认导出能被 export * 带出去吗?

包的入口文件通常是用 export ... from 汇总各模块的桶文件,exports 决定别人能从哪里进来。

参考资料

  • JavaScript:模块与语言机制参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 一个同时发布 ESM 和 CommonJS 的包
  3. 条件为什么要讲顺序
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑