面试官:你会看 Vite 源码吗?

5,253

前言

本来没有打算在专栏《Vite 从入门到精通》 插入这篇文章,但是刚好前几天一朋友去面试有被“虐”了一遍(如下图),身为好兄 (ji) 弟 (you) 的我说什么都要找回点场子了!

6391655286255_.pic.jpg

通过本文你将学会:

  • 如何自己去看 vite 源码;
  • 什么是 monorepo
  • 为什么使用 pnpm workspace
  • vite 各个目录 的作用;
  • vite 的三大命令 如何运行;
  • vite 优雅的使用了哪些插件;

vite 源码版本:v2.9.5

包管理器:pnpm

1. 拉取 vite 源码

方案1:git clone 到本地

 # 1. 克隆 github 仓库中的源码
 git clone https://github.com/vitejs/vite.git
 
 # 2. 进入 vite 目录
 cd vite
 
 # 3. 使用 pnpm 初始化
 pnpm install

方案2:在线查看

如果有同学不想克隆到本地,可以直接在浏览器中类似 vscode 中查看源码;

  1. 打开 vite 仓库地址:github.com/vitejs/vite ;

  2. 把其中 github.com 转成 github1s.com 即可;

  3. 打开 github1s.com/vitejs/vite

注意:由于 方案2 不能运行命令,也就不能断点调式了,所以想要调式代码的还需使用 方案1 哟 ~

源码结构如下图:

Untitled.png

2. 认识 monorepo

粗看 vite 源码文件目录,其实大家不难发现这是一个 monorepo 仓库; 只是使用的既不是 yarn workspace 也不是 lerna 包管理工具 之类的,而是使用 pnpm workspace ;

  1. 什么是 monorepo

    概念:简单点理解就是把 多个项目模块 放在 一个主干仓库之中管理

    而对应的就是传统的 multirepo 模式,即 一个项目对应一个仓库 来分散管理。

  2. 为什么使用 monorepo

    • 代码复用:同一个基础组件,工具函数会被多次用到;

    • 版本管理:统一版本管理;

    • 便于协同工作;

    • 依赖提升

此处只是简单的介绍 monorepo ,让大家明白它是什么就行了;

如果大家想了解更多,可查看:现代前端工程为什么越来越离不开 Monorepo

但是我们很明显的能看到,vite 仓库其实是用 pnpm workspace 来进行 monorepo 管理的;

  1. 为什么使用 pnpm workspace

    • 速度快;

    • 节省盘;

    • monorepo 的支持:因为其本身的设计机制,导致很多关键或者说致命的问题都得到了相当有效的解决;

    • 安全性高;

源码中 ./packages./packages/playground 文件中 每一个子文件 就代表了一个子项目,具体可查看 ./pnpm-workspace.yaml 中的配置

packages:
  - 'packages/*'
  - 'packages/playground/**'

3. packages 目录解析

水印_Untitled 1.png

  1. create-vite: 官方自带的所有已知可支持的 vite 模板;
  2. playground: 一些常见的 Vite 范例;
  3. plugin-legacy: 解决在不支持 ESM 的旧版浏览器提供支持;
  4. plugin-react: 完整的 React 支持插件包;
  5. plugin-vue: 对 vue3 单文件组件的支持插件包;
  6. plugin-vue-jsx: 提供对 Vue3 JSX 的支持插件包;
  7. vite: 核心包,所有运行的逻辑都在此包中;

4. 脚本命令解释

  1. 根目录脚本
{
	...
	"script": {
	// 限制只能用 pnpm 包管理器运行
	"preinstall": "npx only-allow pnpm",
	// 格式化代码
        "format": "prettier --write .",
        "lint": "eslint packages/*/{src,types}/**",
        // 运行测试用例代码
        "test": "run-s test-serve test-build",
        "test-serve": "jest",
        "debug-serve": "cross-env VITE_DEBUG_SERVE=1 node --inspect-brk ./node_modules/.bin/jest",
        "test-build": "cross-env VITE_TEST_BUILD=1 jest",
        "debug-build": "cross-env VITE_TEST_BUILD=1 VITE_PRESERVE_BUILD_ARTIFACTS=1 node --inspect-brk ./node_modules/.bin/jest",
        // 打包运行官方文档
        "docs": "vitepress dev docs",
        "build-docs": "vitepress build docs",
        "serve-docs": "vitepress serve docs",
        // 发布最新版本的代码
        "release": "ts-node scripts/release.ts",
        "ci-publish": "ts-node scripts/publishCI.ts",
        // build 本地 packages/vite、packages/plugin-vue、packages/plugin-react 中的代码
        "build": "run-s build-vite build-plugin-vue build-plugin-react",
        "build-vite": "cd packages/vite && npm run build",
        "build-plugin-vue": "cd packages/plugin-vue && npm run build",
        "build-plugin-react": "cd packages/plugin-react && npm run build",
        "ci-build-vite": "cd packages/vite && npm run ci-build",
        "ci-docs": "run-s build-vite build-plugin-vue build-docs"
	}
	...
}
  1. vite 包脚本

{
    ...
    "scripts": {
        // 打包开发环境可调式的目录代码
        "dev": "rimraf dist && rollup -c -w",
        // 打包生产环境目录代码
        "build": "rimraf dist && npm run lint && run-s build-bundle build-types",
        "build-bundle": "rollup -c",
        "build-types": "run-s build-temp-types patch-types roll-types",
        "build-temp-types": "tsc --emitDeclarationOnly --outDir temp/node -p src/node",
        "ci-build": "rimraf dist && run-s build-bundle build-types",
        "patch-types": "ts-node scripts/patchTypes.ts",
        "roll-types": "api-extractor run && rimraf temp",
        "lint": "eslint --ext .ts src/**",
        "format": "prettier --write --parser typescript \"src/**/*.ts\"",
        "prepublishOnly": "npm run build"
    }
    ...
}

5. 运行 vite

1. 打包:

# 1. 在跟目录运行
pnpm install

# 2. 进入 vite 核心包 
cd packages/vite

# 3. build
pnpm run dev

2. pnpm link:添加硬连接

pnpm linknpm link 使用虽部分相同,但是有本质上的区别;

最主要的区别在于 pnpm link 添加的是 硬链接npm link 添加的是 软连接

  1. 连接到本地 vite 包:
    # 1. 连接
    cd packages/vite && pnpm link “../../”
    
    # 2. 运行
    pnpx vite -v 即可正常运行
    
  2. 连接到全局 (建议使用)
    # 1. 连接
    cd packages/vite && pnpm link --global
    
    # 2. 运行
    vite -v 即可正常运行
    

3. 删除 pnpm link 连接

官方文档 `pnpm unlink` 后,其实并没有删除 .bin 目录下的可执行文件;

pnpm github 仓库已有 [issues](https://github.com/pnpm/pnpm/issues/4294),暂不做解释;

如果你非要强制删除咋办呢?
```bash
# 1. 找到可执行文件的绝对路径
where vite

# 2. 进入该路径
cd 上面输出的路径地址

# 3. 右键删除即可
```

4. 查看 packages/vite/package.json 中的 bin

{
    ... 
    "bin": { 
        "vite": "bin/vite.js"
    }
    ... 
}

通过该段代码,我们得知运行 vite 命令后,执行的是 bin/vite.js 文件;

bin/vite.js 中的主要执行的入口是 dist/node/cli.js

5. 查看 dist/node/cli.js

Untitled 3.png

从图中我们可以得知,vite 的默认命令是执行了 createServer 方法;

那么我们就可以在此处进行 断点调式

6. 在 VS Code 中调式 vite 代码

  1. 在 VS Code 中的右下角点击使用 JavaScript 调试终端 (建议使用)

    Untitled 2.png

  2. 其它调式方法 可参考

那么到现在我们就可以断点调试了

6. vite 的三大命令

  1. vite:亦可是 vite devvite servevite start

    • 作用: 启动开发服务器,主要运行方法
    • 源码入口文件: packages/vite/src/node/cli.ts 的 79 行
    • 源码主要运行文件: packages/vite/src/node/server/index.ts
    • 主要执行方法: createServer()
  2. vite build

    • 作用: 为生产环境构建产物
    • 源码入口文件: packages/vite/src/node/cli.ts 的 160 行
    • 源码运行文件: packages/vite/src/node/build.ts
    • 主要执行方法: build()
  3. vite preview

    • 作用: 在本地预览生产构建产物
    • 源码入口文件: packages/vite/src/node/cli.ts 的 232 行
    • 源码运行文件: packages/vite/src/node/preview.ts
    • 主要执行方法: preview()
  4. 其它命令:vite optimize

    • 作用: 内部的一个优化命令,主要将依赖打包成 ES6 Module 文件
    • 源码入口文件: packages/vite/src/node/cli.ts 的 191 行
    • 源码运行文件: packages/vite/src/node/optimize/index.ts
    • 主要执行方法: optimizeDeps()

由于文章主题不是在于讲解源码,所以具体 源码执行流程等原理 会在后续章节中解释;

感兴趣的同学可以关注我的专栏 《vite从入门到放弃》

7. vite 使用主要的核心插件集合

插件名插件功能github仓库源码使用详细地址
rollup在生产环境(Production)  下基于 rollup 打包来构建代码链接地址快速查看
esbuild在开发环境 预构建依赖链接地址快速查看
typescript这就不需要解释了吧链接地址all
@vue/compiler-dom对 .vue 文件编译处理链接地址快速查看
acorn一个小巧、快速的 JavaScript 解析器链接地址快速查看
cac构建 CLI 应用程序的命令行开发工具链接地址快速查看
chokidar监听文件的变化链接地址快速查看
connect最早期的 HTTP 服务器框架,亦可称为中间件插件链接地址快速查看
debugnodejs 的一个调式程序链接地址快速查看
dotenv把环境变量从 .env 文件加载到 process.env 中链接地址快速查看
fast-glob批量导入文件链接地址快速查看
http-proxy实现反向代理和负载均衡的插件链接地址快速查看
launch-editor-middleware定位到某个文件的行号链接地址快速查看
picocolors在终端使用 ANSI 颜色进行输出链接地址all
sirv类似 serve-static 静态资源请求链接地址快速查看
ws简单易用、速度极快的 WebSocket 客户端和服务器实现链接地址快速查看

上面只是简单的介绍一些实用较多的工具库,其实还没有很多,比如 rollup 全家桶 之类的,用于运行多个 npm 脚本的 npm-run-all,更好用的文件处理库 fs-extra,更好用的进程处理工具 execa,还有 源代码映射postcss 相关之类的,这些大家了解即可;

最后

其实像 vue3 源码vite 源码 使用工具库都较为类似,都通过 pnpm workspace 来进行包管理,也都是通过 typescript 静态语言来进行编程;

该系列会是一个持续更新系列,关于整个《Vite 从入门到放弃》专栏,我主要会从如下图几个方面讲解,感兴趣的同学可以关注下,请大家拭目以待吧!!!

Untitled.png

靓仔靓女们,都看到这里了,要不三连一下呗 😂 😂 😂