Vue3 源码学习笔记(一):环境搭建与初识Monorepo

前言 为啥想学习源码?

在这个AI触手可及的时代,解决问题变得前所未有的简单------提问、复制、粘贴、完成。作为CRUD开发者,我们熟练地搬运代码,却很少追问它们为何这样工作。久而久之,技术变成了黑盒,好奇心也在重复业务中逐渐褪去。

一次偶然的机会,接触到远方 os的源码课程,开始学习Vue3的源码实现。希望把这段时间的疑问和收获整理成笔记,作为自己这段学习旅程的一份纪念。

环境搭建

Vue3 源码本身就是采用 Monorepo 架构管理,所有核心模块(如 reactivity、runtime-core、compiler-core 等)都放在 packages 目录下。

核心配置

  • Monorepo:单仓库管理多个子包,能更方便地管理模块间的依赖、统一版本
  • pnpm workspace :pnpm 内置的 Monorepo 工具,特点是子包本地软链、命令轻量高效

初始化项目

  1. 本地创建一个Vue3文件夹,执行pnpm init
  2. 新建pnpm workspace.yaml
yaml 复制代码
packages:
  - "packages/*" 
  1. 创建packages目录统一管理子项
  2. 执行pnpm install typescript -D -w, 安装到根目录
  3. 初始化ts配置,执行npx tsc --init
json 复制代码
// 配置
{
  "compilerOptions": {
    // 编译目标:使用最新的 ECMAScript 版本
    // 生成的 JavaScript 代码会包含最新的 ES 特性
    "target": "ESNext",

    // 模块系统:使用 ES 模块格式(import/export)
    // 适用于现代浏览器和打包工具
    "module": "ESNext",

    // 模块解析策略:使用 Node.js 风格的模块解析
    // 会在 node_modules 中查找依赖
    "moduleResolution": "node",

    // 输出目录:编译后的 JavaScript 文件将放在 dist 文件夹中
    "outDir": "dist",

    // 允许导入 JSON 文件作为模块
    "resolveJsonModule": true,

    // 严格模式:设置为 false,关闭所有严格类型检查
    // 提供更宽松的类型检查,适合快速开发
    "strict": false,

    // 包含的库文件:ESNext(最新 ES 特性)和 DOM(浏览器 API)
    "lib": ["ESNext", "DOM"]
  }
}
  1. 根目录下新建一个 scripts/dev.js
js 复制代码
/**
 * 打包开发环境
 *
 * node script/dev.js --format or cjs
 */
import { parseArgs } from 'node:util'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import  esbuild from 'esbuild'
import { createRequire } from 'node:module'

/**
 * 解析命令行参数
 */
const { values: { format }, positionals } = parseArgs({
    allowPositionals: true,
    options: {
        format: {
            type: 'string',
            short: 'f',
            default: 'esm',
        },
    },
})

//  创建 esm 的 __filename
const __filename = fileURLToPath(import.meta.url)
//  创建 esm 的 __dirname
const  __dirname = dirname(__filename)

const  require  = createRequire(import.meta.url)

const  target = positionals.length ? positionals[0] : 'vue'

// 构建入口文件路径:../packages/包名/src/index.ts
const  entry = resolve(__dirname, `../packages/${target}/src/index.ts`)

/**
 * --format cjs or esm
 * 构建输出文件路径:../packages/包名/dist/包名.格式index.js
 * 例如:packages/vue/dist/vue.cjsindex.js 或 packages/vue/dist/vue.esmindex.js
 */
const  outfile = resolve(
    __dirname,
    `../packages/${target}/dist/${target}.${format}index.js`
)
// 读取目标包的package.json文件
const pkg = require(`../packages/${target}/package.json`)

// 使用esbuild创建构建上下文并启动监听模式
esbuild.context({
    entryPoints: [entry],  // 指定入口文件
    outfile,               // 指定输出文件
    format,                // 打包格式:'cjs' 或 'esm'
    platform: format === 'cjs' ? 'node' : 'browser', // 根据格式选择平台:cjs用node,esm用browser
    sourcemap: true,       // 生成sourcemap文件,便于调试
    bundle: true,          // 将依赖打包到一个文件中
    globalName: pkg.buildOptions?.name // 从package.json中读取全局变量名(用于UMD格式)
}).then(ctx => ctx.watch())  // 启动监听模式,文件变化时自动重新构建
  1. packages目录新建reactivity、shared、vue文件夹
    • reactivity:响应式模块
    • shared:工具函数模块
    • vue:vue核心包
json 复制代码
// package.json
{
  "name": "@vue/reactivity",
  "version": "1.0.0",
  "description": "响应式模块",
  "main": "iist/reactivity.cjs.js",
  "module": "dist/reactivity.esm.js",
  "files": [
    "index.js",
    "dist"
  ],
  "sideEffects": false,
  "buildOptions": {
    "name": "VueReactivity",
    "formats": [
      "esm-bundler",
      "esm-browser",
      "cjs",
      "global"
    ]
  }
}
json 复制代码
// package.json
{
  "name": "@vue/shared",
  "version": "1.0.0",
  "description": "工具函数",
  "main": "dist/shared.cjs.js",
  "module": "dist/shared.esm.js",
  "files": [
    "index.js",
    "dist"
  ],
  "sideEffects": false,
  "buildOptions": {
    "name": "VueShared",
    "formats": [
      "esm-bundler",
      "esm-browser",
      "cjs",
      "global"
    ]
  }
}
json 复制代码
{
  "name": "vue",
  "version": "1.0.0",
  "description": "vue核心包",
  "main": "dist/vue.cjs.js",
  "module": "dist/vue.esm.js",
  "files": [
    "dist"
  ],
  "sideEffects": false,
  "buildOptions": {
    "name": "Vue",
    "formats": [
      "esm-bundler",
      "esm-browser",
      "cjs",
      "global"
    ]
  }
}
  1. 根目录package.json添加node scripts/dev.js reactivity --format cjs
json 复制代码
{
  "name": "vue3源码",
  "version": "1.0.0",
  "description": "",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "dev": "node scripts/dev.js reactivity --format cjs"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^24.3.0",
    "esbuild": "^0.25.9",
    "prettier": "^3.6.2",
    "typescript": "^5.9.2"
  },
  "dependencies": {
    "vue": "^3.5.21"
  }
}

验证输出

  • 新建reactivity/src/index.ts
js 复制代码
// 测试函数
export function fn(a,b) {
  return a + b
}
  • 执行pnpm dev,在reactivity/dist目录输出如下

到这一步,项目搭建完成!

  • 项目结构
md 复制代码
Vue3/
├── node_modules/              # Node.js 依赖模块
├── packages/                  # 多包工作区
│   ├── reactivity/           # 响应式系统包
│   │   ├── dist/            # 构建输出目录
│   │   ├── src/             # 源代码目录
│   │   │   └── index.ts     # 响应式系统入口文件
│   │   └── package.json     # reactivity 包配置
│   ├── shared/              # 共享工具包
│   │   ├── src/             # 共享代码源代码
│   │   └── package.json     # shared 包配置
│   └── vue/                 # Vue 主包
│       ├── src/             # Vue 源代码
│       └── package.json     # vue 包配置
├── scripts/                  # 构建脚本目录
│   ├── dev.js               # 开发构建脚本
│   └── .prettierrc          # Prettier 代码格式化配置
├── package.json             # 项目根配置
├── pnpm-lock.yaml           # pnpm 依赖锁文件
├── pnpm-workspace.yaml      # pnpm 工作区配置
├── tsconfig.json            # TypeScript 配置
├── External Libraries/      # 外部库(IDE 生成)
└── Scratches and Consoles/ # 临时文件和终端(IDE 功能)

相关链接

(注:本文为学习笔记,如有理解不当之处,欢迎指正交流。)

相关推荐
羊羊小栈1 小时前
基于「YOLO姿态识别 + AI大模型分析」的智能健身辅助系统(vue+flask+AI算法)
vue.js·人工智能·yolo·毕业设计·创业创新·大作业
一只一只妖1 小时前
Taro+Vue3+TS+Vite 小程序开发底座搭建流程
vue.js·小程序·taro
随笔记1 小时前
uniapp开发app使用海康威视播放监控视频流如何使用以及遇到了什么问题
vue.js·uni-app·视频编码
羽沢311 小时前
vue3 + element-plus 表单校验
前端·javascript·vue.js
Dgua2 小时前
一文吃透Vue Diff原理:从核心逻辑到实战避坑
前端·vue.js
小飞侠在吗2 小时前
vue Hooks
前端·javascript·vue.js
小茴香3532 小时前
vue3的传参方式总结
javascript·vue.js·typescript
梵得儿SHI2 小时前
Vue 核心语法深度解析:生命周期与响应式之计算属性(computed)与侦听器(watch/watchEffect)
前端·javascript·vue.js·计算属性·侦听器·缓存机制·数据派生
秋天的一阵风2 小时前
翻掘金看到停更的前辈们,突然想聊两句 🤔
前端·vue.js·程序员