适合自己的构建方案远大于最好和更好的方案,
这可能是你在全网看到的最详细vite在开发环境构建策略教程了;
配置策略
配置路径别名
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {join} from "path"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": join(__dirname, "/src")
}
}
})
开发环境解决跨域
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {join} from "path"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": join(__dirname, "/src")
}
},
server: {
proxy: {
// 代理所有 /api请求
"/api": {
target: "目标origin",
// 改变请求的origin为target的值
changeOrigin: true,
}
}
}
})
配置环境变量
企业级项目,都会区分很多环境,供我们测试试用。不能让我们的测试数据去污染线上的数据。所以vite也提供了我们环境配置文件的方式,让我们很轻松的去通过一些环境选择对应的接口地址等等。
.env.[mode]的格式可以在不同模加载加载不同的内容。
环境加载优先级
一份用于指定模式的文件(例如 .env.production)会比通用形式的优先级更高(例如 .env)。
另外,Vite 执行时已经存在的环境变量有最高的优先级,不会被 .env 类文件覆盖。例如当运行 VITE_SOME_KEY=123 vite build 的时候。
.env 类文件会在 Vite 启动一开始时被加载,而改动会在重启服务器后生效。
我们可以在源码中通过import.meta.env.*的方式获取以VITE_开头的已加载的环境变量。
// .env.development
VITE_BASE_API = "/api"
// package.json
"scripts": {
"dev": "VITE_BASE_API=/oop vite",
}
执行yarn dev
后,我们可以发现,import.meta.env.VITE_BASE_API
是命令行中指定的参数。
通用组件自动注册
vue的Globvite的Glob 导入功能:该功能可以帮助我们在文件系统中导入多个模块
const modules = import.meta.glob('./dir/*.js')
// 以上将会被转译为下面的样子:
const modules = {
'./dir/foo.js': () => import('./dir/foo.js'),
'./dir/bar.js': () => import('./dir/bar.js')
}
然后再通过vue提供的注册异步组件的方式进行引入,vue的defineAsyncComponent方法:该方法可以创建一个按需加载的异步组件 基于以上两个方法,实现组件自动注册。
// import SvgIcon from './svg-icon/index.vue'
// import HmPopup from './popup/index.vue'
import { defineAsyncComponent } from 'vue'
// const components = [SvgIcon, HmPopup]
export default {
install(app) {
// components.forEach((element) => {
// app.component(element.name, element)
// })
// 获取当前路径下所有文件夹下的index.vue
const components = import.meta.glob('./*/index.vue')
// 遍历获取到的组件模块
for (let [key, component] of Object.entries(components)) {
const componentName = 'hm-' + key.replace('./', '').split('/')[0]
// 通过 defineAsyncComponent 异步导入指定路径下的组件
app.component(componentName, defineAsyncComponent(component))
}
}
}
其实如果组件都提供了name属性,我们可以直接手动引入各组件模块,然后实现半自动注册。组件提供name
的好处是,在vue-devtools
中调试时方便查找各个组件。
在vue官网中,在 3.2.34 或以上的版本中,使用 <script setup>
的单文件组件会自动根据文件名生成对应的 name 选项,即使是在配合 <KeepAlive>
使用时也无需再手动声明。 但是对于我们文件名都为index.vue
的开发者来说,就没办法了。
去除debugger、console
// vite.config.js
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue()
],
build: {
target: 'es2020',
minify: 'terser',
terserOptions: {
compress: {
// 生产环境时移除console
drop_console: true,
drop_debugger: true
}
}
}
})
使用svg图标作为icon图标
首先我们需要封装一个通用的svg组件,来使用svg图标。
<template>
<svg aria-hidden="true">
<use :xlink:href="symbolId" :fill="color" :fillClass="fillClass" />
</svg>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
// 图标名称
name: {
type: String,
required: true
},
// 颜色
color: {
type: String
},
// 类名
fillClass: {
type: String
}
})
// 生成图标唯一id #icon-xxx
const symbolId = computed(() => `#icon-${props.name}`)
</script>
然后全局注册该svg通用组件,这里我们使用插件的方式
import SvgIcon from "./svg-icon/index.vue"
export default {
install(app) {
app.component("SvgIcon", SvgIcon)
}
}
main.js中直接通过use注册后,即可使用。
<svg-icon name="back"></svg-icon>
但是这样项目中并不能知道svg图标的路径,我们需要使用vite-plugin-svg-icons
插件来指定查找路径。
在vite.config.js中配置svg相关内容
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import {join} from "path"
import {createSvgIconsPlugin} from "vite-plugin-svg-icons"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [join(__dirname, "/src/assets/icons")],
// 指定symbolId格式,就是svg.use使用的href
symbolId: "icon-[name]"
})
],
})
在main.js中导入并注册svg-icons
,他会把指定文件夹下的svg
图片都注册在首页。
// 注册 svg-icons
import "virtual:svg-icons-register"
base公共基础路径
开发或生产环境服务的公共基础路径。可以是以下几种值:
- 绝对 URL 路径,例如 /boot/
- 完整的 URL,例如 https://boot.com/
- 空字符串或 ./(用于嵌入形式的开发)
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path';
export default defineConfig({
base: './' // 开发或生产环境服务的公共基础路径
})
省略的扩展名
导入时想要省略的扩展名列表。默认为['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
。
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path';
export default defineConfig({
resolve: {
extensions: ['.js', '.ts', '.jsx', '.tsx', '.json'],
}
})
注意:不建议忽略自定义导入类型的扩展名(如:.vue),因为他会影响 IDE 和类型的支持。
指定服务器监听地址
指定服务器监听的的IP地址,默认值为localhost,只监听本地的127.0.0.1.当我们需要开发移动端项目时,需要在手机浏览器上访问当前项目,这个时候就需要将host的值设置为true或0.0.0.0,这样服务器就好监听所有地址,包括局域网和公网地址。
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path';
export default defineConfig({
server: {
host: true // 监听所有地址
}
})
当手机和电脑处于同一网络环境下,我们就可以通过下面的那个地址进行访问了。
处理css
PostCSS
是用来处理css的,可以通过添加各种插件来处理css。像浏览器样式兼容问题、浏览器适配问题等等,都可以通过使用PostCSS来解决。Vite 对PostCSS 有良好的支持,我们只需要安装相应的插件即可。如移动端适配可使用postcss-px-to-viewport
对不同设备进行布局适配。
npm install postcss-px-to-viewport -D
// vite.config.ts
import { defineConfig } from 'vite'
import postcssPxToViewport from 'postcss-px-to-viewport'
import { resolve } from 'path';
export default defineConfig({
css: {
postcss: {
plugins: {
// viewport 布局适配
postcssPxToViewport({
viewportWidth: 375
})
}
}
}
})
这样我们书写的 px 单位就会转为 vw 或 vh,很轻松就解决了手机不同设备的适配问题。
打包文件输出目录
指定打包文件的输出目录。默认为dist
,当dist
被占用或公司有统一的命名规范时,可以进行设置调整。
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path';
export default defineConfig({
build: {
outDir: 'build' // 打包文件的输出目录
}
})
静态文件存放目录
指定静态文件的存放目录。默认为 assets, 可根据需要自行调整。
// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path';
export default defineConfig({
build: {
assetsDir: 'static' // 静态文件的存放目录
}
})
优化策略
Bundle 分析
借助插件 rollup-plugin-visualizer,来进行 bundle 分析
pnpm i rollup-plugin-visualizer -D
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [vue(), visualizer({
emitFile: false,
file: "stats.html", //分析图生成的文件名
open:true //如果存在本地服务端口,将在打包后自动展示
})],
})
打包之后会在项目根目录生成 stats.html 文件打开
图片压缩
node version: >= 12.0.0
vite version: >=2.0.0
yarn add vite-plugin-imagemin -D
import viteImagemin from "vite-plugin-imagemin"
plugins: [vue(), viteImagemin()]
gzip 压缩
当前端资源过大时,服务器请求资源会比较慢。前端可以将资源通过Gzip压缩使文件体积减少大概60%左右,压缩后的文件,通过后端简单处理,浏览器可以将其正常解析出来。
如果浏览器的请求头中包含content-encoding: gzip
,即证明浏览器支持该属性。
npm i vite-plugin-compression -D
修改 vite.config.js 配置
import { defineConfig } from 'vite
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins:[
viteCompression(
{
algorithm: 'gzip',
threshold: 10240,
verbose: false,
deleteOriginFile: true
}
)
]
})
打包后就会生成 gzip 文件了,但是服务端 nginx 还需要配置一下才能生效
http {
gzip_static on;
gzip_proxied any;
}
配置项
可配置项名称 | 数据类型 | 默认值 | 释义 |
---|---|---|---|
verbose | boolean | true | 是否在控制台中输出压缩结果 |
filter | RegExp or (file: string) => boolean | /.(js | mjs |
disable | boolean | false | 是否禁用 |
threshold | number | 1025 | 如果体积大于阈值,则进行压缩,单位为b |
algorithm | string | gzip | 压缩算法,可选[‘gzip’,‘brotliCompress’,‘deflate’,‘deflateRaw’] |
ext | string | .gz | 生成的压缩包的后缀 |
compressionOptions | object | - | 对应压缩算法的参数 |
deleteOriginFile | boolean | - | 压缩后是否删除源文件 |
分包策略
默认情况下,浏览器重复请求相同名称的静态资源时,会直接使用缓存的资源。利用这个机制我们可以将不会经常更新的代码单独打包成一个 JS 文件,这样就可以减少 HTTP 请求,同时降低服务器压力。以 lodash 为例:
npm i lodash
安装 lodash ,然后在 main.js 中写入以下代码:
// src/main.js
import { cloneDeep } from 'lodash'
const obj = cloneDeep({})
打包结果:
项目代码和依赖模块打包成了一个 JS 文件。接着我们来配置分包,修改底层的 Rollup 配置:
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: id => {
// 将 node_modules 中的代码单独打包成一个 JS 文件
if(id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
})
打包结果如下:
可以看到依赖模块已经单独生成一个JS
文件了。这样我们即使修改了main.js
中的代码重新打包,依赖文件vendor.528a7280.js
也不会发生变化的,对于这个文件,浏览器也不会再次发起请求。如果依赖模块很多的话,性能是不是有很大的提升呢?
cdn 加速
内容分发网络(Content Delivery Network,简称 CDN)就是让用户从最近的服务器请求资源,提升网络请求的响应速度。通常我们请求依赖模块使用 CDN ,而请求项目代码依然使用自己的服务器。还是以 lodash 为例:
// src/main.js
import _ from 'lodash'
const obj = _.cloneDeep({})
使用 CDN 也比较简单,一个插件就可以搞定:
npm i vite-plugin-cdn-import -D
// vite.config.js
import { defineConfig } from 'vite'
import viteCDNPlugin from 'vite-plugin-cdn-import'
export default defineConfig({
plugins: [
viteCDNPlugin({
// 需要 CDN 加速的模块
modules: [
{
name: 'lodash',
var: '_',
path: `https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js`
}
]
})
]
})
构建成功后,Vite 会自动帮我们将 cdn 资源通过 script 标签插入到 html 中:
这样请求 lodash 资源就会产生加速 buff ,而且项目体积也会大大减小!
共享公共块
manualChunks 是 rollup 提供的一个配置项,也是最最最基础的优化配置项。
它可以将一些模块作为共享公共块单独打包,这样可以减少重复代码,使得打包出来的构建产物更小。
我们可以将 vue 和 element-ui 等模块抽离出去作为共享公共块,具体配置如下:
vue.config.js
// ...
defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vue: ['vue'],
echarts: ['echarts'],
'element-ui': ['element-ui'],
},
},
},
},
});
按需引入Echarts
echarts 的按需引入方式与其版本有关,我们这里使用的是 5.x 版本,参考官网的引入方式可修改为如下所示:
import * as echarts from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
// 这里我们只引入了折线图、柱状图、饼图,如果你需要其他的图表,可以自行引入
import { LineChart, BarChart, PieChart } from 'echarts/charts';
// 同理,如果你需要其他的组件,也应当自行引入
import { TooltipComponent, TitleComponent, GridComponent, LegendComponent } from 'echarts/components';
echarts.use([
LineChart,
BarChart,
PieChart,
TooltipComponent,
CanvasRenderer,
TitleComponent,
GridComponent,
LegendComponent,
]);
// 最终我们导出的是一个 echarts 的实例,这样我们就可以在项目中使用了
export default echarts;
后续会持续更新。。。。。。
评论区