1. 下载Vue源码(版本:3.5.17)
基本结构:
arduino
vue-next-3.5.17 (Vue.js 核心仓库)
├── tsconfig.json // TypeScript 配置文件
├── rollup.config.js // rollup 的配置文件
├── packages // 核心代码包
│ ├── vue-compat // 用于兼容 vue2 的代码
│ ├── vue // 重要: 浏览器实例,打包之后的 dist 都会放在这里
│ ├── template-explorer // 提供了一个线上的测试 (https://template-explorer.vuejs.org/),用于把 template 转化为 render
│ ├── size-check // 测试运行时包大小
│ ├── shared // 重要: 共享的工具类
│ ├── sfc-playground // sfc 工具,比如: https://sfc.vuejs.org/
│ ├── server-renderer // 服务器渲染
│ ├── runtime-test // runtime 测试相关
│ ├── runtime-dom // 重要: 基于浏览器平台的运行时
│ ├── runtime-core // 重要: 运行时的核心内容,内部针对不同平台进行了实现
│ ├── reactivity-transform // 已过期,无需关注
│ ├── reactivity // 重要: 响应式的核心模块
│ ├── global.d.ts // 全局的 ts 声明
│ ├── compiler-ssr // 服务端渲染的编译模块
│ ├── compiler-sfc // 单文件组件 (.vue) 的编译模块
│ ├── compiler-dom // 重要: 浏览器相关的编译模块
│ └── compiler-core // 重要: 编译器核心代码
├── package.json // npm 包管理工具
├── netlify.toml // 自动化部署相关
├── jest.config.js // 测试相关
├── api-extractor.json // TypeScript 的 API 分析工具
├── SECURITY.md // 报告漏洞,维护安全的说明文件
├── README.md // 项目声明文件
├── LICENSE // 开源协议
├── CHANGELOG.md // 更新日志
├── BACKERS.md // 赞助声明
├── test-dts // 测试相关,不需要关注
├── scripts // 配置文件相关,不需要关注
├── pnpm-workspace.yaml // pnpm 相关配置
└── pnpm-lock.yaml // 使用 pnpm 下载的依赖包本
核心包结构详解:
-
🔥 核心模块 (最重要)
- vue - 主入口包,整合所有功能模块
- compiler-core - 编译器核心,处理模板编译逻辑
- compiler-dom - DOM相关的编译器,处理浏览器特定的编译
- runtime-core - 运行时核心,平台无关的运行时逻辑
- runtime-dom - DOM运行时,浏览器平台的运行时实现
- reactivity - 响应式系统,Vue的响应式核心
- shared - 共享工具函数和常量
-
🛠️ 构建与工具
- compiler-sfc - 单文件组件编译器
- compiler-ssr - 服务端渲染编译器
- server-renderer - 服务端渲染器
- runtime-test - 测试运行时环境
-
🔄 兼容与扩展
- vue-compat - Vue 2.x 兼容层
-
📁 私有包 (packages-private/)
- sfc-playground - 单文件组件在线演练场
- template-explorer - 模板编译探索工具
- dts-test - TypeScript 类型定义测试
-
⚙️ 配置与脚本
- scripts/ - 构建脚本和开发工具
- 各种配置文件 (TypeScript, ESLint, Rollup 等)
这个项目采用 monorepo 架构,使用 pnpm 作为包管理器,支持多种构建格式 (ESM, CJS, UMD等),为不同的使用场景提供了完整的解决方案。
2. 运行Vue源码
-
安装 pnpm 包管理工具
npm install -g pnpm
pnpm 会通过一个 集中管理 的方式来管理 电脑中所有项目 的依赖包,以达到 节约电脑磁盘 的目的。
- 项目根目录下安装依赖
css
pnpm i

- 项目打包
arduino
npm run build
- 查看生成的文件 packages/vue/dist
csharp
vue.runtime.esm-browser.prod.js // 浏览器用 ESM 运行时生产环境版
vue.esm-browser.prod.js // 浏览器用 ESM 完整版生产环境
vue.runtime.global.prod.js // 浏览器用全局运行时生产环境版
vue.global.prod.js // 浏览器用全局完整版生产环境
vue.cjs.prod.js // CommonJS 生产环境版
vue.runtime.esm-browser.js // 浏览器用 ESM 运行时开发版
vue.esm-browser.js // 浏览器用 ESM 完整开发版
vue.runtime.global.js // 浏览器用全局运行时开发版
vue.global.js // 浏览器用全局完整版开发版
vue.cjs.js // CommonJS 开发版
vue.runtime.esm-bundler.js // ESM Bundler 运行时(供打包工具用)
vue.esm-bundler.js // ESM Bundler 完整版(供打包工具用)

3. 构建运行测试实例
-
在源码中 \core\packages\vue\examples(vue自己的测试实例) 下新建 my-examples 文件夹,用于放我们的测试实例。
-
VSCode中安装 Live Server 插件,帮我们直接启动一个 本地服务。

- 创建实例文件:reactive.html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../../dist/vue.global.js"></script>
</head>
<body>
<div id="app"></div>
<script>
// 1. 从 Vue 中解构出 reactive、effect 函数
const { reactive, effect } = Vue;
// 2. 创建响应式对象
const state = reactive({
count: 0
});
// 3. 创建副作用函数(effect)
effect(() => {
document.querySelector('#app').innerHTML = `count is: ${state.count}`;
});
// 4. 定时修改响应式对象的属性,触发副作用函数,更新 DOM(视图发生变化)
setTimeout(() => {
state.count++;
}, 1000);
</script>
</body>
</html>
- 鼠标右键 -> Open with Live Server

- 等待 1s,count 由 0 变成了 1,说明已经成功运行了一个测试实例。
4. 对 Vue 进行debugger
- 开启 SourceMap(源代码映射)
未开启SourceMap时的开发者工具(F12 Sources模块):

开启SourceMap之后:

在执行 npm run build 时,实际执行的是 scripts/build.js 文件

(scripts/build.js)可以找到这么一行代码: ```sourceMap ? SOURCE_MAP:true
: `````

在 rollup.config.js 文件中 output.sourcemap = !!process.env.SOURCE_MAP
赋值给 output.sourcemap。

sourceMap 是通过 parseArgs(nodejs.org/api/util.ht...) 解析命令行参数得到的。parseArgs 解析后,values 对象中会包含 sourceMap 字段,然后通过解构赋值。
--sourceMap
是完整参数名-s
是它的短写

所以 sourceMap 的值最终取决于 运行 scripts/build.js 时是否传递了 --sourceMap 或 -s 参数。
- 修改 package.json,修改build脚本命令
json
"build": "node scripts/build.js -s"

重新执行 npm run build
- 查看源代码
ctrl+p 搜索文件,可以看到有对应的 effect.ts 和 reactive.ts 文件


- 添加断点
点击行序号 94,断点调试 reactive 的代码执行逻辑。
刷新页面,进入调试

5. 开始搭建
- 创建 package.json 模块
csharp
npm init -y

- 新建文件夹结构 packages (核心代码区域)
go
vue-mini (Vue.js MVP)
├── packages // 核心代码包
│ ├── vue // 打包、测试实例、项目整体入口
│ ├── shared // 共享的工具类
│ ├── runtime-dom // 基于浏览器平台的运行时(浏览器部分运行时内容)
│ ├── runtime-core // 运行时的核心内容,内部针对不同平台进行了实现
│ ├── reactivity // 响应式的核心模块
│ ├── compiler-dom // 重要: 浏览器相关的编译模块
│ └── compiler-core // 重要: 编译器核心代码
├── package.json // npm 包管理工具

- 导入 ts 配置
- 项目根目录下创建 tsconfig.json 配置文件(What is a tsconfig.json),用于指定编译项目所需的入口文件和编译器配置。(也可以通过 tsc -init 生成默认配置,这个需先 npm i -g typescript)
- 指定如下配置(www.typescriptlang.org/tsconfig/)
json
{
// 编译器配置
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
// 指定JS语言版本
"target": "es5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// https://www.typescriptlang.org/tsconfig#lib
"lib": [
"esnext",
"dom"
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "libReplacement": true, /* Enable lib replacement. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
// 模块化
"module": "esnext" /* Specify what module code is generated. */,
// 指定根目录
"rootDir": "." /* Specify the root folder within your source files. */,
// 指定模块解析策略(指定类型脚本如何从给定的模块说明符查找文件)
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "noUncheckedSideEffectImports": true, /* Check side effect imports. */
// 允许解析 .json 文件
"resolveJsonModule": true /* Enable importing .json files. */,
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// 禁用 sourceMap
"sourceMap": false /* Create source map files for emitted JavaScript files. */,
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// 转换为 JavaScript 时, 从 TypeScript 文件中删除所有注释
"removeComments": false /* Disable emitting comments. */,
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// 向下兼容迭代器(支持语法迭代) https://www.typescriptlang.org/tsconfig#downlevelIteration
"downlevelIteration": true /* Emit more compliant, but verbose and less performant JavaScript for iteration. */,
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
// "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
// 启用 ES 模块互操作性 https://www.typescriptlang.org/tsconfig#esModuleInterop
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
// 启用所有严格类型检查选项
"strict": true /* Enable all strict type-checking options. */,
// 启用隐式 any 类型检查(有助于简化 ts 复杂度,从而更加专注于逻辑本身)
"noImplicitAny": false /* Enable error reporting for expressions and declarations with an implied 'any' type. */,
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// 允许未使用的局部变量
"noUnusedLocals": false /* Enable error reporting when local variables aren't read. */,
// 允许未使用的参数
"noUnusedParameters": false /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
// "skipLibCheck": true, /* Skip type checking all .d.ts files. */
},
// 入口
"include": ["packages/*/src"]
}
- 配置 prettier 格式化代码工具
- VSCode中安装 prettier 辅助插件

- 项目根目录下创建
.prettierrc
文件
json
{
// 结尾无分号
"semi": false,
// 全部使用单引号
"singleQuote": true,
// 每行最大长度
"printWidth": 80,
// 末尾不添加逗号
"trailingComma": "none",
// 省略箭头函数括号
"arrowParens": "avoid"
}
6. 模块打包器 rollup(www.rollupjs.com/)
与 webpack(webpack.docschina.org/concepts/)一样,可以将 JS 打包为指定模块。区别在于,对于 webpack 而言,打包时会产生许多冗余的代码,在开发大型项目的时候没有什么影响,但是在开发一个库的时候,冗余代码会大大增加库体积,导致不够美好。
rollup 可以将小块代码编译成大块复杂的代码,例如 libray 或应用程序。
Rollup 是一个用于 JavaScript 的模块打包工具,它将小的代码片段编译成更大、更复杂的代码,例如库或应用程序。
6.1. 如何理解更大,更复杂?
这其实是指 Rollup 的主要用途和工作方式:
- 将多个小模块合并成一个文件
在开发时,我们通常会把代码拆分成很多小的模块(每个功能一个文件),这样方便维护和复用。但在发布时,如果直接把这些小文件交给浏览器加载,会导致很多网络请求,影响性能。
- 打包过程
Rollup 会把这些分散的小模块"打包"成一个或几个大的文件。这个过程叫做"bundling"(打包),其实就是把很多小的代码片段合并成一个更大的整体。
- 更复杂的代码
合并后,Rollup 还会做一些优化,比如去除没用的代码(tree-shaking)、转换语法等。最终生成的文件,虽然体积可能更小,但结构上比单个小模块要复杂,因为它包含了所有模块的内容和模块之间的依赖关系处理。
举个例子:
假设你有三个模块:a.js、b.js、c.js。每个文件都很简单,但打包后,Rollup 会把它们合成一个 bundle.js,这个文件里包含了所有模块的代码和它们的依赖关系。这样,浏览器只需要加载一个文件。
总结
这里的"更大、更复杂"不是说代码变得难以理解,而是说:
- 文件体积变大(因为合并了多个模块)
- 代码结构更复杂(因为要处理模块之间的依赖和作用域)
但这样做的好处是:加载更快、部署更方便、可以做更多优化。
可以理解为 rollup 为一个打包 库 的模块打包器,而应用程序打包时则选择 webpack。
6.2. 引入 rollup
- 项目根目录下创建 rollup.config.js 文件
js
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
/**
* 默认导出一个数组,数组的每一个对象都是一个单独的导出文件配置。https://www.rollupjs.com/guide/big-list-of-options
*/
export default {
// 入口文件
input: 'packages/vue/src/index.ts',
// 打包出口
output: [
// 导出 iife 模式的包
{
// 开启 sourcemap
sourcemap: true,
// 导出 iife 模式的包
format: 'iife',
// 导出的文件地址
file: './packages/vue/dist/vue.js',
// 变量名
name: 'Vue',
}
],
// 插件
plugins: [
// ts 支持
typescript({
sourceMap: true,
}),
// 将 CommonJS 转换为 ES2015 模块
commonjs(),
// 模块导入的路径补全
resolve(),
],
}
- 修改 package.json 文件
json
{
"name": "vue-mini",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "rollup -c"
},
"repository": {
"type": "git",
"url": "https://gitee.com/carrierxia/vue-mini.git"
},
"devDependencies": {
"rollup": "^3.12.0",
"@rollup/plugin-commonjs": "^26.0.2",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-typescript": "^10.0.0",
"typescript": "^5.7.3",
"tslib": "^2.8.1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module"
}

- 执行 npm i 安装依赖
- 在新增 \vue-mini\packages\vue\src\index.ts 文件,输入
js
console.log("Vue")
- 执行 npm build 打包,可以看到生成了对应 dist 文件夹

7. 配置路径映射
json
{
// 编译器配置
"compilerOptions": {
...
// 指定基础目录
"baseUrl": "./" ,
// 指定模块路径别名
"paths": {
"@vue/*": ["packages/*/src"]
}
}
}