Yarn2(Berry) workspaces执行yarn start提示找不到react-scripts命令
我在使用基于Yarn2(Berry)搭建的monorepo单仓多包项目,项目包含common和app两个工作区。已在根目录package.json的devDependencies字段中声明typescript和react-scripts作为开发依赖,同时在app工作区的package.json中将typescript和react-scripts声明为peerDependencies。
执行yarn start命令时出现报错:
command not found: react-scripts
补充说明
react-scripts的peerDependencies中包含react,已在根工作区的dependencies配置段中声明了对应的react依赖。- 根目录
package.json配置如下:
{ "name": "monorepo", "packageManager": "yarn@3.2.1", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "^13.3.0", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^16.11.43", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.6", "fictoan-react": "^0.41.22", "react": "^18.2.0", "react-dom": "^18.2.0", "styled-components": "^5.3.5", "web-vitals": "^2.1.4" }, "devDependencies": { "react-scripts": "5.0.1", "typescript": "^4.7.4" }, "workspaces": [ "common", "app" ] }
- app工作区
package.json配置如下:
{ "name": "app", "version": "0.1.0", "private": true, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "dependencies": { "common": "workspace:*" }, "peerDependencies": { "@testing-library/jest-dom": "*", "@testing-library/react": "*", "@testing-library/user-event": "*", "@types/jest": "*", "@types/node": "*", "@types/react": "*", "@types/react-dom": "*", "fictoan-react": "*", "react": "*", "react-dom": "*", "react-scripts": "*", "styled-components": "*", "web-vitals": "*" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
Yarn 2+(Berry)的脚本执行环境规则和Yarn 1有区别:运行某工作区的package.json脚本时,只有声明在该工作区自身dependencies或devDependencies中的依赖,其对应的可执行文件才会被加入临时PATH。
当前配置里,react-scripts只装在根目录的devDependencies,在app工作区仅声明为peerDependencies。peer依赖的作用是声明包对宿主环境的版本要求,不会被Yarn当作当前工作区的直接依赖处理,自然不会把它的bin命令加入app脚本的执行路径,所以会报command not found。
方案1(最稳妥,推荐)
直接在app工作区的devDependencies中声明实际用到的react-scripts和typescript。monorepo中每个应用自己管理构建依赖是常规做法,不会出现依赖隐式引用的问题,也不用修改Yarn全局配置。
修改app目录下的package.json,添加如下字段:
"devDependencies": { "react-scripts": "5.0.1", "typescript": "^4.7.4" }
修改完成后回到根目录执行yarn install重新安装依赖,再执行yarn start即可正常运行。
方案2(统一管理根目录依赖时使用)
如果希望把公共构建依赖统一放在根目录管理,可以调整Yarn的依赖提升规则,让子工作区能访问到根目录安装的依赖可执行文件。
在根目录新建或修改.yarnrc.yml文件,添加如下配置:
# 开启node_modules链接模式(react-scripts对PNP模式兼容性一般,建议开启) nodeLinker: node-modules # 配置需要提升的依赖,让子工作区可以访问到其bin命令 hoistPattern: - "react-scripts" - "typescript" - "react-scripts/**"
保存后执行yarn install重新生成依赖链接即可。注意这种方式需要保证所有工作区用到的上述依赖版本一致,否则容易出现依赖冲突。
如果修改后还是有问题,可以按以下步骤排查:
- 执行
yarn bin react-scripts,看是否能返回正确的可执行文件路径,如果返回找不到说明依赖确实没有被正确链接 - 执行
yarn why react-scripts,查看依赖的安装位置、被哪些工作区引用,确认是否被正确安装 - 如果之前切换过Yarn版本或者清理过依赖,先删除根目录和app目录下的
node_modules、.yarn/cache(存在缓存问题时),重新执行yarn install
内容的提问来源于stack exchange,提问作者D.B.K

