umi
umi copied to clipboard
[Bug] umi4 monorepo 子包找不到依赖
What happens?
app 为应用,lib 为库,app 引用了 lib,app 打包的时候,报错,找不到 lib 的依赖 axios,而看 lib 下的 node_modules,axios 是存在的

Mini Showcase Repository(REQUIRED)
https://github.com/twinkle77/umi4-monorepo
Please provide a minimal reproduction then upload to your GitHub. 请提供 最小重现,并上传到你的 GitHub 仓库
How To Reproduce
Steps to reproduce the behavior: 1. 2.
Expected behavior 1. 2.
Context
- Umi Version: 4.0.7
- Node Version: 14.x
- Platform: mac
mfsu 的问题,可以通过 mfsu: false
解决。
这个问题我记得很久以前就有了, @stormslowly 有空可以辛苦看下有没有解法。
希望能有 mfsu 的能力 哈哈哈
希望能有 mfsu 的能力 哈哈哈
可以临时通过 externals 来解决 我目前是这样搞的
希望能有 mfsu 的能力 哈哈哈
可以临时通过 externals 来解决 我目前是这样搞的

大佬,给 web 配置 externals: { axios } 么,问题是,除了 axios 还有非常多的其他依赖
配置这个吧 https://umijs.org/docs/api/config#alias 这个以可以解决
配置这个吧 https://umijs.org/docs/api/config#alias 这个以可以解决
大佬,指的是?
alias: { lib: '../packages/lib/src' }
alias: { axios: '../packages/lib/node_modules' }
@xierenyuan
是的 axios 写成 require.resolve(’axios‘) 应该就可以 你试试
是的 axios 写成 require.resolve(’axios‘) 应该就可以 你试试

老哥,为什么 app 的 .umirc.ts 文件 require.resolve('axios'),这个 axios 缺会指向 lib/node_modules 下的 axios ?
如果想批量注册的话,需要在 .umirc.ts 实现一个逻辑,收集所有 lib 类的依赖,生成一个 alias 格式的对象 ?
@xierenyuan 把你非子包的依赖的映射下 就没问题呢
是的 axios 写成 require.resolve(’axios‘) 应该就可以 你试试
确认不报错了
试了下,应该是 mfsu 的问题,lib 中的依赖 axios 在设置后 umi config monorepoRedirect 会提升到 app 库的 buildDep 中(个人猜测)
可以通过在 app 中安装 dep: axios,lib中改成 devDep: axios, peerDep: axios
试了下,应该是 mfsu 的问题,lib 中的依赖 axios 在设置后 umi config monorepoRedirect 会提升到 app 库的 buildDep 中(个人猜测)
可以通过在 app 中安装 dep: axios,lib中改成 devDep: axios, peerDep: axios
安装到 app 不行的, lib 很多,app会非常臃肿
试了下,应该是 mfsu 的问题,lib 中的依赖 axios 在设置后 umi config monorepoRedirect 会提升到 app 库的 buildDep 中(个人猜测) 可以通过在 app 中安装 dep: axios,lib中改成 devDep: axios, peerDep: axios
安装到 app 不行的, lib 很多,app会非常臃肿
那可以考虑放弃 monorepoRedirect ,通过 [email protected] config mfsu:exclude ['@mono/lib'] 来实现,这种需要 father 构建 Bundless 包, src 目录不能经过 umi 的源码编译(否则会进入 mfsu 的逻辑,然后 lib 的相关 dep 如 axios 不在 app 的依赖会报错)
lib/package.json
{
"name": "@mono/lib",
"version": "1.0.0",
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.js",
"files": [
"dist",
"compiled"
],
"scripts": {
"dev": "father dev",
"build": "father build",
"postinstall": "pnpm run build",
"build:deps": "father prebundle",
"prepublishOnly": "father doctor && npm run build"
},
"dependencies": {
"axios": "^0.27.2"
},
"devDependencies": {
"father": "^4.0.0",
"webpack": ">=5.11.0 <6.0.0"
}
}
lib/.fatherrc.ts
import { defineConfig } from 'father';
export default defineConfig({
esm: {
output: 'dist'
},
});
lib/tsconfig.json
{
"compilerOptions": {
"strict": true,
"declaration": true,
"skipLibCheck": true,
"baseUrl": ".",
"jsx": "react-jsx"
}
}
试了下,应该是 mfsu 的问题,lib 中的依赖 axios 在设置后 umi config monorepoRedirect 会提升到 app 库的 buildDep 中(个人猜测) 可以通过在 app 中安装 dep: axios,lib中改成 devDep: axios, peerDep: axios
安装到 app 不行的, lib 很多,app会非常臃肿
那可以考虑放弃 monorepoRedirect ,通过 [email protected] config mfsu:exclude ['@mono/lib'] 来实现,这种需要 father 构建 Bundless 包, src 目录不能经过 umi 的源码编译(否则会进入 mfsu 的逻辑,然后 lib 的相关 dep 如 axios 不在 app 的依赖会报错)
lib/package.json
{ "name": "@mono/lib", "version": "1.0.0", "main": "dist/index.js", "module": "dist/index.js", "types": "dist/index.d.js", "files": [ "dist", "compiled" ], "scripts": { "dev": "father dev", "build": "father build", "postinstall": "pnpm run build", "build:deps": "father prebundle", "prepublishOnly": "father doctor && npm run build" }, "dependencies": { "axios": "^0.27.2" }, "devDependencies": { "father": "^4.0.0", "webpack": ">=5.11.0 <6.0.0" } }
lib/.fatherrc.ts
import { defineConfig } from 'father'; export default defineConfig({ esm: { output: 'dist' }, });
lib/tsconfig.json
{ "compilerOptions": { "strict": true, "declaration": true, "skipLibCheck": true, "baseUrl": ".", "jsx": "react-jsx" } }
我试试 感谢
现状
现在以最新版本 umi ( ^4.0.30
) 验证,已不存在如题所述的问题。
发生的新问题
@stormslowly 有时间可以辛苦看下这个问题 🌹
虽然不会发生如题所述的问题,但是在 改动引用子包内容 的时候,mfsu 会报依赖错误:
error - MFSU[eager] analyze dependencies failed with error Error: ENOENT: no such file or directory, open '.../umi4-monorepo/packages/app/node_modules/.cache/lib/src/index.js'
将子包添加到 mfsu.exclude
也无法解决:
// .umirc.ts
export default {
// 当改动子包内容时,仍然会出现依赖错误
mfsu: {
exclude: ['@mono/lib']
}
}
复现方法
-
拉下本 issue 中的仓库 https://github.com/twinkle77/umi4-monorepo
-
将应用
packages/app/package.json
的 umi 版本改为最新:// packages/app/package.json + "umi": "^4.0.30",
-
启动项目
pnpm i cd ./packages/app && pnpm dev
-
改动子包
packages/lib/src/index.ts
代码,即可复现。
目前还是建议 使用 normal strategy 配合 monorepo 使用
normal
策略的问题在于是会报 axios
找不到(如本 issue 中的问题)😭 :
error - Can not resolve dependence : 'axios', please install it
error - AssertionError [ERR_ASSERTION]: dependence not found: axios
@twinkle77 https://github.com/umijs/umi/releases/tag/v4.0.33 应该解决此问题了
@fz6m "@umijs/max": "4.0.64"
, dev没问题,但build还是提示找不到packages/components
里面的依赖classnames antd
,mfsu配置是 strategy: 'normal'
, 请指点~

-
pnpm i
-
pnpm build:umi4app
packages/components/src/InnerButton/index.jsx
这个文件里用到了 antd
和 classnames
这俩依赖,都没有在 package.json
里声明,这是不规范的。
要把子包当成真正的组件库开发,依赖不能是隐形的,用到的依赖必须要满足如下其一的条件:
-
在
dependencies
里,如果该包被发到 npm 上,安装该包的人也会安装dependencies
里面的依赖,从而确保这个依赖一定存在。 -
在
devDependencies
和peerDependencies
里,在devDependencies
是为了开发时的类型和调试开发,但我们不希望他多个实例,而是复用主项目的,那就必须也声明到peerDependencies
里,说明这个依赖需要引用这个包的项目安装哪些依赖。
按这个场景,我们可以自己决策,antd
很大,不应该多实例,应该是 2
的声明法,classnames
很小,多实例也不会产生预期外的问题(一般工具库多实例是无所谓的,但组件库多实例有风险,比如 context 不一致,消息不成队列等),所以 1
/ 2
都可以。
{
"name": "@ifss/components",
"version": "0.0.0",
"private": true,
"main": "src/index.ts",
"typings": "index.d.ts",
"scripts": {
"format": "prettier --write \"src/**/*.{js,jsx,tsx,ts,less,json}\"",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
"lint:fix": "eslint --fix 'src/**/*.{js,jsx,ts,tsx}'"
},
+ "dependencies": {
+ "classnames": "^2.3.2"
+ },
"devDependencies": {
"eslint": "^8.35.0",
"@ifss/eslint-config-custom": "workspace:*",
"@ifss/tsconfig": "workspace:*",
+ "antd": "4.18.9"
},
+ "peerDependencies": {
+ "antd": "^4"
+ }
}
现在我们已经按照 npm 包开发规范声明完了依赖,下一步需要解决 monorepo peer deps 问题,详见 monorepoRedirect
,这是 monorepo 内部引用与 npm 安装下来不一样的地方,通过添加 monorepoRedirect.peerDeps: true
解决,就可以构建成功了。
注:上面说到的 classnames
之所以选择了 1
,工具库一般会这么依赖,多实例没有风险,这样即使该包被发布到 npm ,安装该包的项目也无需每个都安装一遍 classnames
,特别是这种工具库很多的情况,假定有 10 个,安装这个包的项目都要安装这 10 个 peer deps ,是不合理的。
@fz6m 感谢指点,之前看过你的这篇文章,但隐形依赖在dev可以跑还是挺困惑的,因为dev可以跑就误以为umi做了魔法处理,可以不用声明依赖的
这个是 MFSU 的问题,mfsu: false
行为是正常的。