function resolveOptions() {
// command 可以是 dev/build/optimize
if (argv._[0]) {
argv.command = argv._[0];
}
return argv;
}
拿到 options 后,会根据 options.command
的值判断是执行在开发环境需要的 runServe 命令或生产环境需要的 runBuild 命令。
if (!options.command || options.command === ‘serve’) {
runServe(options)
} else if (options.command === ‘build’) {
runBuild(options)
} else if (options.command === ‘optimize’) {
runOptimize(options)
}
在 runServe
方法中,执行 server 模块的创建开发服务器方法,同样在 runBuild
中执行 build 模块的构建方法。
最新的版本中还增加了 optimize 命令的支持,关于 optimize 做了什么,我们下文再说。
server
这部分代码在 src/node/server/index.ts 里,主要暴露一个 createServer
方法。
vite 使用 koa 作 web server,使用 clmloader 创建了一个监听文件改动的 watcher,同时实现了一个插件机制,将 koa-app 和 watcher 以及其他必要工具组合成一个 context 对象注入到每个 plugin 中。
context 组成如下:
plugin 依次从 context 里获取上面这些组成部分,有的 plugin 在 koa 实例添加了几个 middleware,有的借助 watcher 实现对文件的改动监听,这种插件机制带来的好处是整个应用结构清晰,同时每个插件处理不同的事情,职责更分明,
plugin
上文我们说到 plugin,那么有哪些 plugin 呢?它们分别是:
-
用户注入的 plugins —— 自定义 plugin
-
hmrPlugin —— 处理 hmr
-
htmlRewritePlugin —— 重写 html 内的 script 内容
-
moduleRewritePlugin —— 重写模块中的 import 导入
-
moduleResolvePlugin ——获取模块内容
-
vuePlugin —— 处理 vue 单文件组件
-
esbuildPlugin —— 使用 esbuild 处理资源
-
assetPathPlugin —— 处理静态资源
-
serveStaticPlugin —— 托管静态资源
-
cssPlugin —— 处理 css/less/sass 等引用
-
…
我们来看 plugin 的实现方式,开发一个用来拦截 json 文件 plugin 可以这么实现:
interface ServerPluginContext {
root: string
app: Koa
server: Server
watcher: HMRWatcher
resolver: InternalResolver
config: ServerConfig
}
type ServerPlugin = (ctx:ServerPluginContext)=> void;
const JsonInterceptPlugin:ServerPlugin = ({app})=>{
app.use(async (ctx, next) => {
await next()
if (ctx.path.endsWith(‘.json’) && ctx.body) {
ctx.type = ‘js’
ctx.body = export default json
}
})
}
vite 背后的原理都在 plugin 里,这里不再一一解释每个 plugin 的作用,会放在下文背后的原理中一并讨论。
build
这部分代码在 node/build/index.ts 中,build 目录的结构虽然与 server 相似,同样导出一个 build 方法,同样也有许多 plugin,不过这些 plugin 与 server 中的用途不一样,因为 build 使用了 rollup ,所以这些 plugin 也是为 rollup 打包的 plugin ,本文就不再多提。
NO.4
vite 运行原理
ES module
要了解 vite 的运行原理,首先要知道什么是 ES module,目前流览器对其的支持如下:
主流的浏览器(IE11除外)均已经支持,其最大的特点是在浏览器端使用 export
import
的方式导入和导出模块,在 script 标签里设置 type="module"
,然后使用模块内容。
当 html 里嵌入上面的