Vite 依赖预构建
什么是依赖预构建?
vite会找到对应的依赖, 然后调用 esbuild (对js语法进行处理的一个库),
将其他规范的代码(比如 commonJS、UMD)转换成esmodule 规范
, 然后放到当前目录下的node_modules/.vite/deps, 同时对esmodule规范的各个模块进行统一集成
为什么要预构建?
Vite
的开发服务器将所有代码视为原生ES
模块。而不同的第三方包会有不同的导出格式(这个是vite没法约束人家的事情),所以预构建的目的就是将依赖转为 ES 模块
,统一模块规范。- 对
路径
的处理上可以直接使用.vite/deps
, 方便路径重写。 - 优化
http多包传输
的性能问题。- 因为原生 esmodule 规范
不敢支持
node_modules。原因之前也说了,对于每一个 ES 模块来说,浏览器会去请求这个模块。对于像lodash-es
这样有超过 600 个内置模块的 ES 模块来说,那我浏览器是不是要去请求 600 次? 这样会造成网络拥塞,导致页面的加载速度相当慢。 - 而预构建后,无论他有多少的额外 export 和 import 的 ES 模块, vite 都会尽可能的将他们进行
集成
,最后只生成一个或者几个模块。这才能够说明可以用来优化http多包传输
的性能问题
- 因为原生 esmodule 规范
Vite 依赖预构建的相关配置
不要预构建
首先,创建 vite.config.js
,该文件等价于 webpack.config.js
然后再该文件里面配置如下内容:
js
export default {
optimizeDeps:{
exclude:["lodash-es"] // 当遇到lodash-es的时候 不进行预构建
}
}
它的意思是,遇到 lodash-es
这个模块时,不进行预构建
。此时,我们运行 vite 开发环境,打开网络请求,会发现它对 lodash-es 的 600多个 ES 模块
发送了网络请求
语法提示处理
defineConfig
在 vscode 里面我们可以通过 defineConfig
这个函数去配置我们的 vite,这个时候配置时会有语法提示。
js
import { defineConfig } from "vite";
export default defineConfig({
//...配置
})
为什么这样就会有语法提示了?因为有 TS 类型判断嘛(返回的是个 UserConfig
类型的配置对象)
类型注解
/** @type import('vite').UserConfig*/
环境处理
在 defineConfig
中,我们可以去获取运行的命令 command
以及运行的环境
所以我们可以定义三个文件 vite.base.config.js
、vite.dev.config.js
、vite.prod.config.js
来配置不同环境
js
// vite.base.config.js
import { defineConfig } from "vite";
export default defineConfig({
optimizeDeps: {
exclude: ["lodash-es"], // 当遇到lodash-es的时候 不进行预构建
},
});
// vite.dev.config.js
import { defineConfig } from "vite";
export default defineConfig({
});
// vite.prod.config.js
import { defineConfig } from "vite";
export default defineConfig({
});
然后在 vite.config.js
里面引入这三个环境配置
js
import { defineConfig } from "vite"
import viteBaseConfig from "./vite.base.config"
import viteDevConfig from "./vite.dev.config"
import viteProdConfig from "./vite.prod.config"
const envResolver = {
"build": () => Object.assign({}, viteBaseConfig, viteProdConfig),
"serve": () => Object.assign({}, viteDevConfig, viteDevConfig)
}
export default defineConfig(({command, mode})=>{
return envResolver([command])();
})
这样,我们就可以区分环境进行对应的配置了
环境变量
vite 内置了 dotenv
这个第三方库来处理环境变量
dotenv
会自动读取 .env
文件, 并解析这个文件中的对应环境变量,并将其注入到 process
对象下(但是 vite 考虑到和其他配置的一些冲突问题, 他不会直接注入到process对象下)
loadEnv
vite
给我们提供了一个 loadEnv
方法来获取环境变量
js
// vite.config.js
const envResolver = {
"build": () => Object.assign({}, viteBaseConfig, viteProdConfig),
"serve": () => Object.assign({}, viteBaseConfig, viteDevConfig)
}
export default defineConfig(({command, mode})=>{
// mode 为执行指令环境
// npm run serve => mode:development
// npm run build => mode:production
// process.cwd()方法: 返回当前 node 进程的工作目录
const env = loadEnv(mode, process.cwd(), '')
console.log('env', env)
return envResolver[command]();
})
vite 不同环境变量
.env
: 所有环境都需要用到的环境变量
.env.development
: 开发环境需要用到的环境变量(默认情况下vite将我们的开发环境取名为development)
.env.production
: 生产环境需要用到的环境变量(默认情况下vite将我们的生产环境取名为production)
js
export default defineConfig(({command, mode}) => {
const env = loadEnv(mode, process.cwd(), '')
console.log('env==========env', env)
return envResolver[command]();
// mode 为执行指令环境
// npm run serve => mode:development
// npm run build => mode:production
})
当我们执行脚本命令 npm run dev
的时候,此时 mode
是 development
,然后我们的 loadEnv
会接受 mode
作为参数,调用 loadenv
,接下来它会去做下面的事情:
-
直接找到
.env
文件,并解析其中的环境变量并放进一个对象里 -
会将传进来的
mode
值进行拼接(此时是development
):.env.development
,并根据我们提供的目录去取对应的配置文件并进行解析,并放进一个对象 -
相当于:
jsconst EnvConfig1 = 读取 .env1 相关配置 const EnvConfig2 = 读取 .env2 相关配置 const EnvConfig3 = { ...EnvConfig1, ...EnvConfig2 }
import.meta.env
import.meta.env
这个是官方提供的一个变量对象,他能够有效的读取到当前环境变量
此时我们的 .env.development
文件中的额外配置是:
js
ENV = 112
BASE_URL = 'https:/lxq/api'
然后我们在 index.js
中打印一下看看:
我们发现,上面打印的是默认的环境变量对象,其中并没有我们设置的 ENV、BASE_URL
这是因为 vite 做了一个拦截
, 他为了防止我们将隐私性的变量直接送进 import.meta.env
中, 所以他做了一层拦截, 如果你的环境变量不是以 VITE
开头的, 他就不会帮你注入到客户端中去。
更改 .env.development
的变量前缀
js
VITE_ENV = 112
VITE_BASE_URL = 'https:/lxq/api'
此时控制台打印如下:
如果我们想要更改这个 VITE
前缀, 可以去使用 envPrefix
配置
js
import { defineConfig } from "vite";
export default defineConfig({
envPrefix: 'LXQ'
});
修改变量前缀
js
LXQ_ENV = 112
LXQ_BASE_URL = 'https:/lxq/api'
控制台打印: