目录
1.如何读取.env文件中定义的配置
1.3.1 vite使用cac定义命令
1.3.2 createServer
1.3.3 resolveConfig
1.3.4 loadEnv
2.如何将变量挂载到import.meta.env环境变量上
总结
首页 web前端 Vue.js 深入探讨vite是怎么解析.env文件的

深入探讨vite是怎么解析.env文件的

Jan 24, 2023 am 05:30 AM
前端 vue.js vite

深入探讨vite是怎么解析.env文件的

使用vue框架开发前端项目时,我们部署的时候都会部署多套环境,往往开发、测试以及线上环境调用的接口域名都是不一样的。如何能做到区分呢?那就是使用环境变量和模式。

使用vite构建的vue3项目中,可以在根目录下创建.env.[模式]文件定义一种或多种模式,并且在这个文件中定义的变量就是此模式的环境变量。定义了环境变量之后就可以通过import.meta.env.[变量名]的方式读取环境变量了。【相关推荐:vuejs视频教程web前端开发

那么我们要来思考两个问题:第一,vite如何读取.env文件中定义的配置;第二,vite如何将.env文件中配置的环境变量挂载到import.meta.env环境变量上的。通过学习今天vite中的相关源代码我们就能够明白。欢迎阅读本文学习,如果有错误的地方请不吝指正。

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

1.1 问题的着眼点是什么?

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

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

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

1.2 vite的命令定义在何处?

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

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

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

如上代码可以看出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'

const cli = cac('vite')
cli
  .option(&#39;-m, --mode <mode>&#39;, `[string] set env mode`)
cli
  .command(&#39;[root]&#39;, &#39;start dev server&#39;) // default command
  .alias(&#39;serve&#39;) // the command is called &#39;serve&#39; in Vite&#39;s API
  .option(&#39;--port <port>&#39;, `[number] specify port`)
  .action(async (root: string, options: ServerOptions & GlobalCLIOptions) => {
    const { createServer } = await import(&#39;./server&#39;)
    try {
      const server = await createServer({
        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 &#39;../config&#39;
export async function createServer(
  inlineConfig: InlineConfig = {},
): Promise<ViteDevServer> {
  const config = await resolveConfig(inlineConfig, &#39;serve&#39;)
}
登录后复制

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

1.3.3 resolveConfig

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

import { loadEnv, resolveEnvPrefix } from &#39;./env&#39;
export async function resolveConfig(
  inlineConfig: InlineConfig,
  command: &#39;build&#39; | &#39;serve&#39;,
  defaultMode = &#39;development&#39;,
  defaultNodeEnv = &#39;development&#39;,
): Promise<ResolvedConfig> {
  const envDir = config.envDir
    ? normalizePath(path.resolve(resolvedRoot, config.envDir))
    : resolvedRoot
  const userEnv =
    inlineConfig.envFile !== false &&
    loadEnv(mode, envDir, resolveEnvPrefix(config))
  const resolvedConfig: ResolvedConfig = {
    command,
    mode,
    env: {
      ...userEnv,
      BASE_URL,
      MODE: mode,
      DEV: !isProduction,
      PROD: isProduction,
    },
  }
  const resolved: ResolvedConfig = {
    ...config,
    ...resolvedConfig,
  }
  return resolved
}
登录后复制

可以看到resolveConfig的主要工作:

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

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

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

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

1.3.4 loadEnv

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

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

import { parse } from &#39;dotenv&#39;
import { arraify, lookupFile } from &#39;./utils&#39;

export function loadEnv(
  mode: string,
  envDir: string,
  prefixes: string | string[] = &#39;VITE_&#39;,
): Record<string, string> {
  prefixes = arraify(prefixes)
  const env: Record<string, string> = {}
  const envFiles = [
    /** default file */ `.env`,
    /** local file */ `.env.local`,
    /** mode file */ `.env.${mode}`,
    /** mode local file */ `.env.${mode}.local`,
  ]

  const parsed = Object.fromEntries(
    envFiles.flatMap((file) => {
      const path = lookupFile(envDir, [file], {
        pathOnly: true,
        rootDir: envDir,
      })
      if (!path) return []
      return Object.entries(parse(fs.readFileSync(path)))
    }),
  )
  // only keys that start with prefix are exposed to client
  for (const [key, value] of Object.entries(parsed)) {
    if (prefixes.some((prefix) => key.startsWith(prefix))) {
      env[key] = value
    } else if (
      key === &#39;NODE_ENV&#39; &&
      process.env.VITE_USER_NODE_ENV === undefined
    ) {
      // NODE_ENV override in .env file
      process.env.VITE_USER_NODE_ENV = value
    }
  }

  return env
}
登录后复制

如上代码所示理解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,如下图所示:

2.2 resolveConfig

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

import {resolvePlugins,} from &#39;./plugins&#39;

export async function resolveConfig(
  inlineConfig: InlineConfig,
  command: &#39;build&#39; | &#39;serve&#39;,
  defaultMode = &#39;development&#39;,
  defaultNodeEnv = &#39;development&#39;,
): Promise<ResolvedConfig> {
  (resolved.plugins as Plugin[]) = await resolvePlugins(
    resolved,
    prePlugins,
    normalPlugins,
    postPlugins,
  )
}
登录后复制

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

2.3 resolvePlugins

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

import { definePlugin } from &#39;./define&#39;

export async function resolvePlugins(
  config: ResolvedConfig,
  prePlugins: Plugin[],
  normalPlugins: Plugin[],
  postPlugins: Plugin[],
): Promise<Plugin[]> {
  return [
    //...
    definePlugin(config),
    //...
  ].filter(Boolean) as Plugin[]
}
登录后复制

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

2.4 definePlugin

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

const importMetaKeys: Record<string, string> = {}
const importMetaFallbackKeys: Record<string, string> = {}
if (isBuild) {
  const env: Record<string, any> = {
    ...config.env,
    SSR: !!config.build.ssr,
  }
  for (const key in env) {
    importMetaKeys[`import.meta.env.${key}`] = JSON.stringify(env[key])
  }
  Object.assign(importMetaFallbackKeys, {
    &#39;import.meta.env.&#39;: `({}).`,
    &#39;import.meta.env&#39;: JSON.stringify(config.env),
    &#39;import.meta.hot&#39;: `false`,
  })
}
登录后复制

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

总结

通过阅读vite的源码,我们了解到vite处理.env文件时涉及到的两个关键问题:第一,vite如何读取.env文件中定义的配置;第二,vite如何将.env文件中配置的环境变量挂载到import.meta.env环境变量上。

对于第一问题,我们了解到vite使用cac定义命令,当执行vite命令并通过--mode或者-m选项指定模式的时候,vite会拿到mode, 然后vite会去项目目录下查找对应.env.[模式]的文件并读取其内容,然后通过dotenv的parse方法解析文件内容,将定义的环境变量整合到resolved中。

对于第二个问题,我们了解到vite的resolveConfig方法中会执行插件解析的方法resolvePlugins,而此方法又会调用definePlugin方法,在definePlugin方法中会完成将.env文件中定义的变量挂载到import.meta.env环境变量上。

(学习视频分享:vuejs入门教程编程基础视频

以上是深入探讨vite是怎么解析.env文件的的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Vue3+TS+Vite开发技巧:如何进行SEO优化 Vue3+TS+Vite开发技巧:如何进行SEO优化 Sep 10, 2023 pm 07:33 PM

Vue3+TS+Vite开发技巧:如何进行SEO优化SEO(SearchEngineOptimization)是指通过优化网站的结构、内容和关键词等方面,使其在搜索引擎的排名更靠前,从而增加网站的流量和曝光度。在Vue3+TS+Vite等现代前端技术的开发中,如何进行SEO优化是一个很重要的问题。本文将介绍一些Vue3+TS+Vite开发的技巧和方法,帮

Vue3+TS+Vite开发技巧:如何进行跨域请求和网络请求优化 Vue3+TS+Vite开发技巧:如何进行跨域请求和网络请求优化 Sep 09, 2023 pm 04:40 PM

Vue3+TS+Vite开发技巧:如何进行跨域请求和网络请求优化引言:在前端开发中,网络请求是非常常见的操作。如何优化网络请求以提高页面加载速度和用户体验是我们开发者需要思考的问题之一。同时,对于一些需要向不同域名发送请求的场景,我们需要解决跨域问题。本文将介绍如何在Vue3+TS+Vite开发环境下进行跨域请求以及网络请求的优化技巧。一、跨域请求解决方案使

Vue3+TS+Vite开发技巧:如何进行数据加密和存储 Vue3+TS+Vite开发技巧:如何进行数据加密和存储 Sep 10, 2023 pm 04:51 PM

Vue3+TS+Vite开发技巧:如何进行数据加密和存储随着互联网技术的快速发展,数据的安全性和隐私保护变得越来越重要。在Vue3+TS+Vite开发环境下,如何进行数据加密和存储,是每个开发人员都需要面对的问题。本文将介绍一些常用的数据加密和存储的技巧,帮助开发人员提升应用的安全性和用户体验。一、数据加密前端数据加密前端加密是保护数据安全性的重要一环。常用

Vue3+TS+Vite开发技巧:如何进行前端安全防护 Vue3+TS+Vite开发技巧:如何进行前端安全防护 Sep 09, 2023 pm 04:19 PM

Vue3+TS+Vite开发技巧:如何进行前端安全防护随着前端技术的不断发展,越来越多的企业和个人开始使用Vue3+TS+Vite进行前端开发。然而,随之而来的安全风险也引起了人们的关注。在本文中,我们将探讨一些常见的前端安全问题,并分享一些在Vue3+TS+Vite开发过程中如何进行前端安全防护的技巧。输入验证用户的输入往往是前端安全漏洞的主要来源之一。在

PHP与Vue:完美搭档的前端开发利器 PHP与Vue:完美搭档的前端开发利器 Mar 16, 2024 pm 12:09 PM

PHP与Vue:完美搭档的前端开发利器在当今互联网高速发展的时代,前端开发变得愈发重要。随着用户对网站和应用的体验要求越来越高,前端开发人员需要使用更加高效和灵活的工具来创建响应式和交互式的界面。PHP和Vue.js作为前端开发领域的两个重要技术,搭配起来可以称得上是完美的利器。本文将探讨PHP和Vue的结合,以及详细的代码示例,帮助读者更好地理解和应用这两

前端面试官常问的问题 前端面试官常问的问题 Mar 19, 2024 pm 02:24 PM

在前端开发面试中,常见问题涵盖广泛,包括HTML/CSS基础、JavaScript基础、框架和库、项目经验、算法和数据结构、性能优化、跨域请求、前端工程化、设计模式以及新技术和趋势。面试官的问题旨在评估候选人的技术技能、项目经验以及对行业趋势的理解。因此,应试者应充分准备这些方面,以展现自己的能力和专业知识。

Django是前端还是后端?一探究竟! Django是前端还是后端?一探究竟! Jan 19, 2024 am 08:37 AM

Django是一个Python编写的web应用框架,它强调快速开发和干净方法。尽管Django是一个web框架,但是要回答Django是前端还是后端这个问题,需要深入理解前后端的概念。前端是指用户直接和交互的界面,后端是指服务器端的程序,他们通过HTTP协议进行数据的交互。在前端和后端分离的情况下,前后端程序可以独立开发,分别实现业务逻辑和交互效果,数据的交

Vue3+TS+Vite开发技巧:如何进行微件和插件开发 Vue3+TS+Vite开发技巧:如何进行微件和插件开发 Sep 10, 2023 pm 07:30 PM

Vue3是Vue.js最新的版本,它引入了许多新的特性和改进,使得开发者们能够更加高效地构建灵活的Web应用程序。在Vue3中,TypeScript(TS)可以与Vue无缝集成,为我们提供了强大的类型检查功能。而Vite是一个轻量级的,基于ES模块的,开发工具,它具有快速的冷启动时间和快速的热模块更新。本文将为你介绍如何使用Vue3、TS和Vite进行微件和

See all articles