Skip to content
On this page

搭建 Monorepo 环境

Vue3 中使用 pnpm workspace 来实现 monorepo (pnpm-'https://pnpm.io/') 是快速、节省磁盘空间的包管理器。主要采用符号链接的方式管理模块)

全局安装 pnpm

bash
# 全局安装pnpm
npm install pnpm -g
# 初始化配置文件
pnpm init -y
1
2
3
4

创建.npmrc 文件

  • npm 的特点 bootstarp - animate.css 不用重新安装 animate.css (幽灵依赖)
shamefully-hoist = true
1

这里您可以尝试一下安装 Vue3, pnpm install vue@next 此时默认情况下 vue3中依赖的模块不会被提升到 node_modules 下。 添加羞耻的提升可以将 Vue3,所依赖的模块提升到 node_modules

配置 workspace

新建 pnpm-workspace.yaml

javascript
packages:
  - 'packages/*'
1
2

将 packages 下所有的目录都作为包进行管理。这样我们的 Monorepo 就搭建好了。确实比 lerna + yarn workspace 更快捷

环境搭建

打包项目 Vue3 采用 rollup 进行打包代码,安装打包所需要的依赖

依赖-
typescript在项目中支持 Typescript
rollup打包工具
rollup-plugin-typescript2rollup 和 ts 的 桥梁
@rollup/plugin-json支持引入 json
@rollup/plugin-node-resolve解析 node 第三方模块
@rollup/plugin-commonjs将 CommonJS 转化为 ES6Module
minimist命令行参数解析
execa@4开启子进程

安装 rollup 模块

bash
pnpm install typescript rollup rollup-plugin-typescript2 @rollup/plugin-json @rollup/plugin-node-resolve @rollup/plugin-commonjs minimist execa@4 esbuild   -D -w
1

初始化 TS

bash
pnpm tsc --init
1

先添加些常用的 ts-config 配置,后续需要其他的在继续增加

json
{
  "compilerOptions": {
    "outDir": "dist", // 输出的目录
    "sourceMap": true, // 采用sourcemap
    "target": "es2016", // 目标语法
    "module": "esnext", // 模块格式
    "moduleResolution": "node", // 模块解析方式
    "strict": false, // 严格模式
    "resolveJsonModule": true, // 解析json模块
    "esModuleInterop": true, // 允许通过es6语法引入commonjs模块
    "jsx": "preserve", // jsx 不转义
    "lib": ["esnext", "dom"], // 支持的类库 esnext及dom
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

创建模块

我们现在packages目录下新建两个 package,用于下一章手写响应式原理做准备

  • reactivity 响应式模块
  • shared 共享模块

所有包的入口均为src/index.ts 这样可以实现统一打包

reactivity/package.json

json
{
  "name": "@vue/reactivity",
  "version": "1.0.0",
  "main": "index.js",
  "module":"dist/reactivity.esm-bundler.js",
  "unpkg": "dist/reactivity.global.js",
  "buildOptions": {
    "name": "VueReactivity",
    "formats": [
      "esm-bundler",
      "cjs",
      "global"
    ]
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

shared/package.json

json
{
    "name": "@vue/shared",
    "version": "1.0.0",
    "main": "index.js",
    "module": "dist/shared.esm-bundler.js",
    "buildOptions": {
        "formats": [
            "esm-bundler",
            "cjs"
        ]
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

formats 为自定义的打包格式,有 esm-bundler 在构建工具中使用的格式、esm-browser 在浏览器中使用的格式、cjs 在 node 中使用的格式、global 立即执行函数的格式

bash
pnpm install @vue/shared@workspace --filter @vue/reactivity
1

配置 ts 引用关系

tsconfig.json

javascript
"baseUrl": ".",
"paths": {
    "@vue/*": ["packages/*/src"]
}
1
2
3
4

开发环境 esbuild 打包

解析用户参数

package.json

json
"scripts": {
    "dev": "node scripts/dev.js reactivity -f global"
}
1
2
3

新建目录下 scripts/dev.js

javascript
const { build } = require('esbuild')
const { resolve } = require('path')
const args = require('minimist')(process.argv.slice(2));

const target = args._[0] || 'reactivity';
const format = args.f || 'global';

const pkg = require(resolve(__dirname, `../packages/${target}/package.json`));

const outputFormat = format.startsWith('global')// 输出的格式
    ? 'iife'
    : format === 'cjs'
        ? 'cjs'
        : 'esm'

const outfile = resolve( // 输出的文件
    __dirname,
    `../packages/${target}/dist/${target}.${format}.js`
)

build({
    entryPoints: [resolve(__dirname, `../packages/${target}/src/index.ts`)],
    outfile,
    bundle: true,
    sourcemap: true,
    format: outputFormat,
    globalName: pkg.buildOptions?.name,
    platform: format === 'cjs' ? 'node' : 'browser',
    watch: { // 监控文件变化
        onRebuild(error) {
            if (!error) console.log(`rebuilt~~~~`)
        }
    }
}).then(() => {
    console.log('watching~~~')
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
沪ICP备20006251号-1