vite
是一个构建工具,相较于 webpack
,vite
采用了不同的运行方式:
开发阶段:
在开发阶段,Vite 的工作流程如下:
Vite 会先将项目中的第三方依赖(如 node_modules
中的包)进行预构建。它使用了 esbuild
这个超快的构建工具进行依赖的打包,将其他规范的代码转换成esmodule
规范,然后放到当前目录下的node_modules/.vite/deps
,同时对esmodule
规范的各个模块进行统一集成。
预构建的目的是通过 esbuild 将 CommonJS 和 UMD 格式的模块转换为 ESM 格式(主要是node_modules中的第三方依赖),这样浏览器就可以直接加载这些依赖。
解决了:
- 不同的第三方包会有不同的导出格式(vite没法约束第三方包)
- 对路径的处理可以直接使用
node_modules/.vite/deps
,方便路径重写- 网络多包传输的性能问题(也是原生esmodule规范不敢支持node_modules的原因之一,这样会导致网络加载很多依赖),有了依赖预构建以后无论有多少额外的export和import,vite都会尽可能的将他们进行集成,最后只生成一个或几个模块
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
optimizeDeps: {
exclude: ['lodash-es'] // 当遇到lodash-es这个依赖时不进行依赖预构建
}
})
当你在开发时请求一个模块时,Vite 会根据请求动态地加载该模块,并通过 HTTP 服务返回给浏览器。因为是 ESM 格式,浏览器会根据模块的导入顺序按需加载依赖,而无需一次性加载所有内容。
Vite 提供了极快的热模块替换机制。它会在你修改代码后只替换那些真正变化的模块,而不是重新打包整个项目。这样一来,开发体验更为流畅。
构建(打包)阶段:
在构建阶段,Vite 则会采用传统的打包方式,将项目的所有资源打包成可以用于生产环境的静态文件。Vite 默认使用 Rollup 作为打包工具,因此你可以享受到 Rollup 提供的所有优化特性。
Vite 的构建过程主要包括以下几步:
Vite 会分析项目中的所有模块依赖关系,生成模块依赖图。这些依赖关系将帮助 Vite 决定哪些模块需要打包在一起,哪些模块可以分包。
基于依赖分析的结果,Vite 会对代码进行拆分,将共享的模块提取到单独的 chunk 中。这种方式可以实现更好的缓存利用和并行加载。
Vite 会使用 Rollup 的各种优化插件对代码进行优化,比如 tree-shaking(移除未使用的代码)、代码压缩、资源内联等,以生成更小、更高效的最终产物。
Vite 会处理静态资源(如图片、CSS、字体等),将它们打包并优化。对于大文件,Vite 会将其拆分成小块,以支持按需加载。
最终,Vite 会生成一组静态文件,通常包括一个或多个 JavaScript 文件、CSS 文件以及其他资源文件。这些文件可以直接部署到生产环境中。
起因:当我们开始构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。基于 JavaScript 开发的工具就会开始遇到性能瓶颈:通常需要很长时间(甚至是几分钟!)才能启动开发服务器,即使使用模块热替换(HMR),文件修改后的效果也需要几秒钟才能在浏览器中反映出来。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和幸福感。(来自vite官网)
当项目越大,构建工具(webpack)所需要处理的js越多(跟webpack的工作流程有关),就会导致需要很长时间才能启动开发服务器
vite
npm i vite -D
index.html
文件DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>vitetitle>
head>
<script
defer
type="module"
src="./index.js"
>script>
<body>body>
html>
需要使用模块化的方式引入
index.js
文件,否则会报错
vite
的源码目录就是根目录
index.js
文件中引入 css
文件import './style/index.css'
const h1 = document.createElement('h1')
h1.innerText = 'hello vite!!!'
document.body.appendChild(h1)
console.log('hello vite')
vite
npx vite
vite
: 启动vite
开发服务器
vite build
: 打包vite
项目
vite preview
: 预览vite
打包后的代码
defineConfig
import { defineConfig } from "vite"
export default defineConfig({
build: {
rollupOptions: {
input: {
index: "index.js",
}
}
}
})
/** @type {import('vite').UserConfig} */
注释/** @type {import('vite').UserConfig} */
const viteConfig = {
build: {
rollupOptions: {
input: {
index: "index.js",
}
}
}
}
export default viteConfig
文件有:
后三个文件配置:根据不同环境分别配置
import { defineConfig } from "vite" export default defineConfig({})
这里的
defineConfig
也可以使用函数,函数返回配置对象,函数解构的参数有command
和mode
- command:
build
和serve
- mode:
development
和production
import { defineConfig } from "vite"
import viteBaseConfig from "./vite.base.config";
import viteDevConfig from "./vite.dev.config";
import viteProdConfig from "./vite.prod.config";
export default defineConfig(({ command, mode }) => {
// command: 'build' or 'serve'
// mode: 'development' or 'production'
if (command === 'serve') {
// 开发环境
return {
...viteBaseConfig,
...viteDevConfig,
}
} else {
// 生产环境
return {
...viteBaseConfig,
...viteProdConfig,
}
}
})
使用策略模式进行重构:
import { defineConfig } from 'vite'
import viteBaseConfig from './vite.base.config'
import viteDevConfig from './vite.dev.config'
import viteProdConfig from './vite.prod.config'
// 策略模式
const envResolver = {
build: () => ({ ...viteBaseConfig, ...viteProdConfig }),
serve: () => ({ ...viteBaseConfig, ...viteDevConfig })
}
export default defineConfig(({ command, mode }) => {
// command: 'build' or 'serve'
return envResolver[command]()
})
会根据当前的代码环境产生值的变化的变量
代码环境:
- 开发环境
- 测试环境
- 生产环境
- 预发布环境
- 灰度环境
- …
vite内使用dotenv
这个库,dotenv会自动读取.env
文件,并解析这个文件中对应的环境变量,并将其注入到process
对象下(node进程对象),会涉及到一些vite.config.js中的一些配置:
index.html
文件所在的位置)。可以是一个绝对路径,或者一个相对于该配置文件本身的相对路径。默认值:process.cwd().env # 所有情况下都会加载
.env.local # 所有情况下都会加载,但会被 git 忽略
.env.[mode] # 只在指定模式下加载
.env.[mode].local # 只在指定模式下加载,但会被 git 忽略
但是vite考虑到和其他配置冲突问题,它不会直接注入到process对象下,可以手动调用vite
的loadEnv
来手动确认env文件。
// vite.config.js
import { defineConfig, loadEnv } from 'vite'
import viteBaseConfig from './vite.base.config'
import viteDevConfig from './vite.dev.config'
import viteProdConfig from './vite.prod.config'
// 策略模式
const envResolver = {
build: () => ({ ...viteBaseConfig, ...viteProdConfig }),
serve: () => ({ ...viteBaseConfig, ...viteDevConfig })
}
export default defineConfig(({ command, mode }) => {
/**
* 当前env的文件目录
* - 参数1:当前模式,dev/build
* - 参数2:env路径
* - 参数3:env前缀
*/
const env = loadEnv(mode, process.cwd(), '')
console.log('env', env) // 这个时候.env.production中的环境变量就被加到env中了,但是process.env访问不到
return envResolver[command]()
})
注意:
loadEnv(mode, process.cwd(), '')
,这里的mode是脚本中vite --mode develpment
,省略默认为develpoment
当我们调用
loadEnv
的时候,会做如下事情:
- 直接找到
.env
文件不解释,并解析其中的环境变量,放进一个对象里- 会将传进来的
mode
这个变量的值进行拼接:.env.development
,并根据我们提供的目录(提供的目录是指第二个参数传递的process.cwd()
)去取对应的配置文件并进行解析,并放进一个对象- 将后者对象合并前者
const baseEnvConfig = {...xxx} const modeEnvConfig = {...xxx} const lastEnvConfig = {...baseEnvConfig, ...modeEnvConfig}
**node环境中:**例如在vite.config.js中,通过const env = loadEnv(mode, process.cwd(), '')
来读取
**在客户端中:**vite会将对应的环境变量注入到import.meta.env.xxx
中,但是vite做了一层拦截,如果你的环境变量不是以VITE_
开头的,就不会注入到客户端中(node中可以得到)。例如:import.meta.env.VITE_APP_KEY
- .env:所有环境需要用到的环境变量
- .env.development:开发环境需要用到的环境变量(默认情况下vite将开发环境取名为development,所有dotenv才能读到
.env.development
)- .env.production:生产环境
补充知识:为什么vite.config.js可以书写成esm规范?
因为vite在读取这个vite.config.js的时候会率先node去解析文件语法,如果发现你是esm规范,会直接将你的esm规范进行替换成commonjs规范
具体参考上面原理
/**
* 当前env的文件目录
* - 参数1:当前模式,dev/build
* - 参数2:env路径
* - 参数3:env前缀
*/
const env = loadEnv(mode, process.cwd(), '')
console.log('env', env) // 这个时候.env.production中的环境变量就被加到env中了,但是process.env访问不到
注意:需要添加
VITE_
前缀
import.meta.env.VITE_APP_KEY
// .env.development
VITE_APP_KEY=123
如果想要更改这个前缀,可以使用envPrefix
配置
// vite.config.js
import { defineConfig } from "vite"
export default defineConfig({
envPrefix: "WIFI_", // 配置vite注入客户端环境变量校验的前缀
})
vite搭建了一个开发服务器,这时候的vue文件是已经经过编译后的js了,通过开发服务器设置浏览器解析文件的方式(设置Content-Type
)来加载。
res.set("Content-Type", "text/javascript") // 让浏览器以js的方式解析vue文件
const koa = require('koa');
const fs = require('fs');
const path = require('path');
const app = new koa();
app.use(async (ctx) => {
if (ctx.request.url === '/') {
const htmlContent = await fs.promises.readFile(path.resolve(__dirname, 'index.html'));
ctx.response.body = htmlContent;
ctx.response.set('Content-Type', 'text/html');
}
if (ctx.request.url.endsWith('.js')) {
const JSContent = await fs.readFileSync(path.resolve(__dirname, 'main.js'), 'utf-8');
console.log(JSContent);
ctx.response.body = JSContent;
ctx.response.set('Content-Type', 'application/javascript');
}
});
app.listen(3000, () => console.log('listening on port 3000'));
vite天生就支持对css的处理
处理css原理:
main.js
中读取到了index.css
fs
模块去读取index.css
中的文件内容style
标签,将css文件内容直接copy进style标签中css模块化原理(css module):
header
替换成_heaedr_i122st_1
){ header: '_heaedr_i122st_1' }
原理都是:开发服务器设置
Content-Type
在vite.config.js中我们通过css属性中的module去控制整个vite对css的处理行为
localsConvention:修改生成的配置对象的key的展示形式(驼峰还是中横线)
camelCase:驼峰和中横线都生成
camelCaseOnly:只展示驼峰命名
dashes:驼峰和中横线都生成,默认是驼峰
dashesOnly:只有中横线
scopeBehaviour:配置当前的模块化行为是模块化还是全局化(类名带hash的就是开启了模块化)
generateScopedName:生成模块化类名的格式
export default defineConfig({
css: { // 对css进行配置
modules: { // 对css模块化的默认行为进行覆盖
// 方法1:
generateScopedName: "[name]__[local]___[hash:base64:5]", // 生成模块化类名的格式,格式在postcss官网中
// 方法2:
generateScopedName: (name, filepath, css) => {
console.log(name, filepath, css);
return "123" // 所有的类名都为123了
}
}
}
})
globalModulePaths: ["/src/styles/global.css"]
示例:
import { defineConfig } from "vite"
export default defineConfig({
css: { // 对css进行配置
modules: { // 对css模块化的默认行为进行覆盖
localsConvention: "camelCase", // 修改生成的配置对象的key的展示形式(驼峰还是中横线)
scopeBehaviour: "local", // 配置当前的模块化行为是模块化还是全局化
generateScopedName: "[name]__[local]___[hash:base64:5]", // 生成模块化类名的格式,格式在postcss官网中
hashPrefix: "prefix", // 生成哈希值的前缀,会参与hash的运算
globalModulePaths: ["/src/styles/global.css"] // 全局css的存放路径,会作为全局的css,不会被模块化
}
}
})
preprocessorOptions:主要是用来配置css预处理的一些全局参数,key(预处理器名) + config形式配置
less、sass:css预处理器
postcss:css后处理器
import { defineConfig } from "vite"
export default defineConfig({
css: { // 对css进行配置
preprocessorOptions: { // 对css进行预处理,比如less,scss等
less: { // 整个配置对象都会最终给到less的执行参数中去(例如:在没有构建功能的情况下,通过less的命令去构建,命令的参数就是配置的对象)
math: "always",
globalVars: { // 全局变量,可以在所有less文件中直接使用,在webpack给less的loader中配置
mainColor: "red", // less中使用: color: @mainColor;
}
},
sass: {
}
},
devSourcemap: true // 开启css的sourceMap,默认为false
},
})
vite天生支持postcss,postcss主要做css样式兼容的、前缀补全,后处理器
npm i postcss postcss-cli -D
格式很多,以
postcss.config.js
为例
npm i postcss-preset-env -D # 安装预设
// postcss.config.js
const postcssPresetEnv = require('postcss-preset-env')
module.exports = {
plugins: [
postcssPresetEnv()
]
}
直接在css.postcss
中进行配置,该属性直接配置的就是postcss配置,和postcss.config.js
一样
import { defineConfig } from 'vite'
const postcssPresetEnv = require('postcss-preset-env')
export default defineConfig({
css: {
postcss: {
plugins: [postcssPresetEnv()]
}
}
})
import img from './assets/img.png' // url
import imgUrl from './assets/img.png?url' // url
import imgRaw from './assets/img.png?raw' // buffer
console.log(img, imgUrl); // /src/assets/img.png
console.log(imgRaw); // 图片的 buffer
import { defineConfig } from "vite"
export default defineConfig({
resolve: {
alias: {
"@": "./src",
"@assets": "./src/assets"
},
},
})
alias别名最终做的事情就是做字符串替换
在7中讲的vite开发服务器如下:
const koa = require('koa');
const fs = require('fs');
const path = require('path');
const app = new koa();
// 导入vite.config.js配置
const viteConfig = require('./vite.config');
// utils方法:做路径替换的
const aliasResolve = require('./aliasResolver');
app.use(async (ctx) => {
if (ctx.request.url === '/') {
const htmlContent = await fs.promises.readFile(path.resolve(__dirname, 'index.html'));
ctx.response.body = htmlContent;
ctx.response.set('Content-Type', 'text/html');
}
if (ctx.request.url.endsWith('.js')) {
const JSContent = await fs.readFileSync(path.resolve(__dirname, '.', 'main.js'), 'utf-8');
// 直接进行 alias 的替换
const lastResult = aliasResolve(viteConfig.resolve.alias, JSContent);
ctx.response.body = lastResult;
ctx.response.set('Content-Type', 'application/javascript');
}
});
app.listen(3000, () => console.log('listening on port 3000'));
module.exports = function(aliasConf, JSContent) {
const entires = Object.entries(aliasConf);
let lastContent = JSContent;
entires.forEach(entire => {
const [alia, path] = entire;
// vite会做path路径的处理(这里直接写死src)
const srcIndex = path.indexOf('/src');
const realPath = path.slice(srcIndex, path.length);
// alias别名最终做的事情就是做字符串替换
lastContent = JSContent.replace(alia, realPath);
})
return lastContent;
}
import '@/test.js' // 会被替换成 import '/src/test.js'
console.log('main');
import { defineConfig } from "vite"
export default defineConfig({
base: "./", // 配置静态资源路径
build: {
rollupOptions: { // 配置rollup的一些构建策略
input: { // 输入配置
index: "index.js",
},
output: { // 输出配置
// hash:文件名和文件内容生成签名
entryFileNames: "[name].js", // 入口文件名
assetFileNames: "[hash]-[name].[ext]", // 资源文件名
},
},
assetsInlineLimit: 4096, // 默认是4kb,这里修改为0,不进行图片转base64,大于4kb的图片不转base64
outDir: "dist", // 输出目录名
assetsDir: "static", // 静态资源目录名,如果output设置了entryFileNames和assetFileNames,则不会生效
},
})
vite会在不同的生命周期中去调用不同的插件以达到不同的目的
vite的插件必须返回给vite一个配置对象
vite-aliases:可以帮我们自动生成别名:检测当前目录下的,包括src在内的所有文件夹,并帮助我们生成别名
npm i [email protected] -D
import { defineConfig } from "vite"
import { ViteAliases } from 'vite-aliases'
export default defineConfig({
plugins: [
ViteAliases()
],
})
手写vite-aliases其实就是在执行配置文件之前,去修改配置文件的resolve.alias
可以通过vite的config
钩子,去修改配置文件
config
:
(config: UserConfig, env: { mode: string, command: string }) => UserConfig | null | void
在解析 Vite 配置前调用。钩子接收原始用户配置(命令行选项指定的会与配置文件合并)和一个描述配置环境的变量,包含正在使用的 mode
和 command
。它可以返回一个将被深度合并到现有配置中的部分配置对象,或者直接改变配置(如果默认的合并不能达到预期的结果)。
文档:https://cn.vite.dev/guide/api-plugin.html#config
const path = require('path')
const fs = require('fs')
// 将文件和目录区分开
function diffDirAndFile(dirFilesArr = [], basePath = '') {
const result = {
dirs: [],
files: []
}
dirFilesArr.forEach((name) => {
const currentFileStat = fs.statSync(
path.resolve(__dirname, basePath + '/' + name)
)
if (currentFileStat.isDirectory()) {
result.dirs.push(name)
} else {
result.files.push(name)
}
})
return result
}
// 遍历目录,生成别名obj
function getTotalSrcDir() {
const result = fs.readdirSync(path.resolve(__dirname, '../src'))
const diffResult = diffDirAndFile(result, '../src')
const aliasResolveObj = {}
diffResult.dirs.forEach((dirName) => {
const key = `@${dirName}`
const absPath = path.resolve(__dirname, '../src', dirName)
aliasResolveObj[key] = absPath
})
return aliasResolveObj
}
module.exports = () => ({
config: (config, env) => {
// config:目前的配置对象
// env:mode: string(development/production), command: string(build/serve)
let aliasResolveObj = getTotalSrcDir()
// 追加配置
return {
resolve: {
alias: aliasResolveObj
}
}
}
})
作用:动态控制html内容,使用的是ejs语法
npm i vite-plugin-html -D
import { defineConfig } from "vite"
import { createHtmlPlugin } from 'vite-plugin-html'
export default defineConfig({
plugins: [
createHtmlPlugin({
inject: {
data: {
title: 'Vite + React'
}
}
})
],
})
<%= title %>
)DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %>title>
head>
<body>
<script type="module" src="./index.js">script>
body>
html>
通过transformIndexHtml
这个钩子来实现,作用是转换html的
IndexHtmlTransformHook | { order?: 'pre' | 'post', handler: 返回html内容 }
文档:https://cn.vite.dev/guide/api-plugin.html#transformindexhtml
module.exports = (options) => ({
// 写法1:
transformIndexHtml: (html, ctx) => {
return html.replace(/<%= title %>/g, options.inject.data.title);
},
// 写法2:
transformIndexHtml: {
order: 'pre', // 在构建 html 前执行
handler(html, ctx) {
return html.replace(/<%= title %>/g, options.inject.data.title);
}
}
})
import { defineConfig } from 'vite'
import CreateHtmlPlugin from './plugins/CreateHtmlPlugin'
export default defineConfig({
plugins: [
CreateHtmlPlugin({
inject: {
data: {
title: '首页'
}
}
})
]
})
用于模拟数据
npm i vite-plugin-mock mockjs -D
import { defineConfig } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig({
plugins: [
viteMockServe({
mockPath: './mock',
enable: true, // 是否启用 mock 功能
localEnabled: true // 是否开启开发环境
})
]
})
import mockJS from 'mockjs'
const userList = mockJS.mock({
// "字段名|个数"
'list|100': [{
name: '@cname', // 生成中文名
'id|+1': 1, // id自增
email: '@email',
age: '@integer(18, 30)',
address: '@city',
createtime: '@datetime'
}]
})
export default [
{
method: 'get',
url: '/api/users',
response: () => {
return {
code: 200,
data: userList
}
}
}
]
使用configureServer
这个钩子:是用于配置开发服务器的钩子
(server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>
文档:https://cn.vite.dev/guide/api-plugin.html#configureserver
只实现了
vite-plugin-mock
,其他的使用和上面21
一样
const fs = require('fs')
const path = require('path')
module.exports = (options) => {
return {
configureServer(server) {
const mockStat = fs.statSync('mock')
const isDirectory = mockStat.isDirectory()
let mockResult = []
if (isDirectory) {
mockResult = require(path.resolve(process.cwd(), 'mock/index.js'))
}
// 服务器相关配置
server.middlewares.use((req, res, next) => {
const mockItem = mockResult.find(item => item.url === req.url)
if (mockItem) {
const responseData = mockItem.response(req)
res.end(JSON.stringify(responseData))
} else {
next()
}
})
}
}
}
vite-aliases
中)vite-plugin-mock
中)configureServer
相同,但用于预览服务器index.html
的专用钩子。钩子接收当前的 HTML 字符串和转换上下文(在自定义插件vite-plugin-html
中)import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
{
// 在解析 Vite 配置前调用
config(config) {},
// 当整个配置文件被解析并合后调用
configResolved(config) {},
// 用于配置开发服务器的钩子
configureServer(server) {},
// 与 configureServer 相同,但用于预览服务器
configurePreviewServer(server) {},
// 转换 index.html 的专用钩子。钩子接收当前的 HTML 字符串和转换上下文
transformIndexHtml(html) {},
// 自定义热更新,覆盖vite的热更新
handleHotUpdate({ server, modules, timestamp }) {},
}
]
})
文档:https://cn.vite.dev/guide/api-plugin.html#universal-hooks
fullRollupOptions
功能一样import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: {
output: {}
}
},
plugins: [
{
// 配置 Rollup 打包选项(和上面的 build.rollupOptions 中的配置一样)
options(rollupOptions) {},
// 和configResolved一样
buildStart(fullRollupOptions) {}
}
]
})
vite-plugin-checker
,ts错误,dev代码就会报错在vite.config.js
中使用:
import { defineConfig } from 'vite'
import checker from 'vite-plugin-checker'
export default defineConfig({
plugins: [
checker({
typescript: true
})
]
})
"build": "tsc --noEmit && vite build"
在ts的声明文件中:
// 三斜线指令:会引入 vite/client
///
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
// 更多环境变量...
}
性能优化包括:
npm run dev
的一瞬间到呈现结果要占用多少时长来源于浏览器缓存策略,当文件的文件名没有发生变化,就不会从新去请求,所以打包后的文件名一般是hash名,对于第三方库的包,是不需要在每次打包都重新加载的,就可以将这些包分离出去。
分包就是把一些不会常规更新的文件,进行单独打包处理
使用rollupOptions.output.manualChunks(需要的是一个对象)
进行代码拆分
import { defineConfig } from "vite"
export default defineConfig({
build: {
minify: false, // 关闭压缩
rollupOptions: {
output: {
// manualChunks: {
// lodash: ['lodash'] // 输出的文件名:单独打包的包
// },
// 拆分代码
manualChunks: (id) => {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
})
gzip压缩:将所有的静态文件进行压缩,已达到减少体积的目的。但是浏览器也是需要解压时间的,如果不是太多的文件,不要使用gzip压缩
npm i vite-plugin-compression -D
import { defineConfig } from "vite"
import compression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
compression()
]
})
dist/index.html 0.35 kB │ gzip: 0.25 kB
dist/assets/index-BRmDW9Pn.js 1.35 kB │ gzip: 0.58 kB
dist/assets/vendor-DH-rnSg2.js 224.45 kB │ gzip: 42.26 kB
✓ built in 338ms
✨ [vite-plugin-compression]:algorithm=gzip - compressed file successfully:
dist//Users/xxxxxxx/vite/vite-build/assets/index-BRmDW9Pn.js.gz 1.31kb / gzip: 0.56kb
dist//Users/xxxxxxx/vite/vite-build/assets/vendor-DH-rnSg2.js.gz 219.37kb / gzip: 40.91kb
需要后端设置响应头:content encoding --> gzip
在路由懒加载时用的比较多,例如:webpack中
component: () => import(/* webpackChunkName: 'Home' */'@/views/Home.vue')
cdn:内容分发网络,将我们依赖的第三方模块全部写成cdn的形式
使用:vite-plugin-cdn-import
import { defineConfig } from "vite"
import compression from 'vite-plugin-compression'
import importCDNPlugin from 'vite-plugin-cdn-import'
export default defineConfig({
plugins: [
importCDNPlugin({
modules: [
{
name: 'lodash',
var: '_', // lodash全局导出的符号
path: 'https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js'
}
]
})
]
})
以esm标准为目标的构架功能(默认只支持esm,其他模块化的需要使用插件才行),最熟知的功能:tree shaking
"preview": "rollup -i index.js", // 输出到控制台
"build": "rollup -i index.js --file dist/bundle.js", // 输出到dist目录
"build:umd": "rollup -i index.js --file dist/bundle.umd.js --format umd", // 打包成umd格式
"build:iife": "rollup -i index.js --file dist/bundle.iife.js --format iife", // 打包成iife(自执行)格式
"build:config": "rollup --config rollup.config.js" // 以配置文件进行打包
-c, --config <filename> 以配置文件进行打包
-d, --dir <dirname> 输出到某个目录
-f, --format <format> 输出的文件类型(amd, cjs, es, iife, umd, system)2
-i, --input <filename> 输入文件
-o, --file <output> 输出文件
-n, --name <name> 在umd中,全局变量名
/** @type {import('rollup').RollupOptions} */
export default {
input: 'index.js',
output: {
file: 'dist/bundle.esm.js',
format: 'es'
},
plugins: []
}
/** @type {import('rollup').RollupOptions} */
export default [
{
input: 'index.js',
output: {
file: 'dist/bundle.umd.js',
format: 'umd',
name: 'myLib' // 在umd中,全局变量名
}
},
{
input: 'index.js',
output: {
file: 'dist/bundle.esm.js',
format: 'es'
}
}
]
插件:
node_modules
目录中的模块,就像 Node.js 在运行时解析模块一样。// rollup.config.js
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import rosolve from '@rollup/plugin-node-resolve'
import { terser } from 'rollup-plugin-terser'
/** @type {import('rollup').RollupOptions} */
export default {
input: 'index.js',
// external: ['react'],
external: {
react: 'React'
},
output: {
file: 'dist/bundle.esm.js',
format: 'es',
// plugins: [terser()],
banner: '/* author: wifi */'
},
plugins: [rosolve(), commonjs(), json()] // rollup插件的执行顺序是按数组顺序执行的
}