# 学习进度
https://cn.vitejs.dev/guide/features.html#build-optimizations
# 介绍
vite有几个比较重要的概念:
# 预构建
使用esbuild执行预构建,速度非常快。在服务器已经启动之后,如果遇到一个新的依赖关系导入,而这个依赖关系还没有在缓存中,Vite 将重新运行依赖构建进程并重新加载页面。
# 为什么需要与构建?
- 兼容性:因为vite对待所有js文件都当作es模块处理,所以需要先将cjs和umd转换为
es module
- 性能:Vite 将有许多内部模块的 ESM 依赖关系转换为单个模块,以提高后续页面加载性能。例如:当我们执行
import { debounce } from 'lodash-es'
时,浏览器同时发出 600 多个 HTTP 请求!通过预构建lodash-es
成为一个模块,我们就只需要一个 HTTP 请求了!
# 缓存
# 文件缓存
Vite 会将预构建的依赖缓存到 node_modules/.vite
,以下有变动时会重新构建:
package.json
中的dependencies
列表- 包管理器的 lockfile,例如
package-lock.json
,yarn.lock
,或者pnpm-lock.yaml
- 可能在
vite.config.js
相关字段中配置过的
想重新构建可以在启动命令行后输入--force
,或者手动删除node_modules/.vite
# 浏览器缓存
解析后的依赖请求会以 HTTP 头 max-age=31536000,immutable
强缓存,以提高在开发时的页面重载性能。一旦被缓存,这些请求将永远不会再到达开发服务器
# 功能
# css
内置支持@import
内联和变基、PostCSS、 CSS Modules。支持CSS 预处理器,.scss
, .sass
, .less
, .styl
和 .stylus
文件都是内置支持的,需要手动安装相应依赖,例如:
npm install -D sass
# .less
npm install -D less
# .styl and .stylus
npm install -D stylus
# index.html
vite默认以当前目录为根目录作为服务启动,如果想切换位置,使用vite serve dist
修改根目录,注意dist前不能有/
# 静态资源
vite默认支持的资源加载类型为:https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L49
# 配置文件
# 环境变量
vite提供loadEnv插件加载环境变量,只有VITE_
开头的变量才会被暴露给客户端
# config
# resolve.dedupe
如果你在你的应用程序中有相同依赖的副本(比如 monorepos),请使用此选项强制 Vite 始终将列出的依赖项解析为同一副本(从项目根目录)。
# build.lib
目前lib不支持多入口模式,已有相关pr等待合并:https://github.com/vitejs/vite/pull/7047
# build.rollupOptions
# external
把导入包转成外部依赖
const { defineConfig } = require('vite')
module.exports = defineConfig({
build: {
rollupOptions: {
// 确保外部化处理那些你不想打包进库的依赖
external: ['vue'],
output: {
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
globals: {
vue: 'Vue'
}
}
}
}
})
# optimizeDeps.include
不在node_modules
中的包vite默认不会预构建,通过添加这个强制预构建,底层是使用@rollup/plugin-commonjs
这个插件实现的
# 插件
# vite-plugin-singlefile
内联js和css文件
# vite-plugin-imp
自动引入组件库样式文件
# vite-plugin-html
压缩html文件
# vite-plugin-inspect
检查文件在使用不同vite插件之后的变化
# 迁移指南
- 从webpack迁移到vite是一个很繁琐的事情,好在有
wp2vite
这个包自动帮我们实现这些步骤
迁移参考:
- https://cloud.tencent.com/developer/article/1819625
- vue-cli-plugin-vite (opens new window):vue-cli项目迁移到vite
# 最佳实践
- 最好不要使用
@vitejs/plugin-legacy
,打包后文件大小会翻倍。 - 为某些包跳过不必要的
pre-bundled
阶段,使用optimizeDeps.exclude
# 踩坑
- 第三方库如果未遵守严格模式,则在必须使用
type=module
的vite中会报错。 - 使用
vue-class-component
的项目中,如果使用了@Component
装饰属性。build时会报错,提示不认识@
符号。
# 问题
# vite运行dev报错:then it is likely the case that a known bug in npm v7 hascorrupted your package-lock.json file
这是esbuild
的bug,针对npm
版本大于7的解决办法:node node_modules/esbuild/install.js
问题链接:https://github.com/evanw/esbuild/issues/462
# 如何删除build后的hashname?
参考:https://github.com/vitejs/vite/issues/378#issuecomment-789366197
但是,资源assetFileNames无效,需要升级到vite@2.5.0-beta.1
或更高,链接:https://github.com/vitejs/vite/issues/4354#issuecomment-895231516
export default defineConfig({
plugins: [vue()],
build: {
rollupOptions: {
output: {
entryFileNames: `assets/[name].js`, // 作用于入口包装文件
chunkFileNames: `assets/[name].js`, // 作用于js文件
assetFileNames: `assets/[name].[ext]` // 作用于css、图片等静态资源
}
}
}
})
# 如何防止定义的web component组件被vue解析?
配置vite:
export default defineConfig({
plugins:[
vue({
template:{
compilerOptions:{
// vue将跳过my-vue-element解析
isCustomElement:(tag)=>tag === "my-vue-element"
}
}
})
]
})
# 语法转义?
默认vite只做语法转义,不包含任何polyfill。使用@vitejs/plugin-legacy (opens new window)或者polyfill.io (opens new window)
# rollup
# 特性
- v2.74开始支持删除函数中无用的默认参数
- 长期缓存(long-term cache)不如webpack,不支持contenthash,原因是修改a.123123.js文件,打包后变成a.abcdef.js文件,导致引用a.123123.js文件的b.js文件hash也会修改
# input
# 单入口
input:'main.js'
# 多入口
多入口写法为对象格式:
import path from "path";
import fs from "fs";
const inputObj = {};
// 读取该目录下所有文件
fs.readdirSync("./templates/").forEach((file) => {
if (path.extname(file) === ".html") {
inputObj[file.substring(0, file.length - 5)] = "templates/" + file;
}
});
// ======
input: inputObj
# output
# entryFileNames
修改入口包裹js文件的名称和位置
# chunkFileNames
修改打包后js文件的名称和位置
# assetFileNames
修改css、图片等资源打包后的名称和位置
# paths
允许外部引入写入import,比如
// app.js
import { selectAll } from 'd3';
selectAll('p').style('color', 'purple');
// ...
// rollup.config.js
export default {
input: 'app.js',
external: ['d3'],
output: {
file: 'bundle.js',
format: 'amd',
paths: {
d3: 'https://d3js.org/d3.v4.min'
}
}
};
// bundle.js
define(['https://d3js.org/d3.v4.min'], function (d3) {
d3.selectAll('p').style('color', 'purple');
// ...
});
# preferConst
使用const替换var
# treeshake
# moduleSideEffects
该模块是否有副作用,默认为true
# plugins
# rollup-plugin-copy
通过hook
可以更改copy
时机
copy({
targets: [
{ src: "dist/static/js/entry/*.js", dest: "static/js/entry" },
{ src: "dist/static/css/entry/*.css", dest: "static/css/entry" },
{ src: "dist/templates/*.html", dest: "templates" },
],
hook: "writeBundle",
}),
# rollup-plugin-visualizer
打包分析工具
# 问题
如何使用长期缓存,类似与webpack的
contenthash
?目前无法实现,参考:https://github.com/vitejs/vite/issues/6773和https://github.com/rollup/rollup/issues/4426
将在rollup3中实现该功能