阅读 414

Electron+Vue3 MAC 版日历开发记录(10)——env 使用

这是我参与更文挑战的第10天,活动详情查看: 更文挑战

由于之前界面有点傻大个,所以在任务里,我加了一条:「整体缩小一倍」,但是伴随的问题也就出现了,我总不能每次调整界面大小,然后在所以有布局的地方都一遍一遍的找出来修改吧。

所以,今天我把关注点放在了变量上,也就是今天的记录主题:env 的使用。

其实在很多成熟的框架 (各种编程语言),如 PHP 的 Laravel 框架,也是使用 env 来配置我们的静态和敏感变量。

环境变量说明

Vite 在一个特殊的 import.meta.env 对象上暴露环境变量。这里有一些普遍适用的内建变量:

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

import.meta.env.BASE_URL: {string} 应用正被部署在的 base URL。它由 base 配置项 决定。

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

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

  1. 在本项目里,我把常规的通用变量,如 window 长和宽放在 .env 下,如:
VITE_APP_WIDTH=500
VITE_APP_HEIGHT=400
复制代码

注:为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码。

在代码中,就可以直接使用了:

// main/src/App.ts
const window = new BrowserWindow({
  width: Number(this.env.VITE_APP_WIDTH),
  height: Number(this.env.VITE_APP_HEIGHT),
  resizable: false,
  alwaysOnTop: true,
  show: false,
  frame: false,
  webPreferences: {
    webSecurity: false,
    preload: join(__dirname, '../../preload/dist/index.cjs'),
    contextIsolation: this.env.MODE !== 'test',   // Spectron tests can't work with contextIsolation: true
    enableRemoteModule: this.env.MODE === 'test', // Spectron tests can't work with enableRemoteModule: false
  },
});
复制代码
  1. 同样的,本项目用到的天气预报服务器 API 也可以放在 .env 中,在 service 中直接使用
// .env
VITE_APP_WIDTH=700
VITE_APP_HEIGHT=600
VITE_WEATHER_API=***

// WeatherService.ts
const res = await http({
  url: import.meta.env.VITE_WEATHER_API,
  method: 'get',
  params: {
    param: JSON.stringify({
      location: locationStr,
    }),
  },
});
复制代码

智能提示

根据 VITE 官方文档 所说的:

Vite 会默认为 import.meta.env 提供类型定义。随着在 .env[mode] 文件中定义了越来越多自定义环境变量,你可能想要在代码中获取这些以 VITE_ 为前缀的用户自定义环境变量的 TypeScript 智能提示。

要想做到这一点,你可以在 src 目录下创建一个 env.d.ts,接着按下面这样定义 ImportMetaEnv

interface ImportMetaEnv {
  VITE_DEV_SERVER_URL: string,
  // 更多环境变量...
  VITE_APP_WIDTH: number,
  VITE_APP_HEIGHT: number,
}
复制代码

而在本项目所引用的框架中,是采用「命令」生成以上文件的,见:types/env.d.ts:

生成该文件的代码如下:

#!/usr/bin/env node

const {resolveConfig} = require('vite');
const {writeFileSync, mkdirSync, existsSync} = require('fs');
const {resolve, dirname} = require('path');

const MODES = ['production', 'development', 'test'];

const typeDefinitionFile = resolve(process.cwd(), './types/env.d.ts');

/**
 *
 * @return {string}
 */
function getBaseInterface() {
  return 'interface IBaseEnv {[key: string]: string}';
}

/**
 *
 * @param {string} mode
 * @return {Promise<{name: string, declaration: string}>}
 */
async function getInterfaceByMode(mode) {
  const interfaceName = `${mode}Env`;
  const {env: envForMode} = await resolveConfig({mode}, 'build');
  return {
    name: interfaceName,
    declaration: `interface ${interfaceName} extends IBaseEnv ${JSON.stringify(envForMode)}`,
  };
}

/**
 * @param {string[]} modes
 * @param {string} filePath
 */
async function buildMode(modes, filePath) {

  const IBaseEnvDeclaration = getBaseInterface();

  const interfaces = await Promise.all(modes.map(getInterfaceByMode));

  const allDeclarations = interfaces.map(i => i.declaration);
  const allNames = interfaces.map(i => i.name);

  const ImportMetaEnvDeclaration = `type ImportMetaEnv = Readonly<${allNames.join(' | ')}>`;

  const content = `
    ${IBaseEnvDeclaration}
    ${allDeclarations.join('\n')}
    ${ImportMetaEnvDeclaration}
  `;

  const dir = dirname(filePath);
  if (!existsSync(dir)) {
    mkdirSync(dir);
  }


  writeFileSync(filePath, content, {encoding: 'utf-8', flag: 'w'});
}

buildMode(MODES, typeDefinitionFile)
  .catch(err => {
    console.error(err);
    process.exit(1);
  });
复制代码

代码应该都能看得懂,不再解释了。命令写在 package.json

 "buildEnvTypes": "node scripts/buildEnvTypes.js",
复制代码

所以每次更新静态变量,在运行之前,都需要执行一次该命令:

小结

好了,今天总算了解了下有关 Vite 相关的知识,如何使用 env 来配置静态变量,如何在不同环境 (developmentproductiontestlocal) 下使用。最后剩下一个 staging 没用到,有待于以后使用的时候再做总结了。

未完待续!

这个项目的所有记录基本放进专栏里了,欢迎查看: Electron+Vue3 MAC 版日历开发记录

最近有伙伴问代码链接:代码已同步到 github 上了:github.com/fanly/fanly…

文章分类
前端
文章标签