告别硬编码!OpenHarmony PC 使用ohos-signpost 签名安装三方库 dotenv,解决环境变量完整解决方案
欢迎加入开源鸿蒙PC社区: https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
AtomGit 仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_node_vue_ts
本文完整梳理了ARM64架构鸿蒙PC(HarmonyOS/OpenHarmony6.1及以上),基于CodeArts IDE搭建Vite+Vue前端项目的全流程与疑难解决方案。项目实操中,Vite启动会出现rolldown原生模块权限拒绝报错,根源是鸿蒙系统拦截未签名二进制文件,最终解决方案为引入ohos-signpost自动签名工具,配置npm后置钩子,在依赖安装完成后自动为所有.node文件添加系统合法签名,消除权限校验拦截,最终实现CodeArts IDE内Vue+TS项目正常启动、调试。
这里有一篇比较详细的攻略:
OpenHarmony 鸿蒙 PC + CodeArts IDE 前端 Vite+Vue 完整开发环境搭建指南
一、dotenv 库完整介绍
1. 作用与定位
dotenv 是 Node.js 环境变量管理库,读取项目根目录 .env 文件,把自定义配置注入 process.env,解决硬编码密钥、环境区分问题。
核心功能
- 分离配置与代码:数据库账号、密钥、接口地址写在
.env,不提交Git; - 多环境区分:支持
.env.development/.env.production/.env.local; - 自动类型转换、变量插值、空值默认值;
- 兼容鸿蒙PC Node、Vite、Express、脚本、后端服务;
- 配合
.gitignore保护隐私密钥,防止账号泄露。
开发业务场景
- 数据库连接地址、账号密码;
- JWT加密密钥、第三方API key(OSS/短信/支付);
- 服务端口、线上/线下接口域名;
- 功能开关、日志级别、文件存储路径。
2. 安装命令
npm i dotenv
# TS项目类型提示
npm i -D @types/dotenv

步骤1:新建4个环境配置文件
.env(公共基础配置,所有环境共用)
# 服务基础配置
SERVER_PORT=3000
APP_NAME=鸿蒙Node后端Demo
LOG_LEVEL=info
# 数据库公共
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=test_db
.env.development(开发环境)
# 开发环境接口地址
API_BASE_URL=http://127.0.0.1:8080/dev
# 开发库账号
DB_USER=dev_user
DB_PASS=123456dev
# 调试开关
DEBUG=true
.env.production(生产环境)
API_BASE_URL=https://api.prod-harmonypc.com
DB_USER=prod_user
DB_PASS=superSecure123!
DEBUG=false
# JWT密钥
JWT_SECRET=prod_abc123456_secret_key
.env.local(本地私有,git忽略,本机个性化)
# 本机本地覆盖配置,优先级最高
SERVER_PORT=3001
LOG_LEVEL=debug
步骤2:新建 .gitignore 避免密钥提交
# 环境配置,禁止上传
.env
.env.local
.env.development.local
.env.production.local
node_modules
dist
步骤3:主代码 envDemo.js(CommonJS,兼容鸿蒙Node)
// 导入dotenv核心
const dotenv = require('dotenv');
const path = require('path');
const fs = require('fs-extra');
/**
* 工具:根据NODE_ENV加载对应环境文件,支持多层覆盖
* 优先级:.env.local > .env.xxx > .env
*/
function loadEnvByMode() {
// 读取运行时环境标识,默认开发环境
const envMode = process.env.NODE_ENV || 'development';
console.log(`当前运行环境 NODE_ENV = ${envMode}\n`);
// 配置文件路径定义
const envPaths = [
path.resolve(__dirname, '.env'), // 公共基础
path.resolve(__dirname, `.env.${envMode}`), // 环境专属
path.resolve(__dirname, '.env.local'), // 本地私有(最高优先级)
];
// 按顺序加载,后加载的变量会覆盖前面同名变量
envPaths.forEach(filePath => {
if (fs.pathExistsSync(filePath)) {
const envContent = fs.readFileSync(filePath, 'utf8');
dotenv.parse(envContent);
dotenv.config({ path: filePath });
console.log(`已加载配置文件:${path.basename(filePath)}`);
} else {
console.log(`跳过不存在文件:${path.basename(filePath)}`);
}
});
console.log('');
}
/**
* 示例1:读取普通字符串、数字、布尔环境变量
*/
function demoReadBasicEnv() {
console.log('===== 1. 读取基础环境变量 =====');
const port = process.env.SERVER_PORT;
const appName = process.env.APP_NAME;
const logLevel = process.env.LOG_LEVEL;
const debugSwitch = process.env.DEBUG === 'true';
console.log('服务端口(字符串):', port);
console.log('项目名称:', appName);
console.log('日志等级:', logLevel);
console.log('调试开关(布尔转换):', debugSwitch, typeof debugSwitch);
console.log('');
}
/**
* 示例2:数据库配置封装,统一组装连接字符串
*/
function demoDbConfig() {
console.log('===== 2. 数据库配置组装 =====');
const dbConfig = {
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT),
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASS,
};
console.log('完整数据库配置对象:', dbConfig);
const connectStr = `mysql://${dbConfig.user}:${dbConfig.password}@${dbConfig.host}:${dbConfig.port}/${dbConfig.database}`;
console.log('拼接数据库连接串:', connectStr);
console.log('');
}
/**
* 示例3:接口域名、密钥敏感配置读取
*/
function demoSecretConfig() {
console.log('===== 3. 接口与密钥敏感配置 =====');
const apiUrl = process.env.API_BASE_URL;
const jwtKey = process.env.JWT_SECRET || 'default_test_key';
console.log('后端接口地址:', apiUrl);
console.log('JWT加密密钥兜底默认值:', jwtKey);
console.log('');
}
/**
* 示例4:手动解析env文本字符串(动态加载内容场景)
*/
function demoParseManual() {
console.log('===== 4. dotenv.parse 手动解析文本 =====');
const envText = `
CACHE_EXPIRE=3600
REDIS_HOST=127.0.0.1
`;
const parsedObj = dotenv.parse(envText);
console.log('手动解析文本得到对象:', parsedObj);
console.log('缓存过期时间:', parsedObj.CACHE_EXPIRE);
console.log('');
}
/**
* 示例5:校验必填环境变量,缺失直接终止程序
*/
function demoEnvValidate() {
console.log('===== 5. 环境变量必填校验(生产必备) =====');
const requiredKeys = ['SERVER_PORT', 'DB_HOST', 'API_BASE_URL'];
let missing = [];
for (const key of requiredKeys) {
if (!process.env[key]) {
missing.push(key);
}
}
if (missing.length > 0) {
console.error('❌ 缺失必填环境变量:', missing);
process.exit(1); // 缺少关键配置直接退出进程
}
console.log('✅ 所有必填环境变量校验通过');
console.log('');
}
/**
* 统一入口执行所有示例
*/
async function runAllDemo() {
// 第一步:按环境加载对应.env配置
loadEnvByMode();
demoReadBasicEnv();
demoDbConfig();
demoSecretConfig();
demoParseManual();
demoEnvValidate();
console.log('🎉 dotenv 全部功能示例执行完成');
}
// 执行
runAllDemo().catch(err => {
console.error('程序异常:', err);
});

代码逐段完整讲解 dotenv 多环境配置示例
一、头部依赖导入
const dotenv = require('dotenv');
const path = require('path');
const fs = require('fs-extra');
dotenv:核心库,读取.env配置文件,将键值注入全局process.env;path:处理文件绝对/相对路径,兼容鸿蒙、Windows、macOS 不同系统路径分隔符;fs-extra:增强文件工具,pathExistsSync判断配置文件是否存在,原生 fs 判断文件更繁琐。
二、核心工具函数 loadEnvByMode 多环境分层加载
功能说明
根据 NODE_ENV 环境标识自动加载三套配置文件,后加载文件同名变量会覆盖前面,优先级规则:.env.local(本地私有) > .env.xxx(开发/生产) > .env(公共基础)。
function loadEnvByMode() {
// 读取运行时环境标识,未指定默认 development 开发环境
const envMode = process.env.NODE_ENV || 'development';
console.log(`当前运行环境 NODE_ENV = ${envMode}\n`);
// 配置文件加载顺序:公共基础 → 对应环境 → 本地私有
const envPaths = [
path.resolve(__dirname, '.env'),
path.resolve(__dirname, `.env.${envMode}`),
path.resolve(__dirname, '.env.local'),
];
envPaths.forEach(filePath => {
// 判断文件存在才加载,不存在直接跳过不报错
if (fs.pathExistsSync(filePath)) {
// 读取文件原始文本
const envContent = fs.readFileSync(filePath, 'utf8');
// parse 仅解析文本为对象,不会挂载到 process.env
dotenv.parse(envContent);
// config 真正将文件内变量注入全局 process.env
dotenv.config({ path: filePath });
console.log(`已加载配置文件:${path.basename(filePath)}`);
} else {
console.log(`跳过不存在文件:${path.basename(filePath)}`);
}
});
console.log('');
}
关键知识点
NODE_ENV:运行脚本时手动指定,NODE_ENV=production node xxx.js切换生产环境;- 分层设计好处:
.env:所有环境共用通用配置(端口、库名、日志等级);.env.development:开发专用,本地数据库、调试开关;.env.production:线上正式密钥、线上接口地址;.env.local:本机个性化配置,不上传Git,优先级最高,用来临时覆盖端口、账号;
dotenv.parse():只解析文本生成键值对象,不写入全局;dotenv.config()才会挂载到process.env。
三、示例1 demoReadBasicEnv 基础类型读取
function demoReadBasicEnv() {
console.log('===== 1. 读取基础环境变量 =====');
const port = process.env.SERVER_PORT;
const appName = process.env.APP_NAME;
const logLevel = process.env.LOG_LEVEL;
// .env 内所有值都是字符串,需要手动转布尔
const debugSwitch = process.env.DEBUG === 'true';
console.log('服务端口(字符串):', port);
console.log('项目名称:', appName);
console.log('日志等级:', logLevel);
console.log('调试开关(布尔转换):', debugSwitch, typeof debugSwitch);
console.log('');
}
- 所有
.env读取出来的数据全部为字符串,数字、布尔都需要手动转换; - 布尔判断标准:判断字符串是否严格等于
"true",其余值都为 false; - 全局任意文件都能直接使用
process.env.xxx获取配置,无需重复加载文件。
四、示例2 demoDbConfig 数据库配置封装
function demoDbConfig() {
console.log('===== 2. 数据库配置组装 =====');
const dbConfig = {
host: process.env.DB_HOST,
port: Number(process.env.DB_PORT), // 端口转数字
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASS,
};
console.log('完整数据库配置对象:', dbConfig);
// 拼接标准mysql连接字符串,直接供数据库驱动使用
const connectStr = `mysql://${dbConfig.user}:${dbConfig.password}@${dbConfig.host}:${dbConfig.port}/${dbConfig.database}`;
console.log('拼接数据库连接串:', connectStr);
console.log('');
}
业务场景:将零散的数据库配置整合为统一配置对象,统一生成连接地址,避免代码各处重复读取环境变量。
五、示例3 demoSecretConfig 敏感密钥默认兜底
function demoSecretConfig() {
console.log('===== 3. 接口与密钥敏感配置 =====');
const apiUrl = process.env.API_BASE_URL;
// 兜底默认值:环境变量不存在时使用备用密钥,防止 undefined 报错
const jwtKey = process.env.JWT_SECRET || 'default_test_key';
console.log('后端接口地址:', apiUrl);
console.log('JWT加密密钥兜底默认值:', jwtKey);
console.log('');
}
核心技巧:变量 || 默认值 兜底,当配置文件缺失该键时,程序不会拿到 undefined 引发加密、接口请求异常。
六、示例4 demoParseManual 手动解析env文本
function demoParseManual() {
console.log('===== 4. dotenv.parse 手动解析文本 =====');
// 模拟一段 .env 格式的文本内容
const envText = `
CACHE_EXPIRE=3600
REDIS_HOST=127.0.0.1
`;
// 单独解析文本,不注入全局 process.env,仅得到普通JS对象
const parsedObj = dotenv.parse(envText);
console.log('手动解析文本得到对象:', parsedObj);
console.log('缓存过期时间:', parsedObj.CACHE_EXPIRE);
console.log('');
}
适用场景:动态读取远程配置、内存生成配置文本,不需要挂载全局时使用,仅单独解析键值。
七、示例5 demoEnvValidate 必填配置校验(生产环境核心)
function demoEnvValidate() {
console.log('===== 5. 环境变量必填校验(生产必备) =====');
// 定义项目运行不可缺失的关键配置
const requiredKeys = ['SERVER_PORT', 'DB_HOST', 'API_BASE_URL'];
let missing = [];
for (const key of requiredKeys) {
// 判断环境变量为空则加入缺失列表
if (!process.env[key]) {
missing.push(key);
}
}
if (missing.length > 0) {
console.error('❌ 缺失必填环境变量:', missing);
// 关键配置缺失,直接终止进程,不启动残缺服务
process.exit(1);
}
console.log('✅ 所有必填环境变量校验通过');
console.log('');
}
线上服务必备逻辑:数据库地址、接口域名、加密密钥缺失的情况下,服务完全无法正常运行,启动时直接校验并退出,避免运行中途崩溃。
八、统一入口 runAllDemo
async function runAllDemo() {
// 第一步优先加载所有环境配置,后续所有函数才能读取 process.env
await loadEnvByMode();
demoReadBasicEnv();
demoDbConfig();
demoSecretConfig();
demoParseManual();
demoEnvValidate();
console.log('🎉 dotenv 全部功能示例执行完成');
}
// 捕获全局所有异步异常,防止进程闪退
runAllDemo().catch(err => {
console.error('程序异常:', err);
});
执行顺序说明:必须先加载环境文件,再执行读取配置的逻辑,否则 process.env 拿不到任何自定义变量。
整体代码业务价值总结
- 规范多环境管理,区分开发/本地/生产三套独立配置;
- 敏感密码、密钥不和业务代码硬编码,防止代码提交泄露隐私;
- 统一封装加载逻辑,项目任意模块无需重复写读取.env代码;
- 内置配置校验,保障线上服务启动完整性;
- 支持手动解析文本,适配动态配置、远程配置拓展场景;
- 兼容鸿蒙PC Node环境,纯JS无二进制,无需签名直接运行。
TS 精简版 envDemo.ts(无类型报错)
import dotenv from 'dotenv';
import path from 'path';
dotenv.config({ path: path.resolve(__dirname, '.env') });
// 环境变量类型约束
interface EnvConfig {
SERVER_PORT: string;
APP_NAME: string;
}
const env = process.env as unknown as EnvConfig;
console.log('TS读取端口:', env.SERVER_PORT);
4. 运行区分开发/生产环境命令
开发环境(默认)
node envDemo.js
手动指定生产环境
# Linux / Mac / 鸿蒙终端
NODE_ENV=production node envDemo.js
# Windows cmd
set NODE_ENV=production && node envDemo.js
5. 代码核心逻辑讲解
- 多文件分层加载机制
按.env → .env.mode → .env.local顺序加载,后加载变量覆盖前面,本地配置优先级最高,不污染公共配置; - 自动注入 process.env
所有变量挂载到全局process.env,全项目任意文件直接读取; - 手动 parse 方法
支持解析字符串格式的env内容,适合动态生成配置、读取远程配置文本; - 必填变量校验
线上服务启动前校验数据库、密钥等关键配置,缺失直接退出,避免运行时报错; - 默认值兜底
使用process.env.KEY || 默认值,防止未定义变量返回undefined引发逻辑崩溃; - 类型手动转换
.env中所有值都是字符串,数字/布尔需要手动Number()/ 判断=== "true"。
6. 鸿蒙PC Node环境说明
dotenv 纯JS库,无 .node 二进制模块,无需 ohos-signpost 签名,直接 node 运行不会出现 permission denied;
常用于鸿蒙PC端Vite脚本、Node后端服务、打包构建脚本管理环境参数。
7. 开发规范
.env.local写入本机个性化端口、本地数据库密码,不提交仓库;- 密钥、数据库密码严禁写死在代码;
- 线上生产环境优先使用服务器系统环境变量,优先级高于
.env.production; - 提交代码前检查
.gitignore,禁止上传带真实密码的env文件。
更多推荐



所有评论(0)