Docker构建时ESBuild无法解析Monorepo工作空间包的问题
问题
我尝试用Docker镜像编译并运行Monorepo里的应用,用ESBuild把所有依赖打包成单个文件。手动执行打包命令一切正常,但在Docker环境里运行失败,报错无法解析应用依赖的其他工作空间包,错误示例如下:
#10 1.443 ✘ [ERROR] Could not resolve "@platform/bar" #10 1.443 #10 1.443 src/app/logger.ts:1:29: #10 1.443 1 │ import { createBar } from '@platform/bar' #10 1.443 ╵ ~~~~~~~~~~~~~~~ #10 1.443 #10 1.443 You can mark the path "@platform/bar" as external to exclude it from the bundle, which will remove this error.
相关配置文件
Dockerfile
FROM node:18 ENV NODE_ENV=production COPY . /app WORKDIR /app RUN yarn install RUN yarn workspace @platform/foo bundle WORKDIR /platform/packages/apps/foo/dist EXPOSE 8181 CMD ["node", "app.js"]
package.json(@platform/foo)
{ "name": "@platform/foo", "scripts": { "bundle": "node bundle.mjs" }, "dependencies": { "@platform/bar": "workspace:*", "@platform/xyz": "workspace:*" } }
bundle.mjs
import * as esbuild from 'esbuild' import { copy } from 'esbuild-plugin-copy' await esbuild.build({ entryPoints: ['src/main.ts'], bundle: true, outfile: 'dist/app.js', plugins: [ copy({ resolveFrom: 'cwd', verbose: true, assets: [ { from: ['../../../node_modules/couchbase/build/**/*.node'], to: ['./dist'], }, ], }), ], platform: 'node', target: 'node18', loader: { '.node': 'copy', }, })
解决方案
问题根源
- Docker里提前设置了
NODE_ENV=production,Yarn在生产模式下会跳过工作空间内部依赖的本地关联,试图从npm仓库拉取@platform/bar这类不存在的包,导致ESBuild找不到依赖。 - ESBuild默认不识别Monorepo的工作空间路径映射,需要手动配置才能解析内部包别名。
- Dockerfile最后设置的工作目录路径错误,实际代码在
/app下,却指向了/platform。
修复步骤
1. 调整Docker的依赖安装逻辑
取消提前设置生产环境变量,先完整安装所有依赖(包括工作空间包),再打包,最后设置生产环境:
FROM node:18 COPY . /app WORKDIR /app # 先安装所有依赖(含工作空间包) RUN yarn install --production=false # 执行打包 RUN yarn workspace @platform/foo bundle # 打包完成后再设置生产环境 ENV NODE_ENV=production # 修正工作目录路径 WORKDIR /app/packages/apps/foo/dist EXPOSE 8181 CMD ["node", "app.js"]
或者保留NODE_ENV=production,安装时强制包含工作空间:
RUN yarn install --production --workspaces
2. 给ESBuild添加内部包路径映射
在bundle.mjs中配置alias,让ESBuild能找到工作空间内的包(路径根据你的Monorepo目录结构调整):
await esbuild.build({ entryPoints: ['src/main.ts'], bundle: true, outfile: 'dist/app.js', plugins: [/* 原有copy插件 */], platform: 'node', target: 'node18', loader: { '.node': 'copy' }, // 添加路径解析配置 resolve: { extensions: ['.ts', '.js', '.mjs'], alias: { '@platform/bar': '../../bar/src', '@platform/xyz': '../../xyz/src' } } })
如果你的Monorepo根目录有tsconfig.json并配置了paths,也可以用@esbuild-plugins/tsconfig-paths插件自动读取路径映射,不用手动写alias。
3. 修正Docker工作目录路径
原Dockerfile中WORKDIR /platform/packages/apps/foo/dist路径错误,改为/app/packages/apps/foo/dist,确保启动时能找到打包后的app.js。
内容的提问来源于stack exchange,提问作者nickfla1
相关产品推荐
相关产品推荐

