vite 预加载
路径补全
在处理import _ from "lodash这种非绝对路径和相对路径的引用时,会触发路径补全:import _ from "/node_modules/.vite/deps/lodash,会补全类似 /node_modules/.vite/deps,以实际情况为准
找寻依赖的过程是自当前目录依次向上查找的过程,直到寻到根目录或者搜寻到对应依赖为止/user/node_modules/lodash
开发:yarn dev ---> 开发(每次依赖预构建所重新构建的相对路径都是正确的) 生产:vite会全权交给一个叫做 rollup 的库去完成生产环境
依赖预构建
首先 vite 会找到对应的依赖,然后调用 esbuild (对js语法进行处理的一个库),将其他规范的代码转换成 esmodule 规范,然后放到当前目录下的 node modules/.vite/deps,同时对 esmodule 规范的各个模块进行统一集成
以 lodash-es 为例:
export { default as after } from "./after.js";
// 等价
import after1 from "./after.js";
export const after = after1;
将直接引用改成函数形式
在 vite.config.js 文件做如下配置,取消 esmodule 转换
export default {
optimizeDeps: {
exclude: ["lodash-es"]
}
}
解决了3个问题:
- 不同的第三方包会有不同的导出格式(这个是 vite 没法约束人家的事情)
- 对路径的处理上可以直接使用 .vite/deps,方便路径重写
- 网络多包传输的性能问题(也是原生esmoduLe规范不敢支持node modules的原因之一),有了依赖预构建以后无论他有多少的额外exoort 和import,vite 尽可能的集成最后只生成一个或者几个模块
path.resolve 记录
函数作用:兼容各种文件路径拼接:./,../,\a\b等
- __dirname: 该文件的根路径
- process.cwd():node 运行根路径
插件
钩子函数
config
解析 Vite 配置前调用,接收原始用户配置和一个描述配置环境的变量
transformIndexHtml
转换 index.html 的专用钩子。最后修改 index.html文件机会,钩子接收当前的 HTML 字符串和转换上下文
configureServer
配置开发服务器的钩子,可以拦截请求,做 mock 返回
常用插件
vite-aliases
使用了 config 钩子,插件作用:检测 src 目录下的所有文件夹,并帮助我们去生成别名
// vite.config.js 版本差异注意导入方式
import { ViteAliases } from "./node_modules/vite-aliases" // 版本 0.11.7
import { ViteAliases } from "vite-aliases" // 版本 0.9.2
实现代码
const fs = require('fs');
const path = require('path');
function diffDirAndFile (dirFilesArr = [], basePath = "") {
const result = {
dirs: [],
files: []
}
dirFilesArr.forEach(name => {
const currentFileStat = fs.statSync(path.resolve(__dirname, basePath + '/' + name))
// console.log('file stat=', name, currentFileStat.isDirectory())
const isDir = currentFileStat.isDirectory()
if (isDir) {
result.dirs.push(name)
} else {
result.files.push(name)
}
})
return result
}
function getTotalSrcDir (keyName) {
const result = fs.readdirSync(path.resolve(__dirname, '../src'));
const diffResult = diffDirAndFile(result, "../src");
// console.log(diffResult)
const resolveAliasesObj = {}
diffResult.dirs.forEach(dirName => {
const key = keyName + dirName
const absPath = path.resolve(__dirname, "../src" + "/" + dirName)
resolveAliasesObj[key] = absPath
})
return resolveAliasesObj
}
module.exports = ({
keyName = '@'
} = {}) => {
return {
config(config, env) {
// console.log('config=', config);
// console.log('env=', env);
const resolveAliasesObj = getTotalSrcDir(keyName)
// console.log('resolveAliasesObj=', resolveAliasesObj)
return {
resolve: {
alias: resolveAliasesObj
}
}
}
}
}
vite-plugin-html
使用了transformIndexHtml 钩子,插件作用:转换 index.html 文件
实现代码
module.exports = (options) => {
// console.log(options)
return {
name: 'html-transform',
transformIndexHtml(html) {
// console.log('transformIndexHtml', html);
return html.replace(/<%= title %>/g, options.inject.data.title)
},
}
}
VitePluginMock
使用了 configureServer 钩子,插件作用:配置 mock
实现代码
import path from 'path';
const fs = require('fs');
export default (options) => {
return {
configureServer (server) {
// console.log(options)
const mockStat = fs.statSync('mock')
const isDirectory = mockStat.isDirectory()
let mockResult = []
if (isDirectory) {
mockResult = require(path.resolve(process.cwd(), 'mock/index.js'))
// console.log('mockResult',mockResult)
}
server.middlewares.use((req, res, next) => {
// console.log('req', req.url)
const matchItem = mockResult.find(mockDescriptor => mockDescriptor.url === req.url)
if (matchItem) {
const responseData = matchItem.response(req)
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(responseData))
} else {
next()
}
})
}
}
}
构建优化
分包策略
将 node_modules 或修改不多的文件单独打包
// vite-config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: (id) => {
console.log('id: ', id);
if (id.includes('node_modules')) {
return 'vendor';
}
}
}
}
},
})
gzip 压缩
插件:vite-plugin-compression2,vite-plugin-compression2(不维护)
cdn 加速
插件:vite-plugin-cdn-import