慢慢认识世界,慢慢更新自己。
大家好,我是
柒八九
。
由于,新公司的项目打包是用的
Vite
,而之前的所参与的项目都是用
Webpack
作为打包工具,原来对
Vite
的了解,只是一个把玩工具,没有过多的深入了解。本着
干一行,爱一行
的职业态度。所以,就找了很多相关资料学习和研究。
以下的内容,都是基于本人对
Vite
的个人见解。不一定对,随便看看
你能所学到的知识点
-
vite 是个啥?
推荐阅读指数
⭐️⭐️⭐️
-
vite 打包阶段
推荐阅读指数
⭐️⭐️⭐️⭐️⭐️
-
打包阶段的插件执行顺序
推荐阅读指数
⭐️⭐️⭐️⭐️⭐️
-
Vite+React的项目打包优化(简单版)
推荐阅读指数
⭐️⭐️⭐️⭐️
好了,天不早了,干点正事哇。
这里再多絮叨几句,下面的大部分内容,都是从
Vite
打包阶段聊,针对
HMR
一些内容,没有涉及。
vite 是个啥?
Vite
是一种现代化的
前端构建工具
,它的目标是提供一种快速、简单和易于使用的开发体验。
Vite
使用了一些新的技术来实现快速的开发体验,这些技术包括
ES模块
、
即时编译
和
热重载
。
-
ES模块
是一种新的
JavaScript模块格式
,它是浏览器原生支持的。
ES模块
提供了一种简单、可读、可扩展的方式来组织代码,同时还提供了
静态分析
和
优化的机会
。
Vite
利用
ES模块
的特性,将应用程序拆分成更小的代码块,使得应用程序的加载时间更快。
-
-
即时编译是指在代码更改时,
Vite
会立即编译代码并将其发送到浏览器中。
-
这意味着开发人员不需要等待编译过程完成,就可以看到更改后的效果。
-
这大大缩短了开发周期,并提高了开发效率。
-
-
热重载是指在开发过程中,如果更改了代码,应用程序将自动重新加载,而无需手动刷新页面。这使得开发人员能够更快地看到更改后的效果,并且不会丢失任何数据。
想了解更多关于
Vite
的介绍,可以参考
官网
vite 打包阶段
在讨论
Vite
时,通常关注的是其作为
开发服务器
以及它如何在
开发过程中
实现即时反馈。但是,在生产环境下,
Vite
也会大放异彩。
下面,我们就一起来了解一下
Vite
是如何在
生产环境
下,对你的项目代码进行打包/优化处理的。本文假定你已经对
Vite
有一定的了解。如果第一次听说,你可以先移步到
为什么选 Vite
来了解相关的设计理念和解决哪些痛点。
用上帝视角看Vite如何处理资源
在一个
Vite
项目中,
index.html
在项目最外层而不是在
public
文件夹内。这是有意而为之的:在本地开发阶段
Vite
是一个资源服务器,而
index.html
是该
Vite
项目的入口文件。
Vite
将
index.html
视为源码和模块图的一部分。
这个
HTML
文件用于
引入网站资源信息
。
-
通过设置
type="module"
的
script
标签引入
JS
资源(外部资源和内联脚本)
-
通过设置
rel="stylesheet"
的
link
引入外部样式
<!DOCTYPE html>
<script type="module" src="/src/main.ts"></script>
<script type="module">
// 内联 script
</script>
<link rel="stylesheet" href="/src/main.css">
<style>
internal-style: {}
</style>
</head>
<div id="app"></div>
</body>
</html>
复制代码
Vite
接收
HTML
文件,来查找每个加载的JS模块、内联脚本和CSS样式表。
-
JS源代码
通过
Rollup
处理,解析和转换内部依赖项,生成一个
不经常更新
的
vendor.js
(带有依赖项)和一个
index.js
(应用程序的其余部分)。
-
-
这些源文件被转换成的带有
hash
值的文件,以实现
强缓存
。
-
任何在JS中被引用的
CSS
文件都会被打包到
index.css
文件中
script
或
import
可以指向任何文件类型,只要
Vite
知道如何转译它们即可。在上面的情况下,
main.ts
文件需要
在打包过程中转换为JS文件
。在
Vite
中,使用基于
Go
的打包工具
esbuild
实现对应资源的转换。
在资源被转换后,也会生成一个新的资源地址,用它们替换原来的资源地址。并且
Vite
执行
import
的
静态分析
,为每个JS插入
模块预加载标记
(
rel="modulepreload"
),使浏览器可以
并行加载
这些资源,从而避免加载瀑布效应。
<!DOCTYPE html>
<script type="module" src="/assets/index.d93758c6.js"></script>
<link rel="modulepreload" href="/assets/vendor.a9c538d6.js">
<link rel="stylesheet" href="/assets/index.3015a40c.css">
<style>
internal-style: {}
</style>
</head>
<div id="app"></div>
</body>
</html>
复制代码
Vite
针对
JS
和
CSS
资源支持代码分割。当遇到
动态导入
时,会生成一个异步JS块和一个CSS块。
其他资源,如图像、视频、
wasm
,可以
使用相对路径导入
。在生成其输出文件时,
Vite
还会对这些文件进行
hash
处理,并重写JS和CSS文件中的
URL
并指向它们。
另一方面,
public
文件夹中的资源会
按原样复制到输出根目录
,并允许用户通过
绝对路径引用这些文件
。
每个JS和CSS块都需要在生产中进行压缩。自从
Vite 2.6.0
以来,
Vite
也使用
esbuild
为两种语言执行压缩任务,以加快构建过程。
Rollup的二次封装
Vite
应用的
打包过程
,是基于
Rollup
的二次封装 。
Vite
中可以直接使用现有的
Rollup
插件,实现很多
开箱即用
的功能。
但是,需要注意一些与
Rollup
插件的兼容性问题,但
大多数来自
Rollup
生态系统的插件都可以直接作为
Vite
插件工作
。
Vite内部打包流程
下图展示了,
Vite
打包的大体流程。
上面的流程主要分四个步骤
-
收集打包配置信息
-
确认打包后的资源路径
-
使用
rollup
打包处理
-
资源输出
当你执行
vite build
时,
Vite CLI
被运行。运行命令是用
cac
实现的。该操作触发了
build
函数。
await build({ root, base, mode, config, logLevel, clearScreen, buildOptions })
复制代码
build
又调用
doBuild
。实现逻辑如下。
async function doBuild(inlineConfig: InlineConfig = {}): RollupOutput{
// ①收集打包配置信息
const config = await resolveConfig(inlineConfig, 'build', 'production')
// ②确认打包后的资源路径
const outDir = resolve(config.build.outDir)
prepareOutDir(outDir, config)
// ③打包处理
const bundle = await rollup.rollup({
input: resolve('index.html'),
plugins: config.plugins
// ④资源输出
return await bundle.write({
dir: outDir,
format: 'es',
exports: 'auto',
sourcemap: config.build.sourcemap,
entryFileNames: path.join(config.assetsDir, `[name].[hash].js`),
chunkFileNames: path.join(config.assetsDir, `[name].[hash].js`),
assetFileNames: path.join(config.assetsDir, `[name].[hash].[ext]`),
manualChunks: createMoveToVendorChunkFn()
复制代码
首先
,调用
resolveConfig
用于解析
用户配置
、
项目配置文件
和
Vite默认值
来生成一个具体的
ResolvedConfig
。
const config = await resolveConfig(inlineConfig, 'build', 'production')
复制代码
接下来
,确认好输出目录,并
在生成资产之前清空它
。这个函数还将
publicDir
的内容复制到项目
dist文件夹
。
const outDir = resolve(config.build.outDir)
prepareOutDir(outDir, config)
复制代码
然后
,基于
index.html
和
config.plugins
创建了
rollup
的
bundle
对象。
const bundle = await rollup.rollup({
input: resolve('index.html'),
plugins: config.plugins
复制代码
最后
,
bundle.write
被调用,用于生成输出目录中的资源信息。
return await bundle.write({
dir: outDir,
format: 'es',
exports: 'auto',
sourcemap: config.build.sourcemap,
entryFileNames: path.join(options.assetsDir, `[name].[hash].js`),
chunkFileNames: path.join(options.assetsDir, `[name].[hash].js`),
assetFileNames: path.join(options.assetsDir, `[name].[hash].[ext]`),
manualChunks: createMoveToVendorChunkFn()
复制代码
createMoveToVendorChunkFn
函数定义了
默认的分块策略
,定义了
JS
被打包后,何种资源被分配到
index.js
和
vendor.js
中。
具体实现如下:
function createMoveToVendorChunkFn() {
return (id, { getModuleInfo }) => {
id.includes('node_modules') &&
!isCSSRequest(id) &&
staticImportedByEntry(id, getModuleInfo)
return 'vendor'
复制代码
通过对
Vite
的打包做了一个简单的分析,我们可以得知:
Vite
的构建过程,就是以
Rollup
为基础,借助插件对资源的二次处理过程。
常见的插件
插件在
开发阶段
和
打包阶段
是通过
resolvedPlugins
进行解析。
Vite
在
打包时
通过
resolveBuildPlugins
插入
额外的插件,以处理压缩和其他优化
。
有一些关键插件。
-
vite:build-html
和
vite:html-inline-proxy-plugin
用于处理
HTML
,将
JS
和
CSS
替换为经
Vite
优化过的对应资源。
-
vite:css
和
vite:css-post
用于处理
CSS
和预处理器。
-
vite:esbuild
用于为每个模块转换
TypeScript
和
JSX
。
-
vite:asset
用于管理静态资源。
-
vite:build-import-analysis
用于
预加载优化
、支持全局导入和
URL
重写。
-
vite:esbuild-transpile
用于将
chunks
转换为合适的目标和压缩对应资源。
还有一些插件是
官方Rollup插件
-
alias
-
commonjs
-
rollup-plugin-dynamic-import-variables
打包阶段的插件执行顺序
就
webpac
k来说,
plugins
的作用在于强化其构建过程中,所遇到的一些工程化的问题,比如代码压缩,资源压缩等,所以
vite
作为新时代的构建工具,理应当也具有插件系统来解决构建项目的整个生命周期中所遇到的工程化的问题,说白了,插件就是为了解决某一类型的问题而出现的一个或一种工具函数。比如
lodash
,他被称之为一个库,也可以认作是一个插件。所以
vite
会在不同的生命周期中调用不同的插件去达成不同的目的。
让我们深入了解每个插件的使用方式和职责权限。
一个
Vite
插件可以额外指定一个
enforce
属性来调整它的应用顺序。
enforce
的值可以是
pre
或
post
。解析后的插件将按照以下顺序排列:
-
Alias
-
带有
enforce: 'pre'
的用户插件(
前置插件
)
-
Vite
核心插件
-
没有
enforce
值的用户插件(
常规插件
)
-
Vite
构建用的插件
-
带有
enforce: 'post'
的用户插件(
后置插件
)
-
Vite
后置构建插件(最小化,
manifest
,报告)
Vite
构建运行的插件的执行顺序如下:
-
alias
-
带有
enforce: 'pre'
的用户插件(
前置插件
)
-
vite:modulePreload
-
vite:resolve
-
vite:html-inline-proxy-plugin
-
vite:css
-
vite:esbuild
-
vite:json
-
vite:wasm
-
vite:worker
-
vite:asset
-
没有
enforce
值的用户插件(
常规插件
)
-
vite:define
-
vite:css-post
-
vite:build-html
-
commonjs
-
vite:data-uri
-
rollup-plugin-dynamic-import-variables
-
vite:asset-import-meta-url
-
带有
enforce: 'post'
的用户插件(
后置插件
)
-
vite:build-import-analysis
-
vite:esbuild-transpile
-
vite:terser
-
vite:manifest
-
vite:ssr-manifest
-
vite:reporter
1. alias
该插件,用于在打包时
定义别名
,与
Webpack
中的
resolve.alias
相同。
-
可以是一个对象
-
或一个
{ find, replacement, customResolver }
的数组
-
-
Array<{ find: string | RegExp, replacement: string, customResolver?: ResolverFunction | ResolverObject }>
用以下方法配置
Vite
resolve: {
alias: {
'@components': path.resolve(__dirname, 'src/components')
复制代码
可以让你从源码中的
任何地方
导入你想要导出的数据
import Button from '@components/Button.tsx'
复制代码
这个插件
解析路径并将它们转译为真实的路径
import Button from '../../components/Button.tsx'
复制代码
2. 带有
enforce: 'pre'
的用户插件(
前置插件
)
这些是带有
enforce: 'pre'
的插件。例如,
@rollup/plugin-image
配置了该属性,它就在
Vite
的内置插件之前运行。
import image from "@rollup/plugin-image"
export default {
plugins: [
...image(),
enforce: 'pre',
复制代码
3.
vite:modulePreload
-
类型:
boolean
|
{ polyfill?: boolean, resolveDependencies?: ResolveModulePreloadDependenciesFn }
-
默认值:
{ polyfill: true }
默认情况下,一个
模块预加载
polyfill
会被自动注入。该
polyfill
会自动注入到每个
index.html
入口的的代理模块中。
如果构建通过
build.rollupOptions.input
被配置为了使用
非 HTML 入口的形式
,那么必须要在你的自定义入口中
手动引入
该
polyfill
:
import 'vite/modulepreload-polyfill'
复制代码
polyfill 实现
<script>
function processPreload () {
const fetchOpts = {};
if (script.integrity)
fetchOpts.integrity = script.integrity;
if (script.referrerpolicy)
fetchOpts.referrerPolicy = script.referrerpolicy;
if (script.crossorigin === 'use-credentials')
fetchOpts.credentials = 'include';
else if (script.crossorigin === 'anonymous')
fetchOpts.credentials = 'omit';
fetchOpts.credentials = 'same-origin';
fetch(link.href, fetchOpts)
.then(res => res.ok && res.arrayBuffer());
const links = document.querySelectorAll('link[rel=modulepreload]');
for (const link of links)
processPreload(link);
</script>
复制代码
该
polyfill
允许
Vite
预加载模块以避免加载瀑布
,支持非
Chromium
浏览器。
4.
vite:resolve
它使用
Node解析算法
来定位
node_modules
中的
第三方模块
。它与官方的
rollup
插件不同,因为需要对
Vite
特定功能(
SSR
和
devServer
)进行特殊处理。
Node 文件定位
5.
vite:html-inline-proxy-plugin
该插件将
入口HTML文件
中的
内联脚本作为单独的模块加载
。这些脚本由
vite:build-html
插件将其从
HTML
中删除,并替换为一个
type="module"
的
script
。
6.
vite:css
该插件与
vite:css-post
插件一起使用来实现
Vite的CSS功能
。支持预处理器(
postCSS
、
sass
、
less
),包括解析导入的URL。
7.
vite:esbuild
类型:
ESBuildOptions | false
ESBuildOptions
继承自
esbuild
转换选项
。
最常见的用例是自定义 JSX:
export default defineConfig({
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
复制代码
默认情况下,
esbuild
会被应用在
ts
、
jsx
、
tsx
文件。你可以通过
esbuild.include
和
esbuild.exclude
对要处理的文件类型进行配置。
此外,你还可以通过
esbuild.jsxInject
来自动为
每一个被
esbuild
转换的文件注入 JSX helper
。
export default defineConfig({
esbuild: {
jsxInject: `import React from 'react'`,
复制代码
8. vite:json
处理
JSON
文件的导入。
// 导入整个对象
import json from './example.json'
// 导入一个根字段作为命名的出口, 便于tree shaking
import { field } from './example.json'
复制代码
9.
vite:wasm
此插件允许用户直接导入预编译的
.wasm
文件。
预编译的
.wasm
文件可以通过
?init
来导入。默认导出一个初始化函数,返回值为所导出
wasm
实例对象的
Promise
:
import init from './example.wasm?init'
init().then((instance) => {
instance.exports.test()
复制代码
在生产构建当中,体积小于
assetInlineLimit
的
.wasm
文件将会被内联为
base64
字符串。否则,它们将作为资源复制到
dist
目录中,并按需获取。
10.
'vite:worker'
通过构造器导入
一个
Web Worker
可以使用
new Worker()
和
new SharedWorker()
导入。与
worker
后缀相比,这种语法更接近于标准,是创建
worker
的 推荐 方式。
const worker = new Worker(
new URL('./worker.js', import.meta.url)
复制代码
worker
构造函数会接受可以用来创建 “模块”
worker
的选项:
const worker = new Worker(
new URL('./worker.js', import.meta.url),
{ type: 'module',}
复制代码
带有查询后缀的导入
你可以在导入请求上添加
?worker
或
?sharedworker
查询参数来直接导入一个
web worker
脚本。默认导出会是一个自定义
worker
的构造函数:
import MyWorker from './worker?worker'
const worker = new MyWorker()
复制代码
默认情况下,
worker
脚本将在生产构建中编译成
单独的 chunk
。如果你想将
worker
内联为
base64
字符串,请添加
inline
查询参数:
import MyWorker from './worker?worker&inline'
复制代码
如果你想要以一个
URL
的形式读取该
worker
,请添加
url
这个
query
:
import MyWorker from './worker?worker&url'
复制代码
11.
'vite:asset'
该插件用于资源的处理。
将资源引入为 URL
引入一个静态资源会返回解析后的公共路径:
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl
复制代码
例如,
imgUrl
在开发时会是
/img.png
,在生产构建后会是
/assets/img.2d8efhg.png
。
-
常见的
图像
、
媒体
和
字体文件
类型被
自动检测为资源
。你
-
-
可以使用
assetsInclude
选项扩展内部列表。(当从
HTML
引用它们或直接通过
fetch
或
XHR
请求它们时,它们将
被插件转换管道排除在外
。)
-
引用的资源作为构建资源图的一部分包括在内,将生成散列文件名,并可以由插件进行处理以进行优化。
-
较小的资源体积小于
assetsInlineLimit
选项值 则会被内联为
base64 data URL
。
显式 URL 引入
未被包含在
内部列表
或
assetsInclude
中的资源,可以使用
?url
后缀显式导入为一个 URL。
import workletURL from 'extra-scalloped-border/worklet.js?url'
CSS.paintWorklet.addModule(workletURL)
复制代码
将资源引入为字符串
资源可以使用
?raw
后缀声明作为字符串引入。
import shaderString from './shader.glsl?raw'
复制代码
public 目录
如果你有下列这些资源:
-
不会被源码引用(例如 robots.txt)
-
必须保持原有文件名(没有经过 hash)
-
...或者你压根不想引入该资源,只是想得到其 URL。
那么你可以将该资源放在指定的
public
目录中,它应位于你的
项目根目录
。该目录中的资源
在开发时能直接通过 / 根路径访问到,并且打包时会被完整复制到目标目录的根目录下
。
目录默认是
/public
,但可以通过
publicDir
选项 来配置。
请注意:
-
引入
public
中的资源
永远应该使用根绝对路径
-
-
举个例子,
public/icon.png
应该在源码中被引用为
/icon.png
。
-
public
中的资源不应该被
JavaScript
文件引用。
12. 常规插件
没有
enforce
值的用户插件
13.
'vite:define'
定义全局常量替换方式。其中每项在开发环境下会被定义在全局,而在
构建时被静态替换
。
类型:
Record
String
值会以原始表达式形式使用,所以如果定义了一个字符串常量,它需要被显式地打引号。(例如使用
JSON.stringify
)
define: {
__APP_VERSION__: `JSON.stringify(${version})`
复制代码
对于使用
TypeScript
的项目,还需要
env.d.ts
或
vite-env.d.ts
文件中添加
类型声明
,以获得类型检查以及代码提示。
// vite-env.d.ts
declare const __APP_VERSION__: string
复制代码
14. vite:css-post
这个插件用
esbuild
对CSS资源进行最小化。
css资源的URL占位符被解析为其最终的构建路径。
它还实现了
CSS代码拆分
。
Vite
会自动地将一个异步
chunk
模块中使用到的
CSS
代码抽取出来并为其生成一个单独的文件。这个
CSS
文件将在该异步
chunk
加载完成时
自动通过
一个 标签载入,该
异步
chunk
会保证只在
CSS
加载完毕后再执行
,避免发生
FOUC
。
{无样式内容的闪光|flash of unstyled content}(
FOUC
)是指在加载外部CSS样式表之前,
网页以浏览器的默认样式短暂出现
的情况,这是由于网络浏览器引擎在检索到所有信息之前渲染了该网页。
下面是
Vite
中预加载插件的的简化版本。
function createLink(dep) {
// JS -> <link rel="modulepreload" href="dep" />
// CSS -> <link rel="stylesheet" href="dep" />
function preload(importModule, deps) {
return Promise.all(
deps.map(dep => {
if (!alreadyLoaded(dep)) {
document.head.appendChild(createLink(dep))
if (isCss(dep)) {
// 等CSS资源加载,避免出现FOUC
return new Promise((resolve, reject) => {
link.addEventListener('load', resolve)
link.addEventListener('error', reject)
).then(() => importModule())
复制代码
这个插件将使用上面的辅助函数来转换动态导入。以下是
import('./async.js')
复制代码
将被转换为
preload(
() => import('/assets/async.js),
['/assets/async.css','/assets/async-dep.js']
复制代码
如果
build.cssCodeSplit
的值为
false
,这些块会被
vite:build-html
插件作为注入。
15. vite:build-html
这个插件会将
HTML
文件中的 标签编译成一个 JS 模块。
-
它会在
transform
钩子中移除
HTML
中的
script
标签,生成一个
JS
文件,用于引入每个模块和资源文件。
-
随后,在
generateBundle
钩子中插入 JS 文件,并使用
vite:asset
插件插入资源文件。
16. commonjs
它将
CommonJS
模块转换为
ES6
,这样它们就可以被包含在
Rollup
的包中。
-
在开发过程中,
Vite
使用
esbuild
进行资源的
pre-bundling
,它负责将
CommonJS
转换为
ES6
-
但在构建过程中,没有
pre-bundling
的这步,所以需要
commonjs
插件。
17. vite:data-uri
它从
data-URI
导入模块。
Data URL
,即前缀为
data:
协议的
URL
,其允许内容创建者向文档中嵌入小文件。
-
Data URL
由四个部分组成:前缀(
data:
)、指示数据类型的
MIME
类型、如果非文本则为可选的
base64
标记、数据本身:
-
data:[][;base64],
我们可以从
DataURL
中导入模块。
import batman from 'data:application/json;base64, eyAiYmF0bWFuIjogInRydWUiIH0=';
复制代码
18. rollup/plugin-dynamic-import-vars
用于支持动态导入中的变量。
它是用
build.dynamicImportVarsOptions
来配置的。
import dynamicImportVars from '@rollup/plugin-dynamic-import-vars';
export default {
plugins: [
dynamicImportVars({
// options
复制代码
允许用户编写动态解析的导入:
function importLocale(locale) {
return import(`./locales/${locale}.js`);
复制代码
19. vite:asset-import-meta-url
将
new URL(path, import.meta.url)
转换为内置
URL
import.meta.url
是一个
ESM
的原生功能,会暴露当前模块的
URL
。将它与原生的
URL 构造器
组合使用,在一个
JavaScript
模块中,
通过相对路径我们就能得到一个被完整解析的静态资源 URL
:
const imgUrl = new URL('./img.png', import.meta.url).href
document.getElementById('hero-img').src = imgUrl
复制代码
这个模式同样还可以通过字符串模板支持动态 URL:
function getImageUrl(name) {
return new URL(`./dir/${name}.png`, import.meta.url).href
复制代码
在生产构建时,
Vite
才会进行必要的转换保证 URL 在打包和资源哈希后仍指向正确的地址。然而,
这个
URL
字符串必须是静态的
,这样才好分析。否则代码将被原样保留、因而在
build.target
不支持
import.meta.url
时会导致运行时错误。
// Vite 不会转换这个
const imgUrl = new URL(imagePath, import.meta.url).href
复制代码
20. 后置插件
带有
enforce: 'post'
的用户插件。
21. vite:build-import-analysis
这个插件会对
URL 导入
进行词法分析、解析、重写和分析。
动态导入会增加预加载指令。在客户端代码中注入一个
辅助函数
,用于在异步块本身异步加载时
并行预加载 CSS
和直接导入的异步块。
Glob 导入
会被识别并使用
transformImportGlob
进行转译。例如:
const modules = import.meta.glob('./dir/*.js')
复制代码
被转化为
const modules = {
'./dir/foo.js': () => import('./dir/foo.js'),
'./dir/bar.js': () => import('./dir/bar.js')
复制代码
22. vite:esbuild-transpile
这个插件对每个渲染的块进行转译,以支持配置的目标。
如果
build.minify
是
"esbuild"
(
Vite3+
的版本是默认值),它也将使用
esbuild
来最小化代码,避免了对
terser
的需求。它比
terser
快 20-40 倍,压缩率只差
1%-2%
。
23. vite:terser
如果
build.minify
是
'terser'
,这个插件就会被用来使用
terser
对每个渲染的块进行最小化。
24. vite:manifest
当设置为
true
,构建后将会生成
manifest.json
文件,包含了没有被 hash 过的资源文件名和 hash 后版本的映射。可以为一些服务器框架渲染时提供正确的资源引入链接。当该值为一个字符串时,它将作为
manifest
文件的名字。
25. vite:ssr-manifest
当设置为
true
时,构建也将生成
SSR
的
manifest
文件,以确定生产中的样式链接与资产预加载指令。当该值为一个字符串时,它将作为
manifest
文件的名字。
26. vite:reporter
一个记录进度的插件,以及一份包含生成块和资源信息的报告。
$ vite build
vite v3.1.0 building for production...
✓ 34 modules transformed.
dist/assets/favicon.17e50649.svg 1.49 KiB
dist/assets/logo.ecc203fb.svg 2.61 KiB
dist/index.html 0.52 KiB
dist/assets/index.3015a40c.js 1.39 KiB / gzip: 0.73 KiB
dist/assets/index.d93758c6.css 0.77 KiB / gzip: 0.49 KiB
dist/assets/vendor.a9c538d6.js 129.47 KiB / gzip: 41.77 KiB
Done in 2.90s.
复制代码
Vite+React的项目打包优化(简单版)
可以从以下几点出发
-
代码分割
-
预取/预加载
-
代码压缩
-
图片压缩
-
缓存策略
代码分割
使用代码分割可以将代码划分成较小的块,从而减少页面加载时间。可以使用
Vite
提供的
import()函数
或
React
的
React.lazy()
函数来实现代码分割。
import React, { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./LazyComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
复制代码
预取/预加载
使用预取/预加载可以在用户访问页面之前预加载页面所需的资源,从而加快页面加载时间。可以使用Vite提供的
标签来实现预取/预加载。
<link rel="prefetch" href="./lazy-component.js" />
复制代码
代码压缩
使用代码压缩可以减小文件大小,从而加快页面加载时间。可以在
Vite
配置文件中启用代码压缩选项。
// vite.config.ts
import { defineConfig } from 'vite';
import reactRefresh from '@vitejs/plugin-react-refresh';
import { terser } from 'rollup-plugin-terser';
export default defineConfig({
plugins: [reactRefresh(), terser()],
复制代码
图片压缩
使用图片压缩可以减小图片大小,从而加快页面加载时间。可以使用
Vite
提供的
imagemin
插件来实现图片压缩。
// vite.config.ts
import { defineConfig } from 'vite';
import reactRefresh from '@vitejs/plugin-react-refresh';
import { imagemin } from 'rollup-plugin-imagemin';
export default defineConfig({
plugins: [
reactRefresh(),
imagemin({
plugins: [
// add imagemin plugins here
复制代码
缓存策略
使用缓存策略可以减少重复的网络请求,从而加快页面加载时间。可以在
Vite
配置文件中配置缓存策略选项。
// vite.config.ts
import { defineConfig } from 'vite';
import reactRefresh from '@vitejs/plugin-react-refresh';
export default defineConfig({
plugins: [reactRefresh()],
build: {
// set cache options here
cacheDir: '.vite-cache',
复制代码
后记
分享是一种态度
。
参考资料:
-
vite-plugin
-
vite-github
-
vite-build
全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。