在本文中,我们将扩展已在此处发布的概述,并检查 Vite 的源代码以提取有关其内部架构的一些见解。特别是,我们将探索 Vite 的模板和插件系统。到最后,你会更好地理解模板和插件的区别,以及 Vite 核心系统是如何连接到插件的。
现在事不宜迟,让我们用 Vite 创建一个应用程序。
使用 Vite 创建应用
出于本演示的目的,我们将使用以下命令创建一个 Vue 项目:
npm init vite@latest
(拥有者@latest将确保您npm install在这个新创建的项目中进行操作时始终获得最新版本。)
作为旁主,您可能已经看到了该init命令的弃用版本。
如您所见,其用警告告诉我们npm init vite改用它。
这个新命令基本上是以下的简写:
npx create-vite
这将安装并运行一个名为 的工具create-vite,它会提示您正在创建什么样的项目。您将选择一个名称和一个模板。
为您的项目选择一个您喜欢的名称。
并没有选择要使用的模板。
出于探索目的,您可以使用vanilla或vue。
接下来,我们将create-vite通过它在 GitHub 上面的源代码来探索这个工具。
探索 Vite 源代码
首先,访问 Vite 的 GitHub 页面github.com/vitejs/vite。
然后进入packages文件夹。
在这里,您可以看到create-app和create-vite。
create-app负责说“已弃用”的原始命令。我们在这里感兴趣的是create-vite文件夹。它托管用于项目创建的所有内置模板。
在packages文件夹内,我们还可以看到一些内置插件的插件文件夹。
现在是探索模板和插件之间差异以及它们如何在构建工具工作流程中协同工作的好时机。
模板
模板应该是一个容易理解的概念:它是新项目的起始代码。
在packages/create-vite文件夹内,您应该会看到十几个template-*文件夹。
/packages/create-vite
如您所见,Vite 支持各种不同框架(及其对应的 TypeScript)的模板。
您可以vanilla从create-vite提示中进行选择。
如果您选择 vanilla,它基本上会获取文件packages/template-vanilla夹中的文件并将它们克隆为您的新项目。
/packages/template-vanilla
您也可以vue从提示中选择:
如果您选择vue,它会将文件夹中的文件克隆packages/template-vue为您的新项目。
/packages/template-view
从 vue 模板生成的项目将具有您期望从 Vue 项目中获得的标准文件夹结构。
这就是模板。现在让我们谈谈插件。
插件
正如我所提到的,Vite 不是特定于框架的。由于其插件系统,它能够为各种框架创建项目。
Vite 开箱即用,为 Vue、Vue with JSX 和 React 提供插件。
packages您可以检查文件夹中每个内置插件的代码:
/包裹
注意:plugin-legacy适用于不支持本机 ESM 的旧版浏览器。
这些插件最常见的使用方式就是通过它们相应的模板。例如,Vue 模板将需要使用 Vue 插件,而 React 模板将需要使用 React 插件。
作为基本选项,使用 vanilla 模板创建的项目不知道如何提供 Vue 的单文件组件 (SFC) 文件。但是使用 Vite 创建的 Vue 项目将能够处理 SFC 文件类型。它还知道如何捆绑整个 Vue 项目已进行生产。
如果我们比较package.jsonVue 模板和 vanilla 模板中的各自文件,我们可以很容易地看出这是为什么。
/packages/template-vanilla/package.json
/packages/template-vue/package.json
template-vue包含所有的东西template-vanilla,加上三个额外的包。
/packages/template-vue/package.json
"dependencies": {
"vue": "^3.2.6" // 1
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.6.1", // 2
"@vue/compiler-sfc": "^3.2.6", // 3
"vite": "^2.5.4"
}
- vue是在运行时运行的主库
- @vitejs/plugin-vue是负责服务和捆绑 Vue 项目的插件
- @vue/compiler-sfc需要编译 SFC 文件
所以可以肯定地说,这三个包让 Vite 项目能够理解 Vue 代码。该@vitejs/plugin-vue包是连接 Vite 核心系统和 Vue.js 框架的“桥梁”。
用 Evan You 自己的话说……
在本文的其余部分,我们将继续使用 Vue 模板进行探索。但是,如果您想使用 vanilla 模板查看更酷的东西,您可以查看 Evan You 的Lightning Fast Builds with Vite课程中的本教程。
插件视图
正如我们在 Vue 插件中看到的package.json,这个@vitejs/plugin-vue包负责打包一个 Vue 项目。
Vite 将打包工作委托给 Rollup,这是另一个非常流行的构建工具。插件关系依赖于核心在某些特定时间点vite调用包代码。plugin这些特定点被称为“钩子”。插件开发者必须决定在每个钩子中执行什么代码。
例如,在 Vue 插件源代码中,您可以看到其中一些钩子的实现。
/packages/plugin-vue/src/index.ts
async resolveId(id) {
// component export helper
if (id === EXPORT_HELPER_ID) {
return id
}
// serve sub-part requests (*?vue) as virtual modules
if (parseVueRequest(id).query.vue) {
return id
}
},
load(id, ssr = !!options.ssr) {
if (id === EXPORT_HELPER_ID) {
return helperCode
}
const { filename, query } = parseVueRequest(id)
// select corresponding block for sub-part virtual modules
if (query.vue) {
if (query.src) {
return fs.readFileSync(filename, 'utf-8')
}
const descriptor = getDescriptor(filename, options)!
let block: SFCBlock | null | undefined
if (query.type === 'script') {
// handle <scrip> + <script setup> merge via compileScript()
block = getResolvedScript(descriptor, ssr)
} else if (query.type === 'template') {
block = descriptor.template!
} else if (query.type === 'style') {
block = descriptor.styles[query.index!]
} else if (query.index != null) {
block = descriptor.customBlocks[query.index]
}
if (block) {
return {
code: block.content,
map: block.map as any
}
}
}
},
transform(code, id, ssr = !!options.ssr) {
const { filename, query } = parseVueRequest(id)
if (query.raw) {
return
}
if (!filter(filename) && !query.vue) {
if (!query.vue && refTransformFilter(filename)) {
if (!canUseRefTransform) {
this.warn('refTransform requires @vue/compiler-sfc@^3.2.5.')
} else if (shouldTransformRef(code)) {
return transformRef(code, {
filename,
sourceMap: true
})
}
}
return
}
if (!query.vue) {
// main request
return transformMain(
code,
filename,
options,
this,
ssr,
customElementFilter(filename)
)
} else {
// sub block request
const descriptor = getDescriptor(filename, options)!
if (query.type === 'template') {
return transformTemplateAsModule(code, descriptor, options, this, ssr)
} else if (query.type === 'style') {
return transformStyle(
code,
descriptor,
Number(query.index),
options,
this
)
}
}
}
在主vite包中,Rollup 将用于调用上述插件钩子。
/packages/vite/src/node/build.ts
// first, gathers all the plugins used
const plugins = (
ssr ? config.plugins.map((p) => injectSsrFlagToHooks(p)) : config.plugins
) as Plugin[]
...
// then, put the plugins and everything else in an options object
const rollupOptions: RollupOptions = {
input,
preserveEntrySignatures: ssr
? 'allow-extension'
: libOptions
? 'strict'
: false,
...options.rollupOptions,
plugins,
external,
onwarn(warning, warn) {
onRollupWarning(warning, warn, config)
}
}
...
// lastly, delegate to rollup
const bundle = await rollup.rollup(rollupOptions)
Rollup 插件与 Vite 插件非常相似。但是由于 Rollup 不打算用作开箱即用的开发构建工具,Vite 插件将具有经典 Rollup 插件中不可用的额外选项和挂钩。
换句话说,Vite 插件是 Rollup 插件的扩展。
快速命令
回到 Vue 模板,让我们关注一下这个scripts选项。
/packages/create-vite/template-vue/package.json
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
这些配置使我们能够在 Vite 项目中执行以下命令:
- npm run dev用于启动开发服务器
- npm run build用于创建生产版本
- npm run serve用于在本地预览所述生产版本
上述命令映射到以下命令:
- vite
- vite build
- vite preview
如您所见,vite包是一切开始的地方。
package.json您可以通过查看包的文件来了解涉及哪些其他第三方工具vite。
/packages/vite/package.json
"dependencies": {
"esbuild": "^0.12.17",
"postcss": "^8.3.6",
"resolve": "^1.20.0",
"rollup": "^2.38.5"
},
如您所见,vite实际上在后台使用了两个不同的捆绑器:Rollup 和 esbuild。
Rollup 与 esbuild
Vite 将这两个捆绑器用于不同类型的活动。
Vite 使用 Rollup 来满足主要的捆绑需求。esbuild 用于模块兼容性和优化。这些步骤被称为“依赖预捆绑”过程。这个过程被认为是“繁重的任务”,因为它需要在每个模块的基础上完成,并且一个项目中通常使用许多模块。
模块兼容性意味着将不同的格式(UMD 或 CommonJS 模块)转换为标准的 ESM 格式。
优化是将单个依赖包中的所有各种文件捆绑到单个“事物”中,然后只需要获取一次。
与 esbuild 相比,Rollup 处理这些繁重的事情太慢了。Esbuild 实际上是目前最快的构建工具。它很快,因为它是用 Go(编程语言)开发的。
这是官方文档网站上显示的比较。
如您所见,esbuild 不仅速度快,而且速度快。它在另一个层面上。这就是为什么 Vite 快如闪电的原因。⚡
概括
在本文中,我们浏览了源代码并了解到:
- 该npm init vite命令正在使用该create-vite工具
- 该create-vite软件包包含所有内置模板
- 特定于框架的模板依赖于其对应的特定于框架的插件
- 插件在基于钩子的架构中实现
- Vite 在幕后同时使用 Rollup 和 esbuild
如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,,咱们下期见。
收藏 等于白嫖,点赞才是真情。
亲爱的小伙伴们,有需要JAVA面试文档资料请点赞+转发,关注我后,私信我333就可以领取免费资料哦