在使用Rollup构建包含内部组件依赖的react组件库时,开发者常遇到类型声明文件(.d.ts)中因未正确处理css等非JavaScript/typescript资产而导致的“未解析依赖”警告。本文将深入探讨此问题,并提供通过配置Rollup的dts插件来外部化CSS依赖的解决方案,确保组件库的平滑构建和类型声明的准确生成。
问题描述
在构建一个包含多个内部组件(如Button组件内部使用Text组件)的组件库时,如果采用Rollup作为打包工具,并同时生成JavaScript/ESM模块和TypeScript类型声明文件(.d.ts),可能会遇到一个常见的构建问题。具体表现为,当Button组件通过相对路径或tsconfig.json中配置的路径别名(如/atoms/Text/Text.tsx)导入Text组件时,Rollup在生成类型声明文件时会报告“未解析依赖”警告,例如:
(!) Unresolved dependencies https://rollupJS.org/troubleshooting/#warning-treating-module-as-external-dependency atmos/base-text/Text.tsx (imported by "dist/esm/types/molecules/Button.d.ts")
尽管在开发环境中,TypeScript编译器能够正确解析这些内部组件的导入,但在Rollup的构建流程中,特别是在处理类型声明文件时,由于对非JavaScript/TypeScript资产(如CSS文件)的处理不当,导致了这一问题。
项目结构与配置概览
为了更好地理解问题,我们先来看一个典型的组件库项目结构和相关配置:
文件夹结构:
├── src │ ├── components | │ ├── Text | | │ ├── Text.tsx | | │ ├── styles.css // 组件的样式文件 | | │ └── index.ts | │ └── index.ts │ └── index.ts │ ├── molecules | │ ├── Button | | │ ├── Button.tsx // 内部使用了 <Text /> | | │ ├── styles.css | | │ └── index.ts | │ └── index.ts │ └── index.ts ├── styles │ └── general.ts │ └── index.ts ├── package.json └── package-lock.json
tsconfig.json 配置:
{ "compilerOptions":{ "target":"es2016", "jsx":"react", "module":"ESNext", "moduleResolution":"node", "declaration":true, "emitDeclarationOnly":true, "sourceMap":true, "outDir":"dist", "declarationDir":"types", "allowSyntheticDefaultImports":true, "esModuleInterop":true, "forceConsistentCasingInFileNames":true, "strict":true, "skipDefaultLibCheck":true, "skipLibCheck":true, "allowImportingTsExtensions": true, "baseUrl":"src", // 设置基准路径 "rootDir": "src", "paths":{ // 配置路径别名 "atoms/*":[ "components/Text/*" // 示例中应为 components/Text/* ], "molecules/*":[ "molecules/*" ], "styles/*":[ "styles/*" ] } } }
rollup.config.mjs 配置:
import resolve, {nodeResolve} from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import typescript from "@rollup/plugin-typescript"; import {terser} from 'rollup-plugin-terser'; import external from 'rollup-plugin-peer-deps-external' import postcss from 'rollup-plugin-postcss' import dts from "rollup-plugin-dts"; // 用于生成类型声明文件 export default [ { input: "src/index.ts", output: [ { file: packageJson.main, format: "cjs", sourcemap: true, name: 'ui-components' }, { file: packageJson.module, format: "esm", sourcemap: true, }, ], plugins: [ resolve(), commonjs(), external(), postcss(), // 处理CSS文件 terser(), nodeResolve(), typescript({tsconfig: "./tsconfig.json"}), ], }, { // 第二个配置项用于生成类型声明文件 input: "dist/esm/types/index.d.ts", output: [{ file: "dist/index.d.ts", format: "esm" }], external: [/.css$/], // 关键的解决方案 plugins: [dts.default()], // 或者 dts(),取决于插件版本 }, ];
问题分析:为什么Rollup的DTS插件会报错?
Rollup配置中通常包含两个主要打包任务:
- JavaScript/ESM 模块打包:这个任务负责将TypeScript代码编译为JavaScript,并处理CSS等资产。@rollup/plugin-postcss插件在此阶段发挥作用,它会提取或内联CSS,确保最终的JS包能够正确加载样式。
- 类型声明文件(.d.ts)打包:这个任务由rollup-plugin-dts负责,它的目的是将由TypeScript编译器生成的多个.d.ts文件合并成一个或少数几个统一的声明文件,供消费者使用。
问题的核心在于,rollup-plugin-dts在处理类型声明文件时,默认情况下并不知晓如何处理像.css这样的非TypeScript文件导入。尽管在主JS/ESM打包过程中postcss插件已经处理了CSS,但dts插件关注的是类型定义。当Button.d.ts(或其他任何生成的.d.ts文件)内部或其依赖链中包含对.css文件的引用时,dts插件会尝试解析这些引用。由于CSS文件不包含任何类型信息,dts插件无法将其解析为有效的TypeScript模块,从而触发“未解析依赖”的警告。
这个警告提示Rollup将Text.tsx(或其相关的CSS)视为外部依赖,这意味着它不会被打包到最终的index.d.ts文件中,这可能导致使用该组件库的项目在类型检查时出现问题。
解决方案:外部化CSS依赖
解决此问题的关键是在Rollup配置中,针对类型声明文件(.d.ts)的打包任务,明确告诉Rollup将所有.css文件视为外部依赖。这意味着dts插件在生成类型声明文件时,会忽略对CSS文件的解析和捆绑。对于类型声明文件而言,这是正确的行为,因为类型声明文件不应包含CSS的实现细节。
具体修改:
在rollup.config.mjs中,找到负责生成类型声明文件的第二个配置对象,并添加external: [/.css$/]。
// ... 其他导入 export default [ // ... 第一个配置项:JavaScript/ESM 模块打包 { // 第二个配置项:类型声明文件打包 input: "dist/esm/types/index.d.ts", output: [{ file: "dist/index.d.ts", format: "esm" }], plugins: [dts.default()], // 确保这里是 dts() 或 dts.default() external: [/.css$/], // <-- 添加这一行 }, ];
解释:
- external: [/.css$/]:这个配置项告诉Rollup,当它在处理此bundle(即类型声明文件bundle)时,任何匹配正则表达式/.css$/的导入都应被视为外部模块。这意味着Rollup不会尝试解析、捆绑或警告这些.css文件的导入。对于类型声明文件来说,CSS是实现细节,不应包含在类型定义中,因此将其外部化是完全合理的。
通过这一改动,rollup-plugin-dts将不再尝试解析和捆绑.css文件,从而消除了“未解析依赖”的警告,并确保类型声明文件能够正确生成。
注意事项
- 区分打包目标:理解Rollup配置中针对不同输出(如JavaScript模块和类型声明文件)的独立配置至关重要。每个配置对象都有其特定的目的和插件集。
- rollup-plugin-dts 的作用:该插件专注于合并和优化.d.ts文件。它不处理运行时逻辑或样式,因此需要明确告知它如何处理非类型文件。
- 路径别名与Rollup解析:tsconfig.json中的paths配置主要影响TypeScript编译器的模块解析。虽然@rollup/plugin-node-resolve和@rollup/plugin-typescript会尝试利用这些信息,但Rollup自身的解析机制仍需注意,尤其是在处理不同类型的bundle时。
- CSS处理插件:@rollup/plugin-postcss在主JS/ESM打包流程中是必要的,它负责处理和提取CSS。但其作用范围不包括dts插件的类型声明文件生成过程。
总结
当使用Rollup构建组件库并遇到类型声明文件因CSS导入而导致的“未解析依赖”警告时,核心解决方案是在Rollup配置中针对rollup-plugin-dts的打包任务,通过external: [/.css$/]明确将CSS文件标记为外部依赖。这一配置确保了类型声明文件能够专注于类型定义,避免了不必要的解析错误,从而使组件库的构建过程更加健壮和高效。
评论(已关闭)
评论已关闭