Vite+Vue3+TypeScript+Element Plus (九) 搭建企业级轻量框架实践

1,047 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

本章讲解vite中环境变量的使用,*.env环境变量文件大部分前端项目都会使用。一般用于区分开发、生产、测试等环境,在不同环境采取不同配置方案。

推荐阅读

vite.config.ts 之 Env 篇 (九)

.env

默认配置不区分项目环境

# port
VITE_PORT = 8808
# title
VITE_APP_TITLE = Admin JueJin Plus

.env.development

开发环境生效 运行npm run dev 时会加载.env.development配置内容到环境变量中,同时会合并.env配置存在相同变量名会覆盖默认配置。 变量命名规则以VITE_开头

# public path
VITE_PUBLIC_PATH = /

# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false

# 跨域代理 可以配置多个
VITE_PROXY = [["/basic-dev","http://localhost:3000"],["/basic-dev-upload","http://localhost:3300/upload"]]

.env.production

生产环境生效

# public path
VITE_PUBLIC_PATH = /

# 是否启用图片压缩
VITE_USE_IMAGEMIN = false

# 是否启用压缩
VITE_USE_COMPRESS = false

# 是否为打包后的文件提供传统浏览器兼容性支持 支持 true 不支持 false
VITE_LEGACY = false

# 使用压缩时是否删除源文件,默认为false
VITE_COMPRESS_DELETE_ORIGIN_FILE = false

# 跨域代理 可以配置多个
VITE_PROXY = [["/basic-prod","http://localhost:3000"],["/basic-prod-upload","http://localhost:3300/upload"]]
  • 读取环境变量

vite中提供了loadEnv方法可以加载当前环境变量配置

import { loadEnv } from 'vite'
// 加载.env.development
const env = loadEnv('development', process.cwd())
// 加载.env.production
const env = loadEnv('production', process.cwd())

注意获取到的配置值全部都是字符串,通过工具类进行对应类型转换。

// util.ts
declare type Recordable<T = any> = Record<string, T>
// 读取所有要处理的环境变量配置文件
export function wrapperEnv(envConf: Recordable): ViteEnv {
  const ret: any = {}
  for (const envName of Object.keys(envConf)) {
    let realName = envConf[envName].replace(/\\n/g, '\n')
    realName = realName === 'true' ? true : realName === 'false' ? false : realName

    if (envName === 'VITE_PORT') {
      realName = Number(realName)
    }
    if (envName === 'VITE_PROXY' && realName) {
      try {
        realName = JSON.parse(realName.replace(/'/g, '"'))
      } catch (error) {
        realName = ''
      }
    }
    ret[envName] = realName
    if (typeof realName === 'string') {
      process.env[envName] = realName
    } else if (typeof realName === 'object') {
      process.env[envName] = JSON.stringify(realName)
    }
  }
  return ret
}

返回值ViteEnv定义在env.d.ts

// env.d.ts
/// <reference types="vite/client" />
interface ViteEnv {
  readonly VITE_APP_TITLE: string
  readonly VITE_PUBLIC_PATH: string
  readonly VITE_PORT: number
  readonly VITE_PROXY: [string, string][]
  readonly VITE_DROP_CONSOLE: boolean
  readonly VITE_USE_IMAGEMIN: boolean
  readonly VITE_USE_COMPRESS: boolean
  readonly VITE_COMPRESS_DELETE_ORIGIN_FILE: boolean
  readonly VITE_USE_MOCK: boolean
  readonly VITE_LEGACY: boolean
}
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
  const component: DefineComponent<{}, {}, any>
  export default component
}
  • 配置
import { UserConfig, ConfigEnv, loadEnv } from 'vite'
import { createVitePlugins, createViteBuild } from './config'
import { wrapperEnv } from './config/utils'
// https://vitejs.dev/config/
export default ({ command, mode }: ConfigEnv): UserConfig => { 
  const isBuild = command === 'build'
  const env = loadEnv(mode, process.cwd())
  const viteEnv = wrapperEnv(env)
  const { VITE_PUBLIC_PATH } = viteEnv
  return {
    base: VITE_PUBLIC_PATH,
    plugins: createVitePlugins(viteEnv, isBuild),
    build: createViteBuild(isBuild),
  }
}
  • 使用
import vue from '@vitejs/plugin-vue'
import vueSetupExtend from 'vite-plugin-vue-setup-extend'
import legacy from '@vitejs/plugin-legacy'
import OptimizationPersist from 'vite-plugin-optimize-persist'
import PkgConfig from 'vite-plugin-package-config'
import { configCompressPlugin } from './compress'
import { configImageminPlugin } from './imagemin'
import { configStyleImportPlugin } from './style'
import {
  configAutoImportPlugin,
  configVueComponentsPlugin,
  configVueIconsPlugin,
  configVuePurgeIconsPlugin,
} from './unplugin'
export function createVitePlugins(viteEnv: ViteEnv, isBuild: boolean) {
  const { VITE_USE_IMAGEMIN, VITE_USE_COMPRESS, VITE_COMPRESS_DELETE_ORIGIN_FILE, VITE_LEGACY } =
    viteEnv
  const plugins = [vue(), vueSetupExtend(), PkgConfig(), OptimizationPersist()]
  // 是否为打包后的文件提供传统浏览器兼容性支持
  VITE_LEGACY &&
    plugins.push(
      legacy({
        targets: ['ie >= 11'],
        additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
      })
    )
  if (isBuild) {
    // vite-plugin-compress
    VITE_USE_COMPRESS && plugins.push(configCompressPlugin(VITE_COMPRESS_DELETE_ORIGIN_FILE))
    // vite-plugin-imagemin
    VITE_USE_IMAGEMIN && plugins.push(configImageminPlugin())
  }
  // unplugin-auto-import
  plugins.push(configAutoImportPlugin())
  // unplugin-vue-components
  plugins.push(configVueComponentsPlugin())
  // vite-plugin-style-import
  plugins.push(configStyleImportPlugin())
  // unplugin-icons
  plugins.push(configVueIconsPlugin())
  // vite-plugin-purge-icons
  plugins.push(configVuePurgeIconsPlugin())
  return plugins
}
  • 开发服务器配置

开发服务器配置没有添加到vite配置中,如果想要使用自行配置。完整代码已经提交到Gitee中,想要学习的小伙伴请自行下载👍

import { ProxyOptions } from 'vite'
type ProxyTargetList = Record<string, ProxyOptions>
const httpsRE = /^https:\/\//
export function createViteServer(viteEnv: ViteEnv) {
  const { VITE_PORT, VITE_PROXY } = viteEnv
  const proxy: ProxyTargetList = {}
  for (const [prefix, target] of VITE_PROXY) {
    const isHttps = httpsRE.test(target)
    // https://github.com/http-party/node-http-proxy#options
    proxy[prefix] = {
      target: target,
      changeOrigin: true,
      ws: true,
      rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
      // https is require secure=false
      ...(isHttps ? { secure: false } : {}),
    }
  }
  return {
    hmr: { overlay: false }, // 禁用或配置 HMR 连接 设置 server.hmr.overlay 为 false 可以禁用服务器错误遮罩层
    cors: true, // 类型: boolean | CorsOptions 为开发服务器配置 CORS。默认启用并允许任何源
    open: true, // 服务启动时是否自动打开浏览器
    port: VITE_PORT, // 类型: number 指定服务器端口
    headers: {
      'Cache-Control': 'no-store',
    },
    https: false, // 是否开启 https
    host: '0.0.0.0', // IP配置,支持从IP启动
    // 本地跨域代理
    proxy,
  }
}

继续学习

废话只说一句:码字不易求个👍,收藏 === 学会,快行动起来吧!🙇‍🙇‍🙇‍。

# Vite+Vue3+TypeScript+Element (十) 搭建企业级轻量框架实践