vite是如何解析.env文件的(vite,编程语言)

时间:2024-05-02 04:49:47 作者 : 石家庄SEO 分类 : 编程语言
  • TAG :

使用vite构建的vue3项目中,可以在根目录下创建.env.[模式]文件定义一种或多种模式,并且在这个文件中定义的变量就是此模式的环境变量。定义了环境变量之后就可以通过import.meta.env.[变量名]的方式读取环境变量了。

那么我们要来思考两个问题:第一,vite如何读取.env文件中定义的配置;第二,vite如何将.env文件中配置的环境变量挂载到import.meta.env环境变量上的。

1.如何读取.env文件中定义的配置

1.1 问题的着眼点是什么?

首先我们看一下vite如何读取.env文件中定义的配置。如下图所示,在项目根目录下有.env.development,.env.fat,.env.uat,.env.pro四个模式文件,其中development模式是对应默认的开发环境用于本地开发,fat模式对应的也是开发环境用于自测,uat模式对应的是预发布环境用于测试团队测试,pro模式对应的是生产环境也叫线上环境用于客户使用。

vite是如何解析.env文件的

那么如何能够让vite知道我们要使用相关模式的文件呢?运行vite 或者vite build命令时可以通过--mode或者-m设置环境模式(详见文档),如下图所示:

vite是如何解析.env文件的

这就提示我们要了解vite如何读取定义环境变量的模式文件则需要从vite命令或者vite build命令入手,接下来从vite命令入手研究一下。

1.2 vite的命令定义在何处?

看一下vite的package.json文件(路径:vite/packages/vite/package.json):

vite是如何解析.env文件的

当我们使用vite命令的时候,会执行bin目录下的vite.js文件,看一下这个文件(路径:vite/packages/vite/bin/vite.js):

vite是如何解析.env文件的

可以看到这段代码的关键是执行start方法,而start方法是导入打包后的cli.js文件,那么这个打包后的文件对应的原文件是哪个文件呢?vite打包的时候是使用rollup的,所以我们看一下rollup的配置文件(路径:vite/packages/vite/rollup.config.ts):

vite是如何解析.env文件的

如上代码可以看出vite相关命令的定义在/src/node/cli.ts 这个文件当中。

1.3 vite的命令是如何定义的?

1.3.1 vite使用cac定义命令

我们来看一下vite的命令是如何定义的(路径:vite/packages/vite/src/node/cli.ts):

import{cac}from'cac'constcli=cac('vite')cli.option('-m,--mode<mode>',`[string]setenvmode`)cli.command('[root]','startdevserver')//defaultcommand.alias('serve')//thecommandiscalled'serve'inVite'sAPI.option('--port<port>',`[number]specifyport`).action(async(root:string,options:ServerOptions&GlobalCLIOptions)=>{const{createServer}=awaitimport('./server')try{constserver=awaitcreateServer({root,base:options.base,mode:options.mode,configFile:options.config,logLevel:options.logLevel,clearScreen:options.clearScreen,optimizeDeps:{force:options.force},server:cleanOptions(options),})})

如上代码所示,vite主要是使用cac这个命令行工具库定义命令的,解释一下这里使用到的cac的相关API:

  • cac(name?):用于创建一个cac实例,name参数是可选的。

  • option(name, description, config): 用于设置配置项。

  • command(name, description, config?): 声明cli命令,可以给命令设置独立的配置项喝其配置后的执行动作。

  • command.alias(name):给cli命令起别名。

  • action(callback): 指定命令所执行的操作。

可以看出,当运行vite命令的时候会执行createServer方法,我们这里要注意参数mode就是我们运行命令时通过--mode 或者 -m指定的参数,下面来研究createServer方法。

1.3.2 createServer

看一下createServer方法(路径:createServervite/packages/vite/src/node/server/index.ts):

import{resolveConfig}from'../config'exportasyncfunctioncreateServer(inlineConfig:InlineConfig={},):Promise<ViteDevServer>{constconfig=awaitresolveConfig(inlineConfig,'serve')}

可以看到createServer方法调用的是resolveConfig方法,下面看一下resolveConfig方法。

1.3.3 resolveConfig

resolveConfig方法的代码如下(路径;vite/packages/vite/src/node/config.ts):

import{loadEnv,resolveEnvPrefix}from'./env'exportasyncfunctionresolveConfig(inlineConfig:InlineConfig,command:'build'|'serve',defaultMode='development',defaultNodeEnv='development',):Promise<ResolvedConfig>{constenvDir=config.envDir?normalizePath(path.resolve(resolvedRoot,config.envDir)):resolvedRootconstuserEnv=inlineConfig.envFile!==false&&loadEnv(mode,envDir,resolveEnvPrefix(config))constresolvedConfig:ResolvedConfig={command,mode,env:{...userEnv,BASE_URL,MODE:mode,DEV:!isProduction,PROD:isProduction,},}constresolved:ResolvedConfig={...config,...resolvedConfig,}returnresolved}

可以看到resolveConfig的主要工作:

  • 首先确定.env文件的路径

  • 然后调用loadEnv方法加载解析.env文件,将结果赋值给userEnv

  • 最后返回整个解析后的配置

我们看到这里的关键代码是loadEnv(mode, envDir, resolveEnvPrefix(config))下面我就重点看一下loadEnv方法。

1.3.4 loadEnv

loadEnv方法是vite中一个比较核心的方法,也作为vite对外提供的一个JavaScript API,用于加载 envDir 中的 .env 文件。

vite是如何解析.env文件的

我们看一下loadEnv方法(路径:vite/packages/vite/src/node/env.ts):

import{parse}from'dotenv'import{arraify,lookupFile}from'./utils'exportfunctionloadEnv(mode:string,envDir:string,prefixes:string|string[]='VITE_',):Record<string,string>{prefixes=arraify(prefixes)constenv:Record<string,string>={}constenvFiles=[/**defaultfile*/`.env`,/**localfile*/`.env.local`,/**modefile*/`.env.${mode}`,/**modelocalfile*/`.env.${mode}.local`,]constparsed=Object.fromEntries(envFiles.flatMap((file)=>{constpath=lookupFile(envDir,[file],{pathOnly:true,rootDir:envDir,})if(!path)return[]returnObject.entries(parse(fs.readFileSync(path)))}),)//onlykeysthatstartwithprefixareexposedtoclientfor(const[key,value]ofObject.entries(parsed)){if(prefixes.some((prefix)=>key.startsWith(prefix))){env[key]=value}elseif(key==='NODE_ENV'&&process.env.VITE_USER_NODE_ENV===undefined){//NODE_ENVoverridein.envfileprocess.env.VITE_USER_NODE_ENV=value}}returnenv}

如上代码所示理解loadEnv方法注意以下几个方面:

  • 该方法接收三个参数,分别是模式、.env文件的路径还有环境变量的前缀。

  • 使用递归方法lookupFile找到.env文件的路径,使用fs.readFileSync读取文件。

  • 使用dotenv提供的方法解析.env文件内容。

关于dotenv可以学习川哥的文章,也可以看看笔者的源码共读语雀笔记。至此,我们了解了vite是如何读取.env文件中定义的环境变量了。下面我们研究第二个问题vite如何将.env中配置的环境变量挂载到import.meta.env环境变量上。

2.如何将变量挂载到import.meta.env环境变量上

2.1 vite的环境变量和import.meta

Vite 在一个特殊的 import.meta.env 对象上暴露环境变量,有一些在所有情况下都可以使用的内建变量:

import.meta.env.MODE: {string} 应用运行的模式。

import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。

import.meta.env.PROD: {boolean} 应用是否运行在生产环境。

import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD相反)。

import.meta.env.SSR: {boolean} 应用是否运行在 server 上。

详见环境变量。这里我们要解释一下import.meta。它是一个给JavaScript模块暴露特定上下文的元数据属性的对象。它包含了这个模块的信息,比如说这个模块的URL。详见import.meta 的MDN文档。需要注意不可以在模块的外部使用import.meta,如下图所示:

vite是如何解析.env文件的

2.2 resolveConfig

在上文中我们已经研究了resolveConfig的代码,我们再来看以下此方法中的另一段代码(路径:vite/packages/vite/src/node/config.ts):

import{resolvePlugins,}from'./plugins'exportasyncfunctionresolveConfig(inlineConfig:InlineConfig,command:'build'|'serve',defaultMode='development',defaultNodeEnv='development',):Promise<ResolvedConfig>{(resolved.pluginsasPlugin[])=awaitresolvePlugins(resolved,prePlugins,normalPlugins,postPlugins,)}

这里调用了resolvePlugins,接收resolved对象,此对象中含有开发者所指定的模式以及.env文件中的环境变量。我们接着看一下resolvePlugins方法。

2.3 resolvePlugins

节选resolvePlugins方法如下(路径:vite/packages/vite/src/node/plugins/index.ts):

import{definePlugin}from'./define'exportasyncfunctionresolvePlugins(config:ResolvedConfig,prePlugins:Plugin[],normalPlugins:Plugin[],postPlugins:Plugin[],):Promise<Plugin[]>{return[//...definePlugin(config),//...].filter(Boolean)asPlugin[]}

resolvePlugins负责解析插件,这里面调用了definePlugin方法,我们看一下。

2.4 definePlugin

definePlugin的代码如下(路径:vite/packages/vite/src/node/plugins/define.ts):

constimportMetaKeys:Record<string,string>={}constimportMetaFallbackKeys:Record<string,string>={}if(isBuild){constenv:Record<string,any>={...config.env,SSR:!!config.build.ssr,}for(constkeyinenv){importMetaKeys[`import.meta.env.${key}`]=JSON.stringify(env[key])}Object.assign(importMetaFallbackKeys,{'import.meta.env.':`({}).`,'import.meta.env':JSON.stringify(config.env),'import.meta.hot':`false`,})}

这段代码的关键部分在于第8-10行的for循环,将.env文件中定义的环境变量挂在到了import.meta.env上。至此,如何也了解了vite是如何将环境变量挂在到import.meta.env环境变量上。

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:vite是如何解析.env文件的的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:php-fpm重启失败如何解决下一篇:

2 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18