Yarn Workspace依赖提升本地正常,部署环境失效排查
问题:Yarn Workspace依赖提升在Vercel部署时失效,导致运行时「模块未找到」
我使用Next.js服务端渲染,本地运行Yarn Workspace时,根目录package.json中定义的lodash-es包可被子目录正常引用。但通过Cloud Build部署到Vercel后,运行时出现「模块未找到」错误——子目录package.json中未声明该包,推测是Workspace依赖提升未生效。
项目结构
. └── tiles/ ├── packages/ │ ├── hosted/ │ │ ├── next.config.js │ │ ├── tailwind.config.js │ │ ├── package.json │ │ ├── tsconfig.json │ │ ├── node_modules (auto-generated) │ │ ├── .next (auto-generated) │ │ └── .vercel (auto-generated) │ ├── modules/ │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── node_modules (auto-generated) │ └── react/ │ ├── tsconfig.json │ ├── package.json │ └── node_modules (auto-generated) ├── .yarnrc.yml ├── package.json └── yarn.lock
子包依赖配置
hosted/package.json中的Workspace依赖:
{ "dependencies": { "@project/modules": "workspace:*", "@project/react": "workspace:*" } }
本地运行命令
从tiles根目录执行:
cd packages/react && yarn && tsc && cd packages/modules && yarn && yarn build && concurrently --kill-others "cd packages/react && yarn tsc --watch" "cd packages/modules && yarn tsc --watch" "cd packages/hosted && NODE_OPTIONS='--inspect' next dev -p 3001"
Cloud Build部署配置(原配置)
steps: - name: "us-central1-docker.pkg.dev/<project-name>/docker-repository/builders/node-with-utils" id: "build-react" dir: "javascript/tiles/packages/react" entrypoint: "bash" args: - "-c" - |- yarn gcp-auth refresh \ && yarn install \ && git diff --exit-code \ && yarn run build - name: "us-central1-docker.pkg.dev/<project-name>/docker-repository/builders/node-with-utils" id: "build-modules" dir: "javascript/tiles/packages/modules" entrypoint: "bash" args: - "-c" - |- yarn gcp-auth refresh \ && yarn install \ && git diff --exit-code \ && yarn run build - name: "us-central1-docker.pkg.dev/<project-name>/docker-repository/builders/node-with-utils" id: "build-and-deploy" dir: "javascript/tiles/packages/hosted" entrypoint: "bash" env: - "COMMIT_SHA=$COMMIT_SHA" args: - "-c" - |- yarn gcp-auth refresh \ && yarn install \ && git diff --exit-code \ && yarn vercel --token "$$VERCEL_ACCESS_TOKEN" --scope <vercel_project> pull --yes \ && yarn vercel --token "$$VERCEL_ACCESS_TOKEN" --scope <vercel_project> build --prod \ && find .vercel/output/static/_next/static -type f -name "*.map" -delete \ && yarn vercel --token "$$VERCEL_ACCESS_TOKEN" --scope <vercel_project> --yes deploy --prebuilt --prod
根目录.yarnrc.yml配置
nodeLinker: node-modules nmHoistingLimits: workspaces npmScopes: fermat: npmAlwaysAuth: true npmPublishRegistry: "https://us-central1-npm.pkg.dev/<project-name>/npm-repository/" npmRegistryServer: "https://us-central1-npm.pkg.dev/<project-name>/npm-repository/" unsafeHttpWhitelist: - metadata.google.internal plugins: - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs spec: "@yarnpkg/plugin-interactive-tools" - path: .yarn/plugins/@yarnpkg/plugin-gcp-auth.cjs spec: "https://github.com/AndyClausen/yarn-plugin-gcp-auth/releases/latest/download/plugin-gcp-auth.js" yarnPath: .yarn/releases/yarn-3.3.0.cjs
Vercel端已启用「在构建步骤中包含根目录外的文件」选项。
问题根源
Cloud Build的每个步骤都进入子目录单独执行yarn install,而非从Workspace根目录操作。Yarn的依赖提升是基于根目录统一管理的node_modules,子目录单独执行install只会安装该子包的直接依赖和Workspace依赖,无法继承根目录声明的公共依赖(如lodash-es)。
解决方案
调整Cloud Build配置,统一从Workspace根目录执行yarn install,再分别运行子包的构建命令:
修正后的Cloud Build配置
steps: - name: "us-central1-docker.pkg.dev/<project-name>/docker-repository/builders/node-with-utils" id: "root-install" dir: "javascript/tiles" entrypoint: "bash" args: - "-c" - |- yarn gcp-auth refresh \ && yarn install \ && git diff --exit-code - name: "us-central1-docker.pkg.dev/<project-name>/docker-repository/builders/node-with-utils" id: "build-react" dir: "javascript/tiles" entrypoint: "bash" args: - "-c" - |- yarn workspace @project/react build - name: "us-central1-docker.pkg.dev/<project-name>/docker-repository/builders/node-with-utils" id: "build-modules" dir: "javascript/tiles" entrypoint: "bash" args: - "-c" - |- yarn workspace @project/modules build - name: "us-central1-docker.pkg.dev/<project-name>/docker-repository/builders/node-with-utils" id: "build-and-deploy" dir: "javascript/tiles/packages/hosted" entrypoint: "bash" env: - "COMMIT_SHA=$COMMIT_SHA" args: - "-c" - |- yarn vercel --token "$$VERCEL_ACCESS_TOKEN" --scope <vercel_project> pull --yes \ && yarn vercel --token "$$VERCEL_ACCESS_TOKEN" --scope <vercel_project> build --prod \ && find .vercel/output/static/_next/static -type f -name "*.map" -delete \ && yarn vercel --token "$$VERCEL_ACCESS_TOKEN" --scope <vercel_project> --yes deploy --prebuilt --prod
额外注意事项
- 确保根目录
package.json中的lodash-es放在dependencies下,而非devDependencies——Next.js SSR需要运行时依赖可被访问。 - 确认Vercel的「包含根目录外文件」选项保持启用,保证Workspace相关配置能被正确读取。
内容的提问来源于stack exchange,提问作者10may




