在 Node.js 项目中,使用 Express 框架时,配置开发环境和正式环境的环境变量是一个常见的需求。通过合理配置环境变量,可以避免在开发、测试和发布上线时修改代码,同时保证不同环境下的配置隔离。
以下是实现这一目标的详细步骤和最佳实践:
1. 使用 dotenv
管理环境变量
dotenv
是一个流行的 Node.js 库,用于从 .env
文件加载环境变量。通过 .env
文件,可以将环境变量与代码分离,方便管理。
安装 dotenv
npm install dotenv
创建 .env
文件
在项目根目录下创建 .env
文件,用于存储开发环境的环境变量:
# .env (开发环境)
NODE_ENV=development
PORT=3000
DATABASE_URL=mongodb://localhost:27017/dev_db
API_KEY=dev_api_key
创建 .env.production
文件
在项目根目录下创建 .env.production
文件,用于存储生产环境的环境变量:
# .env.production (生产环境)
NODE_ENV=production
PORT=80
DATABASE_URL=mongodb://prod_user:prod_password@prod_host:27017/prod_db
API_KEY=prod_api_key
在代码中加载环境变量
在项目的入口文件(如 app.js
或 index.js
)中加载环境变量:
const express = require('express');
const dotenv = require('dotenv');
// 根据 NODE_ENV 加载对应的 .env 文件
if (process.env.NODE_ENV === 'production') {
dotenv.config({ path: '.env.production' });
} else {
dotenv.config({ path: '.env' });
}
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.send(`当前环境: ${process.env.NODE_ENV}, 数据库地址: ${process.env.DATABASE_URL}`);
});
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
2. 使用 cross-env
设置环境变量
cross-env
是一个跨平台的工具,用于在命令行中设置环境变量。它可以确保在不同操作系统(如 Windows、macOS、Linux)上设置环境变量的行为一致。
安装 cross-env
npm install cross-env --save-dev
在 package.json
中配置脚本
在 package.json
中配置开发环境和生产环境的启动脚本:
{
"scripts": {
"start": "node app.js",
"dev": "cross-env NODE_ENV=development node app.js",
"prod": "cross-env NODE_ENV=production node app.js"
}
}
运行项目
-
开发环境:
npm run dev
此时会加载
.env
文件中的环境变量。 -
生产环境:
npm run prod
此时会加载
.env.production
文件中的环境变量。
3. 使用环境变量区分配置
在代码中,可以根据 process.env.NODE_ENV
的值动态加载不同的配置。例如:
创建配置文件
在项目中创建一个 config
文件夹,用于存放不同环境的配置文件:
// config/development.js
module.exports = {
port: 3000,
databaseUrl: 'mongodb://localhost:27017/dev_db',
apiKey: 'dev_api_key',
};
// config/production.js
module.exports = {
port: 80,
databaseUrl: 'mongodb://prod_user:prod_password@prod_host:27017/prod_db',
apiKey: 'prod_api_key',
};
动态加载配置
在代码中根据 NODE_ENV
加载对应的配置文件:
const express = require('express');
const config = require(`./config/${process.env.NODE_ENV || 'development'}`);
const app = express();
const PORT = config.port;
app.get('/', (req, res) => {
res.send(`当前环境: ${process.env.NODE_ENV}, 数据库地址: ${config.databaseUrl}`);
});
app.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}`);
});
4. 使用 Docker 管理环境变量
如果项目使用 Docker 部署,可以通过 Docker 的环境变量功能来管理不同环境的配置。
Dockerfile 示例
FROM node:16
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
ENV NODE_ENV=production
CMD ["npm", "run", "prod"]
docker-compose.yml 示例
version: '3'
services:
app:
build: .
ports:
- "80:80"
environment:
- NODE_ENV=production
- DATABASE_URL=mongodb://prod_user:prod_password@prod_host:27017/prod_db
- API_KEY=prod_api_key
5. 最佳实践
-
不要将敏感信息提交到版本控制:
- 将
.env
和.env.production
文件添加到.gitignore
中,避免敏感信息泄露。.env .env.production
- 将
-
使用默认值:
- 在代码中为环境变量设置默认值,避免因环境变量未定义导致程序崩溃。
const PORT = process.env.PORT || 3000;
- 在代码中为环境变量设置默认值,避免因环境变量未定义导致程序崩溃。
-
统一管理环境变量:
- 将所有环境变量集中管理,方便维护和扩展。
-
使用环境变量注入工具:
- 在 CI/CD 流程中,使用环境变量注入工具(如 GitHub Actions、GitLab CI)动态设置环境变量。
6. 总结
通过 dotenv
、cross-env
和动态加载配置的方式,可以在 Node.js 项目中实现开发环境和生产环境的环境变量隔离。这种方法可以避免在发布上线时修改代码,同时保证配置的安全性和灵活性。
dotenv
和 cross-env
是两个独立的工具,它们的功能不同,但可以配合使用以更好地管理环境变量。以下是它们的区别、使用场景以及如何配合使用的说明:
1. dotenv
的作用
dotenv
是一个用于从 .env
文件加载环境变量的工具。它可以将环境变量从代码中分离出来,存储在一个 .env
文件中,然后在运行时动态加载这些变量。
使用场景
- 当你需要将环境变量(如数据库连接字符串、API 密钥等)存储在文件中时。
- 当你希望避免将敏感信息硬编码在代码中时。
- 当你需要在不同环境中使用不同的配置时(如开发环境和生产环境)。
示例
// .env 文件
PORT=3000
DATABASE_URL=mongodb://localhost:27017/dev_db
// app.js
require('dotenv').config();
console.log(process.env.PORT); // 输出 3000
console.log(process.env.DATABASE_URL); // 输出 mongodb://localhost:27017/dev_db
2. cross-env
的作用
cross-env
是一个跨平台的工具,用于在命令行中设置环境变量。它的主要作用是解决不同操作系统(如 Windows、macOS、Linux)在设置环境变量时的兼容性问题。
使用场景
- 当你需要在命令行中动态设置环境变量时(如设置
NODE_ENV=production
)。 - 当你希望确保在不同操作系统上运行脚本时,环境变量的设置行为一致。
示例
// package.json
{
"scripts": {
"dev": "cross-env NODE_ENV=development node app.js",
"prod": "cross-env NODE_ENV=production node app.js"
}
}
运行以下命令:
npm run dev # 设置 NODE_ENV=development
npm run prod # 设置 NODE_ENV=production
3. dotenv
和 cross-env
的关系
dotenv
:用于从.env
文件加载环境变量。cross-env
:用于在命令行中设置环境变量。
它们的功能是互补的,可以单独使用,也可以配合使用。
单独使用场景
- 如果你只需要从
.env
文件加载环境变量,可以单独使用dotenv
。 - 如果你只需要在命令行中设置环境变量,可以单独使用
cross-env
。
配合使用场景
- 如果你既需要从
.env
文件加载环境变量,又需要在命令行中动态设置环境变量(如NODE_ENV
),则可以配合使用dotenv
和cross-env
。
4. 配合使用的示例
以下是一个典型的配合使用场景:
步骤 1:安装依赖
npm install dotenv cross-env
步骤 2:创建 .env
文件
# .env (开发环境)
PORT=3000
DATABASE_URL=mongodb://localhost:27017/dev_db
# .env.production (生产环境)
PORT=80
DATABASE_URL=mongodb://prod_user:prod_password@prod_host:27017/prod_db
步骤 3:配置 package.json
{
"scripts": {
"dev": "cross-env NODE_ENV=development node app.js",
"prod": "cross-env NODE_ENV=production node app.js"
}
}
步骤 4:在代码中加载环境变量
// app.js
require('dotenv').config({ path: `.env.${process.env.NODE_ENV || 'development'}` });
console.log(`当前环境: ${process.env.NODE_ENV}`);
console.log(`端口: ${process.env.PORT}`);
console.log(`数据库地址: ${process.env.DATABASE_URL}`);
步骤 5:运行项目
-
开发环境:
npm run dev
输出:
当前环境: development 端口: 3000 数据库地址: mongodb://localhost:27017/dev_db
-
生产环境:
npm run prod
输出:
当前环境: production 端口: 80 数据库地址: mongodb://prod_user:prod_password@prod_host:27017/prod_db
5. 总结
dotenv
:用于从.env
文件加载环境变量,适合管理静态配置。cross-env
:用于在命令行中设置环境变量,适合动态设置环境变量。- 配合使用:当需要同时管理静态配置和动态设置环境变量时,可以配合使用
dotenv
和cross-env
。
如果你只需要其中一种功能,可以单独使用;如果需要更灵活的环境变量管理,建议配合使用。如果有进一步的问题,欢迎继续讨论!