很多情况下我们可能有多个nuxtjs项目,多个项目之前有或多或少的关联,每个项目第一次启动项目都要安装一遍依赖,非常占用磁盘空间,那么可以不可以在一个文件夹下管理多个项目呢,这就是
monorepo
的概念。
很多流行的库都使用了monorepo
的方式管理,比如vue
, react
。
monorepo
的管理方式可以使用lerna
和 yarn workspace
, 这里说说yarn workspace
管理多个nuxtjs项目,当然也可以管理其他的vue项目。
原理
nodejs项目引入外部依赖包,首先从本级目录查找,查找不到就到上级目录查找,直到系统根目录。
monorepo
其实就是把各个项目里面的包,安装到根目录下,就是利用这个原理。但是如果包版本冲突呢?
举个例子:
A 依赖了 C@^2.0.0
B 依赖了 C@^2.9.0
系统会判定这两个没有冲突,因为根据语义化结果只需要安装C@2.9.0以上的版本就行。
但是如果:
A 依赖了 C@^1.0.0
B 依赖了 C@^2.9.0
那么A只能安装C@1.x.x 的最高版本,那么B只能安装C@2.9.x 的最高版本。
这就形成了冲突,yarn workspace
就会把低版本的包放到对应的子目录的node_modules
里,高版本的放在根目的node_modules
录,这样各自都能找到自己需要依赖的包了。
如何配置
如果我们的项目根目录是这样的
+-- common #基础包
+-- project1 #项目1
+-- project2 #项目2
+-- package.json
yarn worskspace
要求根目录的package.json
,必须含有, 如何两个字段:
{
"private": true,
"workspaces": ["common", "project1", "project2"] // 也可以使用通配符设置为 ["project*"]
}
执行安装依赖(无论在根目录或者子目录执行)
yarn
安装之后我们可以看到都安装到了根目录的node_modules
里面了。
那如果我们要执行子目录的命令怎么办?
两个办法:
- 直接在子目录命令行里敲命令, 比如
yarn build
- 直接在父目录命令行执行 比如
yarn workspace project1 build
一般来讲我们可以把子目录的各种命令放到根目录
#根目录下的 `package.json`, 加入脚本
"scripts": {
"project1-build": "yarn workspace project1 build",
"project1-dev": "yarn workspace project1 dev",
"project2-build": "yarn workspace project2 build",
"project2-dev": "yarn workspace project2 dev"
}
引入本地包
yarn workspace
的包是可以相互引入的,引入方式也很简单,在需要引入的子项目的package.json
里面引入本地包即可,版本号对应即可。
比如project1
引入common
, 将它的依赖加入dependencies
字段即可:
"dependencies": {
"common": "^1.0.0"
}
在project1
的项目代码里即可引入了
import * as common from 'common';
console.log(common):
*common项目要符合npm包的规范才可以正常使用。
需要注意的问题
1.node_modules 里的包移动后带来的问题。
很多原本安装在子项目node_modules
的包被安装到了父目录了,而有些安装包并没有对monorepo
进行适配, 所以编译会报错。
举几个例子:
-
postcss
编译报错
在linux服务器编译postcss,说配置未找到。
在根目录创建一份配置即可
- 某些包编译配置依赖要改变。
比如webpack-cdn-plugin
插件
plugins:[new WebpackCdnPlugin({
modules: buildConfig.cdnConfig, // CDN配置
pathToNodeModules: path.resolve(__dirname, './../') // 指定查找的node_modules的目录,指向上级目录
})];
- 多个项目的冲突。
你如你在project1
里面引入了element-ui
。 nuxtjs项目的types
文件夹扩展vue
定义
// node_modules\@nuxt\types\app 第119行
export interface NuxtApp extends Vue {
/***给vue拓展了 $loading***/
$loading: NuxtLoading
}
而element-ui
也定义了
// node_modules\element-ui\types\loading.d.ts 59行
declare module 'vue/types/vue' {
interface Vue {
$loading (options: LoadingServiceOptions): ElLoadingComponent
}
}
如果是TypeScript项目,这个俩定义重复了就报错误,当然这并不影响运行结果。