为何Webpack会尝试打包我的specs测试文件?
项目里有src和specs两个主目录,Webpack配置的入口和上下文都明确指向src目录下的文件。package.json里配置了postinstall钩子,执行npm install时会自动把应用打包到dist目录,但此时devDependencies不会被安装,直接导致打包失败。排查后发现Webpack居然在尝试处理specs目录下的文件,因为缺少依赖才报错——明明配置里没涉及specs,为什么会这样?
以下是完整的Webpack配置:
const path = require("path"); const nodeExternals = require("webpack-node-externals"); const NODE_ENV = "development"; const client = { entry: path.join(__dirname, "src", "browser_sdk", "index.ts"), context: path.resolve(__dirname, "src", "browser_sdk"), target: "web", mode: NODE_ENV, devtool: "source-map", watch: false, output: { path: path.resolve(__dirname, "dist"), filename: "client.js", library: { type: "umd", }, }, module: { rules: [ { test: /\.ts$/, use: "ts-loader", exclude: /node_modules.*\.js$/, }, ], }, resolve: { extensions: [".tsx", ".ts", ".js"], }, externals: { "pg-native": "require('pg-native')" }, optimization: { minimize: false, }, }; const server = { entry: path.join(__dirname, "src", "server", "index.ts"), context: path.resolve(__dirname, "src", "server"), mode: NODE_ENV, target: "node", externals: [nodeExternals(), 'pg-native'], watch: false, devtool: "source-map", output: { path: path.resolve(__dirname, "dist"), filename: "server.js", library: { type: "umd", }, }, resolve: { extensions: [".ts", ".js"], }, module: { rules: [ { test: /\.ts$/, use: "ts-loader", exclude: /node_modules.*\.js$/, }, ], }, }; module.exports = [server, client];
核心原因
TypeScript配置的“越界”
你的tsconfig.json大概率没明确限制处理范围——如果include字段包含了specs(比如写了["**/*"]或者["src/**/*", "specs/**/*"]),或者没把specs加入exclude,ts-loader会严格按照TS的配置去加载所有匹配的.ts文件,完全不受Webpack入口和上下文的限制。Webpack规则的排除遗漏
当前Webpack的exclude规则只写了/node_modules.*\.js$/,这只会排除node_modules下的.js文件,对specs目录下的.ts文件完全没限制。只要TS配置扫描到specs,ts-loader就会去处理这些文件。意外的间接引用
检查src下的业务代码,有没有不小心引入specs里的测试文件——比如某个工具函数被测试文件引用后,又反向被业务代码导入了,或者路径别名配置错误导致解析到specs目录。
解决办法
锁死TS的处理范围
打开tsconfig.json,把include设为["src/**/*"],同时添加exclude字段:{ "include": ["src/**/*"], "exclude": ["node_modules", "specs", "dist"] }在Webpack中直接排除specs
修改两个配置里的module.rules,把specs加入排除列表:{ test: /\.ts$/, use: "ts-loader", exclude: [/node_modules/, /specs/] }双重保险,不管TS配置如何,Webpack都会跳过
specs下的文件。调整postinstall的依赖逻辑
postinstall执行时默认不会安装devDependencies,如果你的打包依赖(比如webpack、ts-loader)都在devDependencies里,要么把这些包移到dependencies,要么换用prepare钩子(它会在npm publish前执行,且会安装devDependencies),具体看你的需求场景。排查代码中的误引用
全局搜索项目里的import/require语句,确认没有业务代码引用specs目录下的文件,避免间接触发文件加载。
内容的提问来源于stack exchange,提问作者Oliver Wolf

