
本文详解 Rollup 构建的 React 组件库(如 @b/b-core)在消费端报 Module not found: Can't resolve '@b/b-core' 的根本原因——package.json 中 main/module/types 字段路径未相对于包根目录,导致 Node.js 模块解析器无法定位文件。
本文详解 rollup 构建的 react 组件库(如 `@b/b-core`)在消费端报 `module not found: can't resolve '@b/b-core'` 的根本原因——`package.json` 中 `main`/`module`/`types` 字段路径未相对于包根目录,导致 node.js 模块解析器无法定位文件。
当你使用 Rollup 构建并发布一个 TypeScript 编写的 React 组件库(例如 @b/b-core)后,在下游 React 应用中执行 npm install @b/b-core 并尝试 import { X } from '@b/b-core' 时,却遇到如下构建错误:
Module not found: Error: Can't resolve '@b/b-core'
而 VS Code 中类型提示正常、TS 编译无误——这说明问题不在类型系统或源码逻辑,而在运行时/打包时的模块解析路径。
根本原因:package.json 中的入口字段路径不正确
Node.js(及 Webpack/Vite/Rollup 等打包工具)在解析第三方包时,会严格依据 package.json 中的 main(CommonJS 入口)、module(ESM 入口)、types(类型声明入口)字段,从包安装后的根目录(即 node_modules/@b/b-core/)出发,拼接相对路径来查找文件。
你当前的 package.json 配置为:
"main": "dist/cjs/index.js", "module": "dist/esm/index.js", "types": "dist/index.d.ts"
⚠️ 这是致命错误:dist/ 是构建产物目录,它仅存在于你的源码仓库中;但当你执行 npm publish 时,npm 默认只发布 package.json 所在目录下的文件(除非显式配置 .npmignore 或 files 字段)。若未将 dist/ 目录纳入发布范围,或虽发布了但路径书写错误,消费者安装后 node_modules/@b/b-core/dist/cjs/index.js 实际并不存在,自然触发 Can't resolve。
更关键的是:即使 dist/ 被成功发布,"main": "dist/cjs/index.js" 在语义上也要求该路径必须相对于 node_modules/@b/b-core/ 目录存在。而正确的做法是确保构建产物被复制到包根下(如 cjs/, esm/, index.d.ts),再让入口字段指向这些包内顶层路径。
正确配置:三步修复
✅ 第一步:调整 rollup.config.js 输出路径(移除 dist/ 前缀)
确保 Rollup 将构建产物直接输出到包根目录(而非嵌套在 dist/ 下),例如:
// rollup.config.js
export default [
{
input: "src/index.ts",
output: [
{
file: "cjs/index.js", // ← 不再是 "dist/cjs/index.js"
format: "cjs",
sourcemap: true,
},
{
file: "esm/index.js", // ← 不再是 "dist/esm/index.js"
format: "esm",
sourcemap: true,
},
],
plugins: [
peerDepsExternal(),
resolve(),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" }),
copy({
targets: [
{ src: "package.json", dest: "." }, // 将 package.json 复制到包根(确保发布时存在)
],
}),
],
external: ["react", "react-dom"],
},
{
input: "src/index.ts",
output: [{ file: "index.d.ts", format: "es" }], // ← 不再是 "dist/index.d.ts"
plugins: [dts()],
},
];? 提示:rollup-plugin-copy 此处用于确保 package.json 位于最终发布的包根目录(虽然通常默认存在,但显式声明更稳妥)。
✅ 第二步:同步更新 package.json 入口字段
构建产物路径变更后,package.json 必须严格匹配:
{
"main": "cjs/index.js",
"module": "esm/index.js",
"types": "index.d.ts",
// ...其余字段保持不变
}✅ 此时,当用户安装 @b/b-core 后,node_modules/@b/b-core/cjs/index.js 即为有效 CJS 入口,Webpack/Vite 可正确解析。
✅ 第三步:确认发布内容(推荐显式声明 files)
在 package.json 中添加 files 字段,明确指定哪些文件应被发布(避免意外遗漏或包含开发文件):
"files": [ "cjs", "esm", "index.d.ts", "package.json", "README.md" ]
执行 npm publish 前,可先运行 npm pack 生成 tarball 并解压验证目录结构是否符合预期。
验证与调试技巧
- 检查已安装包结构:进入 node_modules/@b/b-core/,手动确认 cjs/index.js、esm/index.js、index.d.ts 是否真实存在;
- 使用 npm ls @b/b-core 查看解析路径;
-
在消费项目中临时修改 resolve.alias(仅调试):
// webpack.config.js(如使用自定义配置) resolve: { alias: { '@b/b-core': path.resolve(__dirname, '../path/to/your/lib/cjs') } }若此方式能跑通,则 100% 确认是发布路径问题。
总结
| 错误写法 | 正确写法 | 原因 |
|---|---|---|
| "main": "dist/cjs/index.js" | "main": "cjs/index.js" | dist/ 是构建中间目录,非包内路径 |
| 依赖 dist/ 存在且可读 | 显式 files + Rollup 输出至包根 | npm 发布机制只认 package.json 所在目录及其子目录 |
Rollup 本身不决定模块如何被消费,真正起决定作用的是 package.json 的标准化字段 + npm 的发布约定。牢记:所有入口路径必须是相对于包安装根目录(node_modules/










