这是我参与更文挑战的第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
相反)
- 在本项目里,我把常规的通用变量,如
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
},
});
复制代码
- 同样的,本项目用到的天气预报服务器 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
来配置静态变量,如何在不同环境 (development
、production
、test
、local
) 下使用。最后剩下一个 staging
没用到,有待于以后使用的时候再做总结了。
未完待续!
这个项目的所有记录基本放进专栏里了,欢迎查看:
Electron+Vue3 MAC 版日历开发记录最近有伙伴问代码链接:代码已同步到 github 上了:github.com/fanly/fanly…