如何配置Webpack适配含仅TS文件的自定义NPM包的Angular项目
嘿,这个问题我之前帮不少开发者解决过——当你只发布TS文件的自定义NPM包到Angular项目(尤其是Angular 5这种稍旧的版本)时,ng serve会默认去找编译好的JS文件,自然会报错。下面给你一步步来解决:
1. 先调整项目的tsconfig.json
首先得告诉TypeScript编译器:你的自定义包不是已编译好的JS模块,需要把它纳入项目的编译流程里。修改项目根目录的tsconfig.json:
- 在
include数组里添加你的包的TS文件路径,比如你的包叫@my-team/utils,就加"node_modules/@my-team/utils/**/*.ts" - 确认
compilerOptions里的allowJs设为false(默认就是false,但保险起见检查下) - Angular 5的话,
compilerOptions里的moduleResolution要设为node,target设为es5或es6,和你项目的现有配置匹配
给你个示例片段:
{ "compilerOptions": { "target": "es5", "moduleResolution": "node", "strict": true, // 其他原有配置... }, "include": [ "src/**/*.ts", "node_modules/@my-team/utils/**/*.ts" ] }
2. 调整Webpack配置(Angular 5专属操作)
Angular 5用的是Angular CLI 1.x,默认不会暴露Webpack配置,所以你需要先执行ng eject导出配置文件(注意:eject之后就没法用部分ng CLI命令了,要是不想这么做,后面我给你另一个办法)。导出后修改webpack.config.js:
- 找到
module.rules里匹配.ts文件的规则(通常是test: /\.ts$/那一项) - 在这个规则的
include数组里,添加你的自定义包的绝对路径,比如path.resolve(__dirname, 'node_modules/@my-team/utils') - 检查
exclude数组,如果原来写的是/node_modules/,得改成排除除了你的包之外的node_modules内容,不然会把你的包也排除掉:
exclude: [ /node_modules(?!\/@my-team\/utils)/, /\.(spec|e2e)\.ts$/ ]
这样Webpack就会把你的自定义包的TS文件当成项目源码的一部分来编译,而不是去搜不存在的JS文件。
3. 不想用ng eject?试试自定义构建器
如果你不想eject,Angular 5可以用@angular-builders/custom-webpack的早期版本来扩展Webpack配置,步骤大概是:
- 安装对应版本的构建器(比如
npm install @angular-builders/custom-webpack@6 --save-dev,要匹配Angular 5的版本) - 修改
.angular-cli.json,把defaults.build.builder改成@angular-builders/custom-webpack:browser,同时添加customWebpackConfig字段指向你的自定义Webpack配置文件 - 在自定义Webpack配置文件里,重复上面第2步的TS规则调整即可
4. 自定义包本身的小优化
为了让你的包更好地被Angular识别,建议在包的根目录加个tsconfig.json,配置如下:
{ "compilerOptions": { "declaration": true, "target": "es5", "module": "es2015", "moduleResolution": "node", "strict": true, "skipLibCheck": true }, "include": ["src/**/*.ts"] }
同时在包的package.json里,把main设为你的入口TS文件(比如"main": "src/index.ts"),再加个types字段指向你的声明文件(如果开了declaration,编译后会生成.d.ts,要是只发TS,也可以设为"types": "src/index.ts")。另外,发布时记得用.npmignore排除掉编译出来的JS文件,避免混淆。
这样配置完之后,再跑ng serve,Angular的编译器就会正确处理你的自定义TS包了。
内容的提问来源于stack exchange,提问作者shikhar

