欢迎加入开源鸿蒙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,解决硬编码密钥、环境区分问题。

核心功能

  1. 分离配置与代码:数据库账号、密钥、接口地址写在 .env,不提交Git;
  2. 多环境区分:支持 .env.development / .env.production / .env.local
  3. 自动类型转换、变量插值、空值默认值;
  4. 兼容鸿蒙PC Node、Vite、Express、脚本、后端服务;
  5. 配合 .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');
  1. dotenv:核心库,读取 .env 配置文件,将键值注入全局 process.env
  2. path:处理文件绝对/相对路径,兼容鸿蒙、Windows、macOS 不同系统路径分隔符;
  3. 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('');
}

关键知识点

  1. NODE_ENV:运行脚本时手动指定,NODE_ENV=production node xxx.js 切换生产环境;
  2. 分层设计好处:
    • .env:所有环境共用通用配置(端口、库名、日志等级);
    • .env.development:开发专用,本地数据库、调试开关;
    • .env.production:线上正式密钥、线上接口地址;
    • .env.local:本机个性化配置,不上传Git,优先级最高,用来临时覆盖端口、账号;
  3. 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('');
}
  1. 所有 .env 读取出来的数据全部为字符串,数字、布尔都需要手动转换;
  2. 布尔判断标准:判断字符串是否严格等于 "true",其余值都为 false;
  3. 全局任意文件都能直接使用 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 拿不到任何自定义变量。

整体代码业务价值总结

  1. 规范多环境管理,区分开发/本地/生产三套独立配置;
  2. 敏感密码、密钥不和业务代码硬编码,防止代码提交泄露隐私;
  3. 统一封装加载逻辑,项目任意模块无需重复写读取.env代码;
  4. 内置配置校验,保障线上服务启动完整性;
  5. 支持手动解析文本,适配动态配置、远程配置拓展场景;
  6. 兼容鸿蒙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. 代码核心逻辑讲解

  1. 多文件分层加载机制
    .env → .env.mode → .env.local 顺序加载,后加载变量覆盖前面,本地配置优先级最高,不污染公共配置;
  2. 自动注入 process.env
    所有变量挂载到全局 process.env,全项目任意文件直接读取;
  3. 手动 parse 方法
    支持解析字符串格式的env内容,适合动态生成配置、读取远程配置文本;
  4. 必填变量校验
    线上服务启动前校验数据库、密钥等关键配置,缺失直接退出,避免运行时报错;
  5. 默认值兜底
    使用 process.env.KEY || 默认值,防止未定义变量返回undefined引发逻辑崩溃;
  6. 类型手动转换
    .env 中所有值都是字符串,数字/布尔需要手动 Number() / 判断 === "true"

6. 鸿蒙PC Node环境说明

dotenv 纯JS库,无 .node 二进制模块,无需 ohos-signpost 签名,直接 node 运行不会出现 permission denied;
常用于鸿蒙PC端Vite脚本、Node后端服务、打包构建脚本管理环境参数。

7. 开发规范

  1. .env.local 写入本机个性化端口、本地数据库密码,不提交仓库;
  2. 密钥、数据库密码严禁写死在代码;
  3. 线上生产环境优先使用服务器系统环境变量,优先级高于 .env.production
  4. 提交代码前检查 .gitignore,禁止上传带真实密码的env文件。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐