monorepo概念
monorepo 是一种将多个项目代码存储在一个仓库里的软件开发策略(mono 意为单一,repo 意为 仓库)。与之相对的是另一种流行的代码管理方式 MultiRepo,即每个项目对应一个单独的仓库来分散管理。
monorepo在H5中的应用
业务场景:我们的业务需求要开发许多轻量的H5项目(页面不会很多),各个H5页面又互相独立,需要单独部署发包,但是各个H5之间又有许多相同的功能,比如拉起登录、与App的交互、上报埋点等
考虑到实际开发情况,不可能为每一个H5页面单独开一个工程,所以采用monorepo的思想来进行开发迭代。与常规的monorepo项目不一样的是,不同的H5页面无需单独维护自己的版本和依赖包,因此无需使用lerna插件。
以自己开发的Vue3项目为例,目录结构如下:
├── config // vite相关配置
├── src
| ├── common // 通用方法
| ├── packages // 包文件
| | ├── demo1
| | | ├── index.html
| | | ├── main.ts
| | | ├── config.json
| | | ├── App.vue
| | ├── demo2
| | | ├── index.html
| | | ├── main.ts
| | | ├── App.vue
├── package.json
├── vite.config.ts
入口文件
本地调试
开发过程中,通过访问 host:port/src/package/demo1
或host:port/src/package/demo2
即可进行本地多入口调试,也可通过配置
{
root:src/packages,
base:h5
}
即可通过host:port/h5/demo1
或host:port/h5/demo2
直接调试
具体配置可参考:vite配置
打包构建
构建时需要指定多个.html
文件作为入口
// 官网示例
module.exports = defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
nested: resolve(__dirname, 'nested/index.html')
}
}
}
})
Vite多页面应用模式
也可以在input中传入数组
// 本文示例
module.exports = defineConfig({
build: {
rollupOptions: {
input: [
resolve(__dirname, 'src/packages/demo1/index.html'),
resolve(__dirname, 'src/packages/demo2/index.html')
]
}
}
})
这样可以通过build命令对demo1和demo2进行打包。
因为packages目录下随着版本迭代会追加更多的H5项目,为了避免添加新项目而反复维护input数组,可以利用node的fs模块自动对packages目录进行解析。
具体代码如下:
// entry.ts
import path from 'path'
import fs from 'fs'
interface IEntry {
template: string
option: any
}
const getEntries = (): Array<IEntry> => {
let entries: Array<IEntry> = []
const pathName = path.join(__dirname, '/../src/packages')
const files = fs.readdirSync(pathName)
files.forEach(file => {
const stat = fs.lstatSync(`${pathName}/${file}`)
if (stat.isDirectory()) {
entries.push({ template: `${file}/index.html` })
}
})
// [{template: 'demo1/index.html'},{template: 'demo2/index.html}]
return entries
}
export { entries }
这样input可以改为
input: entries.map(entry => path.join(__dirname, `${entry.template}`))
即可自动解析入口文件。
下一章谈一谈vuex在项目中的使用