【大厂企业级项目架构】之vite基础配置与多环境区分
这篇文章开始正式进入正题,接下来的内容都是会对我们项目最终的构建结果产生影响的。本篇先讲解vite的基础配置以及如何区分环境构建和开发。
为什么用vite
毫无疑问,vite
是当下最热门和最高效的前端构建工具之一。
从开发角度来讲,相较于传统老大哥webpack
,vite
大大地提高了开发体验和效率。不管是冷启动还是热更新,vite
都比webpack
快上不少。因为webpack
必须对整个工程进行构建后才能启动,而vite
借助浏览器原生支持的ESM
,使得源码在真正被使用时才做处理。而对于项目依赖,vite
使用esbuild
进行与构建,同样比js编写的打包器快上很多。
而从生产的角度来讲,vite
使用rollup
进行生产的构建打包,同样可以像webpack
一样配合babel
等工具使用,对于构建出来的生产包质量是可以信赖的。
当然webpack
依然是最流行的构建工具,生态完善,有各种各样的插件、loader,对于生产的构建仍然还是比vite
有优势的,毕竟生产环境我们要求稳,确保质量。所以有很多人也会用vite
做开发构建,用webpack
做生产打包
最后,我们作为一个新项目,没有什么负担和迁移成本,而且只要测试做的足够充分,同样可以保证线上的质量,所以大胆上vite
吧。
开始配置
我不会从头到尾介绍一遍vite是如何使用的,这些都可以在vite官网上自行查阅。也不会一开始就把vite配置的很完整,因为项目刚开始,后面可能会遇到各种业务场景,会根据需要做相应的调整和配置。这里只做较为通用和基础的配置。
通过脚手架生成的vite配置只有以下短短几行,虽然本身vite已经内置支持了很多特性,可以开箱即用,但是还不足以应对后续日益复杂的项目,我们需要增加一些基础配置。
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
});
多环境区分的必要性
通常我们一个项目版本的完整周期,至少都需要经过开发、测试、发布上线
这几个阶段。开发阶段我们在自己的本地环境进行开发调试,测试阶段就会发布到测试环境进行各种测试,到最后测试完成则正式发布到生产环境,当然,再完整点的还会有预发布环境等。
因此,环境区分是很有必要的,举几个例子:
- 测试环境和生产环境的域名和接口路径不一样
- 测试环境我们可能需要vConsole定位问题,生产环境则不能把vConsole打到发布包里
- 测试环境的图片我们发到CDN上,但是生产环境我们可能会发到专用的图片存储服务,所以这里的路径也要区分
- ….
注入环境变量
区分环境的起点是什么呢?通常我们是通过命令参数去注入环境,比如说
# 测试环境 sit这个名字根据你自己的叫法定义即可
vite build --mode sit
# 生产环境
vite build --mode prod
此时vite就可以根据这个环境是sit
还是prod
去读取相应的配置文件了。
vite环境模式
vite
使用dotenv
来从我们的项目目录下读取相应的配置文件,从而获取额外的环境变量。什么意思呢?就是我们需要在项目根目录下新建以下几个.env
配置文件
.env # 所有情况下都会加载
.env.sit # 只在 --mode sit的时候加载,对应测试环境的配置
.env.prod # 只在 --mode prod的时候加载,对应生产环境的配置
然后就可以在里面写我们的环境变量了,举例如下:
# .env.sit
# 静态资源部署路径
VITE_PUBLIC_PATH = /
# 测试环境使用vConsole
VITE_USE_VCONSOLE = true
# 测试环境域名
VITE_API_DOMAIN = https://yoururl.test.com
# 测试环境api前缀
VITE_API_PREFIX = /testApi
....
# .env.prod
# 静态资源部署路径
VITE_PUBLIC_PATH = /vueApp
# 生产环境不使用vConsole
VITE_USE_VCONSOLE = false
# 生产环境域名
VITE_API_DOMAIN = https://yoururl.com
# 生产环境api前缀
VITE_API_PREFIX = /api
....
注意,只有VITE_开头的变量才会暴露给经过vite构建处理的代码
经过上面的配置后,我们的代码在运行时就可以拿到注入的环境变量了,同时,在构建的时候我们也可以拿到这些环境变量,就可以根据环境做差异化处理了。比如在vite.config.ts
中,我们可以拿到环境变量,根据环境去做不同的配置。如下所示:
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
// 项目根路径
const root = process.cwd();
// 通过vite提供的工具方法去加载相应环境的配置
// 这里的mode其实就是我们 --mode prod的prod
const { VITE_PUBLIC_PATH } = loadEnv(mode, root);
return {
// 这里根据环境不同,设置不同的静态资源部署路径
base: VITE_PUBLIC_PATH,
};
});
假如我们在源码里也需要根据环境做差异化处理,则可以像下面一样使用
<script setup lang="ts">
import { ref } from 'vue';
defineProps<{ msg: string }>();
// 通过import.meta.env.XXX拿到环境变量
const apiUrl = ref(`${import.meta.env.VITE_API_DOMAIN}`);
if (import.meta.env.VITE_XXX) {
// 做差异化处理
}
</script>
同时,为了有良好的ts提示,我们在src目录下新增types
目录,然后新增global.d.ts
类型定义文件,内容如下:
interface ImportMetaEnv {
readonly VITE_PUBLIC_PATH: string;
readonly VITE_API_PATH: string;
// 更多环境变量...
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
此时我们就可以在编辑器里有只能提示了。
其他配置
上面做好了多环境区分之后,我们就可以来做一些基础配置了
首先我们需要支持jsx的写法,所以需要增加相应的插件@vitejs/plugin-vue-jsx
import { defineConfig, loadEnv } from 'vite';
// 默认生成的配置只支持模板语法
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
// 通过defineConfig可以给我们提供类型提示
export default defineConfig(({ mode }) => {
// 项目根路径
const root = process.cwd();
// 通过vite提供的工具方法去加载相应环境的配置
// 这里的mode其实就是我们 --mode prod的prod
const { VITE_PUBLIC_PATH } = loadEnv(mode, root);
return {
// 这里根据环境不同,设置不同的静态资源部署路径
base: VITE_PUBLIC_PATH,
// 增加jsx插件来支持jsx的写法
plugins: [vue(), vueJsx()]
};
});
路径别名
然后我们可以通过alias
配置一些路径别名,如下
return {
// 这里根据环境不同,设置不同的静态资源部署路径
base: VITE_PUBLIC_PATH,
// 增加jsx插件来支持jsx的写法
// 后面如果需要增加更多的插件,我们会单独抽离出一个方法来获取插件
plugins: [vue(), vueJsx()],
resolve: {
alias: [
// import xxx from '@/path' -> import xxx from 'src/path'
{
find: /@/,
replacement: resolvePath('src'),
},
// ...其他更多的路径别名可以在这里继续配
],
},
};
构建选项
继续配置构建选项,如下:
{
// ...
build: {
// 我们的构建产物需要兼容到es6
target: 'es2015',
// 假如要兼容安卓微信的webview
cssTarget: 'chrome61',
// 非生产环境下生成sourcemap
sourcemap: mode !== 'prod',
// 禁用gzip 压缩大小报告,因为压缩大型文件可能会很慢
reportCompressedSize: false,
// chunk大小超过1500kb是触发警告
chunkSizeWarningLimit: 1500,
},
}
less配置
本项目打算使用less
作为预处理器,本身vite
对sass|less
内置就支持了,其实我们什么都不用做就可以使用,后续如果需要修改主题等,再修改配置。
开发服务器配置
我们需要配置开发服务器来帮我们做请求代理,解决跨域问题
server: {
// 开启https
https: true,
// 监听所有ip地址
host: true,
// 端口默认是5173
port: 6666,
// 配置代理帮我们转发请求,解决跨域问题
proxy: {
// api/开头的请求将被转发到下面的target的地址
'api/': {
target: 'https://mock.com',
// 改变请求头的origin
changeOrigin: true,
// 支持代理websocket
ws: true,
// 路径重写 相当于把api/去掉
rewrite: (path) => path.replace(new RegExp(`^api/`), ''),
}
},
},
最终配置
import { defineConfig, loadEnv } from 'vite';
// 默认生成的配置只支持模板语法
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
// 通过defineConfig可以给我们提供类型提示
export default defineConfig(({ mode }) => {
// 项目根路径
const root = process.cwd();
// 通过vite提供的工具方法去加载相应环境的配置
// 这里的mode其实就是我们 --mode prod的prod
const { VITE_PUBLIC_PATH } = loadEnv(mode, root);
return {
// 这里根据环境不同,设置不同的静态资源部署路径
base: VITE_PUBLIC_PATH,
// 增加jsx插件来支持jsx的写法
plugins: [vue(), vueJsx()],
resolve: {
alias: [
// import xxx from '@/path' -> import xxx from 'src/path'
{
find: /@/,
replacement: resolvePath('src'),
},
// ...其他更多的路径别名可以在这里继续配
],
},
build: {
// 我们的构建产物需要兼容到es6
target: 'es2015',
// 假如要兼容安卓微信的webview
cssTarget: 'chrome61',
// 非生产环境下生成sourcemap
sourcemap: mode !== 'prod',
// 禁用gzip 压缩大小报告,因为压缩大型文件可能会很慢
reportCompressedSize: false,
// chunk大小超过1500kb是触发警告
chunkSizeWarningLimit: 1500,
},
server: {
// 开启https
https: true,
// 监听所有ip地址
host: true,
// 端口默认是5173
port: 6666,
// 配置代理帮我们转发请求,解决跨域问题
proxy: {
// api/开头的请求将被转发到下面的target的地址
'api/': {
target: 'https://mock.com',
// 改变请求头的origin
changeOrigin: true,
// 支持代理websocket
ws: true,
// 路径重写 相当于把api/去掉
rewrite: (path) => path.replace(new RegExp(`^api/`), ''),
}
},
},
};
});
总结
经过上面的配置,目前项目已经支持多环境区分以及vite的基础配置了。当然,后面项目开发过程中会遇到更多的业务场景,到时候会对配置做出相应的修改,并且后续会增加很多插件来支撑我们的项目开发,这些留到后续处理具体的场景再说。