阿里云主机折上折
  • 微信号
Current Site:Index > Multi-environment variable configuration management

Multi-environment variable configuration management

Author:Chuan Chen 阅读数:20626人阅读 分类: 构建工具

The Necessity of Multi-Environment Variable Configuration Management

Modern frontend projects typically need to run in different environments, such as development, testing, staging, and production. Each environment may require different API endpoints, feature flags, log levels, and other configurations. Hardcoding these variables makes the code difficult to maintain and increases the likelihood of deployment errors. Through environment variable configuration management, flexible adaptation of a single codebase across different environments can be achieved.

Basic Webpack Environment Variable Configuration

Webpack provides the DefinePlugin to define global constants, which is the foundational method for environment variable management. In webpack.config.js:

const webpack = require('webpack');

module.exports = {
  // ...other configurations
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development'),
      'API_URL': JSON.stringify('https://dev.api.example.com')
    })
  ]
}

These variables can be accessed directly in the code:

console.log(process.env.NODE_ENV); // Outputs 'development'
fetch(`${API_URL}/users`).then(...)

Multi-Environment Configuration File Solution

A more professional approach is to create separate configuration files for each environment. A typical directory structure looks like this:

config/
  ├── dev.env.js
  ├── test.env.js
  ├── stage.env.js
  ├── prod.env.js
  └── index.js

Example content of dev.env.js:

module.exports = {
  NODE_ENV: '"development"',
  API_URL: '"https://dev.api.example.com"',
  DEBUG_MODE: true,
  AUTH_ENABLED: false
}

config/index.js serves as the unified entry point:

const env = process.env.NODE_ENV || 'development'
module.exports = require(`./${env}.env.js`)

Managing Sensitive Variables with dotenv

For variables containing sensitive information, use the dotenv-webpack plugin:

npm install dotenv-webpack --save-dev

Create a .env file in the project root:

API_KEY=your_api_key_here
DB_PASSWORD=secure_password

Webpack configuration:

const Dotenv = require('dotenv-webpack');

module.exports = {
  plugins: [
    new Dotenv({
      path: './.env', // Default path
      safe: true // Loads .env.example to check for required variables
    })
  ]
}

Environment Variable Injection Strategy

Dynamically inject variables based on the build environment:

// webpack.config.js
const envConfig = require('./config')

module.exports = (env) => {
  return {
    // ...other configurations
    plugins: [
      new webpack.DefinePlugin({
        'process.env': envConfig[env.NODE_ENV]
      })
    ]
  }
}

Example build commands:

{
  "scripts": {
    "build:dev": "webpack --env.NODE_ENV=development",
    "build:prod": "webpack --env.NODE_ENV=production"
  }
}

Type-Safe Environment Variables

In TypeScript projects, define environment variable types:

// src/types/env.d.ts
declare namespace NodeJS {
  interface ProcessEnv {
    readonly NODE_ENV: 'development' | 'production' | 'test';
    readonly API_URL: string;
    readonly GA_TRACKING_ID?: string;
  }
}

Usage example:

const apiUrl: string = process.env.API_URL;
if (process.env.NODE_ENV === 'development') {
  console.log('Development mode');
}

Environment-Specific Code Optimization

Conditional compilation using environment variables:

if (process.env.NODE_ENV === 'production') {
  // Production-specific code
  enableAnalytics();
  disableDebugLogs();
} else {
  // Development-specific code
  mockAPIResponses();
}

Webpack's TerserPlugin can remove dead code based on environment variables:

optimization: {
  minimizer: [
    new TerserPlugin({
      terserOptions: {
        compress: {
          dead_code: true,
          global_defs: {
            'process.env.NODE_ENV': 'production'
          }
        }
      }
    })
  ]
}

Cross-Platform Environment Variable Handling

Handling differences in environment variables across operating systems:

// Unified boolean parsing
function parseBool(value) {
  if (typeof value === 'boolean') return value;
  if (typeof value === 'string') {
    return value.toLowerCase() === 'true';
  }
  return false;
}

// Usage example
const shouldLog = parseBool(process.env.ENABLE_LOGGING);

Runtime Environment Variable Injection

For scenarios requiring post-deployment variable modification, use a config.js in the public directory:

// public/config.js
window.__env__ = {
  API_URL: 'https://runtime.api.example.com',
  FEATURE_FLAGS: {
    newDashboard: true
  }
};

Include in HTML:

<script src="%PUBLIC_URL%/config.js"></script>

Access in code:

const apiUrl = window.__env__.API_URL || process.env.API_URL;

Environment Variable Validation

Add validation to ensure required variables exist:

// config/validator.js
function validateEnv(env) {
  const requiredVars = ['API_URL', 'AUTH_DOMAIN'];
  const missingVars = requiredVars.filter(varName => !env[varName]);
  
  if (missingVars.length > 0) {
    throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
  }
}

module.exports = validateEnv;

Use in Webpack configuration:

const validateEnv = require('./config/validator');
const envConfig = require('./config');

validateEnv(envConfig[env.NODE_ENV]);

Environment Variable Encryption

Encrypt sensitive variables:

// config/encrypt.js
const crypto = require('crypto');

function encrypt(text, key) {
  const cipher = crypto.createCipher('aes-256-cbc', key);
  let encrypted = cipher.update(text, 'utf8', 'hex');
  encrypted += cipher.final('hex');
  return encrypted;
}

function decrypt(encrypted, key) {
  const decipher = crypto.createDecipher('aes-256-cbc', key);
  let decrypted = decipher.update(encrypted, 'hex', 'utf8');
  decrypted += decipher.final('utf8');
  return decrypted;
}

module.exports = { encrypt, decrypt };

Usage example:

const { encrypt, decrypt } = require('./config/encrypt');
const encrypted = encrypt(process.env.DB_PASSWORD, 'secret-key');
const decrypted = decrypt(encrypted, 'secret-key');

Environment Variables and Feature Flags

Implement feature flags:

// src/features.js
export const features = {
  newCheckout: process.env.FEATURE_NEW_CHECKOUT === 'true',
  darkMode: process.env.FEATURE_DARK_MODE === 'true',
  experimentalAPI: process.env.FEATURE_EXPERIMENTAL_API === 'true'
};

// Usage example
if (features.newCheckout) {
  renderNewCheckout();
} else {
  renderLegacyCheckout();
}

Environment Variable Naming Conventions

Recommended naming conventions:

// Basic configurations
APP_NAME
API_BASE_URL

// Feature flags
FEATURE_[FEATURE_NAME]_ENABLED

// Third-party services
AWS_S3_BUCKET
GOOGLE_ANALYTICS_ID

// Security-related
AUTH0_CLIENT_ID
ENCRYPTION_KEY

Environment Variable Documentation

Generate documentation using JSDoc:

/**
 * @env {string} API_BASE_URL - Base API URL
 * @env {boolean} FEATURE_NEW_UI - Whether to enable the new UI
 * @env {number} MAX_API_RETRIES - Maximum API retry attempts
 * @env {string} SENTRY_DSN - Sentry error tracking DSN
 */

Environment Variables and Test Configuration

Special handling for test environments:

// jest.config.js
module.exports = {
  globals: {
    'process.env': {
      NODE_ENV: 'test',
      API_URL: 'http://localhost:3000/mock-api',
      TEST_USER: 'jest@example.com'
    }
  }
};

Environment Variable Debugging Tips

Debugging environment variable loading:

// Print all environment variables
console.log('Loaded environment variables:', {
  ...process.env,
  // Filter sensitive information
  API_KEY: process.env.API_KEY ? '***' : undefined
});

// Check variable sources
console.log('NODE_ENV from:', process.env.NODE_ENV);

Environment Variables and Docker Integration

Dockerfile example:

FROM node:16

ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

COPY . .
RUN npm install && npm run build

CMD ["node", "server.js"]

Build command:

docker build --build-arg NODE_ENV=development -t my-app:dev .

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.