大家好,我是小墨,射手座,三十多年从未打过架,斗地主逃跑率99% 。代码写得比字多,bug 修得比头发快 ,秉持“能跑就是好代码”的哲学 。日常和前端打交道,代码写得比注释多,希望和大家多多交流!🤝
大家好,我是小墨!最近好多小伙伴跟我吐槽Vite配置的问题,本期咱们就来一次深度解析,从源码层面彻底搞懂Vite配置的加载流程!再也不用为各种配置问题头疼啦!
先给大家上一张Vite配置加载流程脑图,方便大家理解整体流程:
你是否也遇到过这些“坑”?
1.格式之谜:项目里.js,.ts,cjs,esm配置都有,到底哪个生效?
2.环境变量之惑:.env文件明明配置了,但在vite.config.ts里却获取不到?
3.插件冲突之痛:自定义插件时而生效,时而不生效,让人摸不着头脑?
别急!接下来,小墨将带你抽丝剥茧,逐一击破这些难题!
核心问题:Vite是如何寻觅并加载配置文件的?
当我们敲下vite命令,Vite的配置解析之旅就正式开始了。这其中,loadConfigFromFile函数扮演着至关重要的角色。
如果命令行没有用--config参数指定配置文件,Vite会在项目根目录依次寻找:
找到第一个存在的,就认定是它了!
重头戏:不同文件,不同对待!
Vite加载配置文件,可不是简单的读取内容。它会根据文件类型(.js,.ts等)和模块规范(ESM, CJS),采用不同的策略。
核心:isFilePathESM函数
这个函数决定了配置文件是ESM还是CJS:
Esbuild
你可能万万没想到,Vite在加载配置文件时,就已经用上了Esbuild!通过bundleConfigFile函数,Vite会将配置文件“打包”成一个临时文件:
有两个特别的插件,在这里发挥着关键作用:
1.externalize-deps: 负责处理配置文件的依赖。
• 如果是入口文件、绝对路径、Node内置模块,直接返回。
• 如果是类Node内置模块(以node:,npm:,bun:开头),标记为external: true,不打包进最终产物。
• 其它依赖,通过tryNodeResolve解析路径,同样标记为external: true。
2.inject-file-scope-variables: 给.js、.ts等文件注入__dirname,__filename,import.meta.url这几个变量。
加载配置:AOT 和 JIT
Vite拿到Esbuild“预编译”后的代码(bundle.code),怎么加载配置呢?
•ESM:采用AOT (Ahead-Of-Time) 方式
1. 将bundle.code写入临时文件(例如node_modules/.vite-temp/xxx.mjs)。
2. 利用import()动态导入这个临时文件。
3. 获取导出的配置对象。
4. 删除临时文件。
•CJS:采用JIT (Just-in-Time) 方式
1. 拦截Node.js的require.extensions['.js']。
2. 当require配置文件时,用module._compile编译bundle.code。
3. 正常require,拿到配置。
4. 恢复require.extensions['.js']。
环境变量
Vite支持从.env文件加载环境变量,由loadEnv函数实现。loadEnv会按优先级加载.env,.env.local,.env.[mode],.env.[mode].local文件,并将它们合并。
注意:.env文件中的NODE_ENV会被特殊处理,可能会被保存到process.env.VITE_USER_NODE_ENV。Vite会优先根据这个值来判断是否为生产环境。
插件配置
Vite的插件机制让其拥有了强大的扩展性。解析完配置文件后,Vite会:
1. 根据apply属性(可以是'serve','build', 或一个函数),筛选出适用的插件。
2. 根据enforce属性(pre,normal,post),对插件进行排序。
3. 依次调用插件的config钩子,将配置进行合并。
掌握了这些,各种配置难题都将迎刃而解!下次遇到配置问题,再也不用盲猜啦!
如果觉得内容不错,欢迎点赞、分享、推荐!一起交流前端开发!
领取专属 10元无门槛券
私享最新 技术干货