前言

在现代前端开发中,应用程序通常需要在多种环境(开发、测试、Mock、生产等)中运行,每种环境都需要不同的配置参数。本文将详细介绍如何通过YAML配置文件实现Webpack环境变量的可配置化管理,使项目能够灵活适应各种部署场景。

一、YAML配置文件结构设计

我们采用分层配置方案,在项目根目录创建config文件夹,包含以下配置文件:

config/
  ├── default.yaml        # 基础默认配置
  ├── development.yaml    # 开发环境配置
  ├── mock.yaml           # Mock环境配置
  ├── production.yaml     # 生产环境配置
  └── prd.template.yaml   # 生产环境配置模板(含占位符)

配置文件示例

default.yaml (基础配置)

API_HOST: 'http://localhost:8000/api/v1'
AUTH_SELF_URL: 'http://localhost:8000/v1/account/users/self'
LOGIN_URL: 'http://localhost:8000/login'

development.yaml (开发环境)

extends: default
API_HOST: 'http://dev-api.example.com/api/v1'
AUTH_SELF_URL: 'http://dev-api.example.com/v1/account/users/self'
LOGIN_URL: 'http://dev-api.example.com/login'

mock.yaml (Mock环境)

API_HOST: '/mock/api'
AUTH_SELF_URL: '/account/users/self'
LOGIN_URL: 'http://localhost:8000/login'

prd.template.yaml (生产环境模板)

extends: default
API_HOST: '#{API_HOST}#'                  # 占位符,部署时替换
AUTH_SELF_URL: '#{AUTH_SELF_URL}#'        # 占位符,部署时替换
LOGIN_URL: '#{LOGIN_URL}#'                # 占位符,部署时替换

二、配置加载系统实现

1. 安装依赖

pnpm add -D yaml js-yaml dotenv

2. 核心配置加载器 (config-loader.js)

const yaml = require('js-yaml');
const fs = require('fs');
const path = require('path');

/**
 * 加载环境配置
 * @param {string} env - 环境名称 (development|production|test|mock)
 * @returns {Object} 合并后的配置对象
 */
function loadConfig(env = 'development') {
  // 加载默认配置
  const defaultConfig = yaml.load(
    fs.readFileSync(path.join(__dirname, 'config/default.yaml'), 'utf8')
  );

  let envConfig = {};
  try {
    const configPath = path.join(__dirname, `config/${env}.yaml`);
    let configContent = fs.readFileSync(configPath, 'utf8');
    
    // 生产环境占位符检查
    if (env === 'production') {
      const placeholderRegex = /\$\{[A-Z_]+\}|#\{[A-Z_]+\}#/;
      if (placeholderRegex.test(configContent)) {
        console.warn('⚠️ 生产环境配置中存在未替换的占位符');
      }
    }
    
    envConfig = yaml.load(configContent);
  } catch (e) {
    console.warn(`未找到 ${env} 环境特定配置,使用默认配置`);
  }

  // 合并配置(环境配置覆盖默认配置)
  return { ...defaultConfig, ...envConfig };
}

module.exports = loadConfig;

3. Webpack集成方案

const webpack = require('webpack');
const loadConfig = require('./config-loader');
const dotenv = require('dotenv');

// 初始化环境变量
dotenv.config();

// 根据NODE_ENV加载对应配置
const env = process.env.NODE_ENV || 'development';
const config = loadConfig(env);

module.exports = {
  // ...其他webpack配置
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify(env),
        API_HOST: JSON.stringify(process.env.API_HOST || config.API_HOST),
        AUTH_SELF_URL: JSON.stringify(process.env.AUTH_SELF_URL || config.AUTH_SELF_URL),
        LOGIN_URL: JSON.stringify(process.env.LOGIN_URL || config.LOGIN_URL),
      },
    }),
  ],
};

三、生产环境部署方案

1. Docker启动脚本 (docker-entrypoint.sh)

#!/bin/bash
set -e

# 配置处理
CONFIG_FILE="/app/config/prd.yaml"

# 初始化生产环境配置文件
if [ ! -f "$CONFIG_FILE" ]; then
  cp /app/config/prd.template.yaml "$CONFIG_FILE"
fi

# 设置默认环境变量
export API_HOST=${API_HOST:-"https://api.example.com/api/v1"}
export AUTH_SELF_URL=${AUTH_SELF_URL:-"https://api.example.com/v1/account/users/self"}
export LOGIN_URL=${LOGIN_URL:-"https://api.example.com/login"}

# 替换配置文件中的占位符
envsubst < "$CONFIG_FILE" > /tmp/prd.yaml
mv /tmp/prd.yaml "$CONFIG_FILE"

# 启动应用
exec "$@"

2. Dockerfile配置

FROM node:16-alpine

# 安装envsubst工具
RUN apk add --no-cache gettext

WORKDIR /app

# 复制配置文件
COPY config/ ./config/

# 安装依赖
COPY package*.json ./
RUN npm install

# 复制应用代码
COPY . .

# 设置入口脚本
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["npm", "start"]

四、多环境启动方案

1. 基础启动脚本配置

"scripts": {
  "start": "NODE_ENV=development webpack-dev-server --config webpack.config.js",
  "start:prod": "NODE_ENV=production webpack-dev-server --config webpack.config.js",
  "start:test": "NODE_ENV=test webpack-dev-server --config webpack.config.js",
  "start:mock": "NODE_ENV=mock webpack-dev-server --config webpack.config.js"
}

2. 跨平台方案(推荐)

"scripts": {
  "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js",
  "stage": "cross-env NODE_ENV=staging API_HOST=http://stage-api.example.com webpack-dev-server --config webpack.config.js",
  "build:prod": "cross-env NODE_ENV=production webpack --config webpack.config.js",
  "start:custom": "cross-env NODE_ENV=development API_HOST=http://custom-api.example.com webpack-dev-server --config webpack.config.js"
}

最佳实践建议

  1. 环境隔离:严格区分不同环境的配置,避免开发配置泄漏到生产环境
  2. 安全防护:生产环境配置应使用占位符,通过CI/CD管道或部署时注入
  3. 配置优先级:遵循 环境变量 > YAML配置 > 默认配置 的优先级顺序
  4. 文档记录:维护CONFIGURATION.md文档说明各环境配置项的含义和使用方法
  5. 版本控制:将config/目录纳入版本控制,但排除包含敏感信息的实际生产配置

此方案提供了从开发到生产的完整配置管理流程,既保证了开发时的灵活性,又确保了生产环境的安全性,是现代化前端项目的理想配置方案。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐