自研React组件库使用报错:无法解析文件路径
React组件库作为依赖引入的问题排查与解决
背景
自研React组件库(下称LIB),配置了"type": "module",仅通过tsc命令编译生成dist目录,希望在其他项目中作为依赖引入使用。
LIB文件结构
. └── LIB/ └── src/ └── container/ ├── index.ts ├── container.tsx ├── container-footer.tsx └── ...
container/index.ts 代码
export * from './container'; export * from './container-footer'; export ...
疑问:ContainerFooter组件仅在Container内部导入使用,不会对外单独调用,是否不该在index.ts中导出?
container/container.tsx 代码
import { ContainerFooter } from './container-footer'; const Container = props => ( <div> {/* Some stuff here */} {props.showFooter && <ContainerFooter />} </div> )
遇到的问题
问题1:无法顶层导入组件
尝试通过import { Container } from '@company_name/LIB'导入时,报错:
ERROR in ./src/App.tsx export ‘Container’ (imported as ‘Container’) was not found in ‘@company_name/LIB’ (module has no exports)
问题2:从dist目录导入时模块解析失败
尝试import { Container } from '@company_name/LIB/dist/container/container'(或@company_name/LIB/dist/container)时,报错:
ERROR in ./node_modules/@company_name/LIB/dist/container/container.js 6:0-47 Module not found: Error: Can't resolve './container-footer' in '/Users/username/git/NEW_PROJECT/node_modules/@company_name/LIB/dist/container' Did you mean 'container-footer.js'? BREAKING CHANGE: The request './container-footer' failed to resolve only because it was resolved as fully specified (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains "type": "module"). The extension in the request is mandatory for it to be fully specified. Add the extension to the request.
LIB相关配置
package.json(非依赖部分)
{ "files": [ "dist" ], "main": "dist/index.js", "type": "module", "types": "dist/index.d.ts", "scripts": { "build": "tsc", ... } ... }
tsconfig.json
{ "compilerOptions": { "allowJs": true, "allowSyntheticDefaultImports": true, "baseUrl": "src", "declaration": true, "emitDecoratorMetadata": true, "esModuleInterop": true, "experimentalDecorators": true, "isolatedModules": true, "jsx": "react-jsx", "lib": [ "dom", "dom.iterable", "esnext" ], "module": "esnext", "moduleResolution": "node", "outDir": "dist", "resolveJsonModule": true, "rootDirs": [ "src" ], "skipLibCheck": true, "sourceMap": true, "strict": true, "strictNullChecks": false, "target": "esnext" }, "include": [ "src/**/*" ] }
解决方案
解决问题2:模块解析缺少扩展名
- 原因:LIB配置了
"type": "module",属于严格ES模块,Node.js的ES模块规范要求导入路径必须带完整文件扩展名。但当前tsconfig.json中moduleResolution设为node,TypeScript不会自动给编译后的JS文件添加扩展名,导致导入路径找不到对应文件。 - 修复方法:
- 将
tsconfig.json中compilerOptions.moduleResolution改为nodenext(TypeScript 4.7+支持)或bundler(TypeScript 5.0+支持),这样编译时会自动为导入添加正确的扩展名。 - 确保TypeScript版本至少为4.7,以支持
nodenext模块解析策略。
- 将
解决问题1:顶层导入失败
- 原因:package.json中
main指向dist/index.js,但当前LIB的src目录没有顶层的index.ts文件,导致编译后dist目录下没有顶层index.js,自然没有对外导出的内容。 - 修复方法:在LIB的
src目录下创建顶层index.ts,导出需要对外暴露的组件:
这样// src/index.ts export * from './container';tsc编译后会生成dist/index.js,其他项目就能通过import { Container } from '@company_name/LIB'正常导入。
关于内部组件导出的疑问
ContainerFooter仅作为Container的内部组件使用,确实不需要在container/index.ts中导出。对外暴露的index文件只需要导出外部项目需要使用的组件(比如Container),这样可以保持组件库的API简洁,避免暴露内部实现细节。
内容的提问来源于stack exchange,提问作者physicsboy
相关产品推荐
相关产品推荐

