当我们开始构建越来越大型的应用时,需要处理的 JavaScript 代码量也呈指数级增长。包含数千个模块的大型项目相当普遍。我们开始遇到性能瓶颈 —— 使用 JavaScript 开发的工具通常需要很长时间(甚至是几分钟!)才能启动开发服务器。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和幸福感。
Vite 旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持 ES 模块,且越来越多 JavaScript 工具使用编译型语言编写。
编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成 为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++、Delphi等.
当冷启动开发服务器时,基于打包器的方式启动必须优先抓取并构建你的整个应用,然后才能提供服务。(就是首次启动项目时会进行打包依赖,之后更新就不用重新获取依赖了)
Vite 通过在一开始将应用中的模块区分为 依赖 和 源码 两类,改进了开发服务器启动时间。
![image.png](https://img-blog.csdnimg.cn/img_convert/4c363ca817ab918d6f73921494b59f04.png#clientId=u79cf894e-3c0c-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=410&id=uadf43670&margin=[object Object]&name=image.png&originHeight=819&originWidth=1318&originalType=binary&ratio=1&rotation=0&showTitle=false&size=527066&status=done&style=none&taskId=u8c4650db-7a82-40e3-8b6c-7a324c7040f&title=&width=659)
缓慢的更新
基于打包器启动时,重建整个包的效率很低。原因显而易见:因为这样更新速度会随着应用体积增长而直线下降。(如webpack)
在 Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失活[1](大多数时候只是模块本身),使得无论应用大小如何,HMR 始终能保持快速更新。
Vite 同时利用 HTTP 头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据 304 Not Modified 进行协商缓存,而依赖模块请求则会通过 Cache-Control: max-age=31536000,immutable 进行强缓存,因此一旦被缓存它们将不需要再次请求。
为什么打包环境任然需要打包
尽管原生 ESM 现在得到了广泛支持,但由于嵌套导入会导致额外的网络往返,在生产环境中发布未打包的 ESM 仍然效率低下(即使使用 HTTP/2)。为了在生产环境中获得最佳的加载性能,最好还是将代码进行 tree-shaking、懒加载和 chunk 分割(以获得更好的缓存)。
兼容性注意
Vite 需要 Node.js 版本 大于等于 12.0.0版本。
//npm
npm init vite@latest
//yarn
yarn create vite
可以使用模板来创建项目:
# npm 6.x
npm init vite@latest my-vue-app --template vue
# npm 7+, 需要额外的双横线:
npm init vite@latest my-vue-app -- --template vue
# yarn
yarn create vite my-vue-app --template vue
目前支持的模板预设如下:
JavaScript | TypeScript |
---|---|
vanilla | vanilla-ts |
vue | vue-ts |
react | react-ts |
preact | preact-ts |
lit | lit-ts |
svelte | svelte-ts |
<template>
<img src="@/assets/logo.png" />
<img :src="logo" />
<Home />
</template>
<script setup lang="ts">
import Home from "views/home.vue";
//图片可以用ESM 来引用,用来当变量使用
import logo from "@/assets/logo.png"
</script>
import { defineConfig } from 'vite' // 帮手函数,这样不用 jsdoc 注解也可以获取类型提示
import vue from '@vitejs/plugin-vue' //识别.vue文件
import viteCompression from "vite-plugin-compression"; //gzip必备插件,开启gzip、br压缩
//path
const path = require('path');
/**
*
* 此时 TS 可能有这个错误提示:找不到模块“path”或其相应的类型声明。
* 解决方法:npm install @types/node --save-dev
*/
const resolve = (dir: string) => path.join(__dirname, dir)//__dirname 总是指向被执行 js 文件的绝对路径 EX:/d1/d2/myscript.js 文件中写了 __dirname, 它的值就是 /d1/d2
// https://vitejs.dev/config/
export default defineConfig({
//开发或生产环境服务的公共基础路径
base: './',
//作为静态资源服务的文件夹。并在构建期间复制到 outDir 的根目录,并且始终按原样提供或复制而无需进行转换。
publicDir: "public",
//用于加载 .env 文件的目录。
// envDir:"root",
//控制台输出的级别 info 、warn、error、silent
logLevel: "info",
// 设为false 可以避免 vite 清屏而错过在终端中打印某些关键信息
clearScreen: true,
//plugins配置需要使用的插件列表
plugins: [vue(), viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: "gzip",
ext: ".gz",
})],
// 路径相关规则
resolve: {
//配置别名
alias: {
'@': resolve('src'),// @表示当前的src目录路径
comps: resolve('src/components'),// comps表示当前的src目录路径下components
apis: resolve('src/apis'),// apis表示当前的src目录路径下apis
views: resolve('src/views'),
utils: resolve('src/utils'),
routes: resolve('src/routes'),
}
},
//本地运行配置,以及反向代理配置
// server: {
// host: "0.0.0.0",//指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
// port: 12138,//指定开发服务器端口
// strictPort: false, //设为true时端口被占用则直接退出,不会尝试下一个可用端口
// https: false,//是否启用 http 2
// open: true,//服务启动时自动在浏览器中打开应用
// cors: true,//为开发服务器配置 CORS , 默认启用并允许任何源
// force: true,//是否强制依赖预构建
// hmr: false,//禁用或配置 HMR 连接
// // 传递给 chockidar 的文件系统监视器选项
// watch: {
// ignored: ["!**/node_modules/your-package-name/**"]
// },
// // 反向代理配置
// proxy: {
// '/api': {
// target: "https://xxxx.com/",// 所要代理的目标地址
// changeOrigin: true,
// rewrite: (path) => path.replace("/^/api /", '') //重写地址
// }
// }
// },
//打包配置
build: {
//传递给 Terser 的更多 minify 选项。 生产环境去除 console debugger
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
// //浏览器兼容性 "esnext"|"modules"
// target: "modules",
// //指定输出路径
// outDir: "dist",
// //生成静态资源的存放路径
// assetsDir: "assets",
// //小于此阈值的导入或引用资源将内联为 base64 编码,以避免额外的 http 请求。设置为 0 可以完全禁用此项
// assetsInlineLimit: 4096,
// //启用/禁用 CSS 代码拆分
// cssCodeSplit: true,
// //构建后是否生成 source map 文件
// sourcemap: false,
// //自定义底层的 Rollup 打包配置
// rollupOptions: {
// },
// //@rollup/plugin-commonjs 插件的选项
// commonjsOptions: {
// },
// //构建的库
// lib: {
// },
// //当设置为 true,构建后将会生成 manifest.json 文件
// manifest: false,
// // 设置为 false 可以禁用最小化混淆,
// // 或是用来指定使用哪种混淆器
// // boolean | 'terser' | 'esbuild'
// minify: "terser", //terser 构建后文件体积更小
// //设置为 false 来禁用将构建后的文件写入磁盘
// write: true,
// //默认情况下,若 outDir 在 root 目录下,则 Vite 会在构建时清空该目录。
// emptyOutDir: true,
// //启用/禁用 brotli 压缩大小报告
// brotliSize: true,
// //chunk 大小警告的限制
// chunkSizeWarningLimit: 500
},
})
/***
* 注意事项:
*/
// ● 假设不配置 base 时,打包之后,访问时出现白屏。
// ● alias 不配置的时候,每次引入文件需要找根目录,比较麻烦。