一、安装cross-env

pnpm add cross-env -D

1、解决方案一

直接设置公开变量:

{
  "dev": "cross-env NEXT_PUBLIC_APP_ENV=development next dev -p 4400",

  "dev:test": "cross-env NEXT_PUBLIC_APP_ENV=test next dev -p 4400",

  "build:prod": "cross-env NEXT_PUBLIC_APP_ENV=production next build"
}

然后:

process.env.NEXT_PUBLIC_APP_ENV

就会得到:

development
test
production

2、解决方案二(推荐)

命令脚本:

{
  "dev": "cross-env APP_ENV=development next dev",

  "dev:test": "cross-env APP_ENV=test next dev",

  "build:prod": "cross-env APP_ENV=production next build"
}

在nextjs项目的根目录下创建三个包含不同环境变量的文件分别是.env.development、.env.production、.env.test,其中:

.env.development文件内容:

APP_ENV=development
API_URL=http://localhost:3000

.env.test文件内容:

APP_ENV=test
API_URL=https://api.test.winpoker.com

.env.production文件内容:

APP_ENV=production
API_URL=https://api.winpoker.com

然后在 next.config.ts

import { existsSync, readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import type { NextConfig } from 'next';

function loadEnvFile(appEnv: string) {
  const envPath = resolve(process.cwd(), `.env.${appEnv}`);
  if (!existsSync(envPath)) return;

  for (const line of readFileSync(envPath, 'utf8').split('\n')) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) continue;

    const separatorIndex = trimmed.indexOf('=');
    if (separatorIndex === -1) continue;

    const key = trimmed.slice(0, separatorIndex).trim();
    let value = trimmed.slice(separatorIndex + 1).trim();

    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      value = value.slice(1, -1);
    }
    process.env[key] = value;
  }
}

const APP_ENV = process.env.APP_ENV ?? 'development';
loadEnvFile(APP_ENV);
const apiUrl = process.env.NEXT_PUBLIC_API_URL ?? '';
console.log('🚀 ~ :34 ~ apiUrl:', apiUrl);
const nextConfig: NextConfig = {
  /* config options here */
  env: {
    NEXT_PUBLIC_APP_ENV: APP_ENV,
    NEXT_PUBLIC_API_URL: apiUrl,
  },
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: `${apiUrl}/:path*`,
      },
    ];
  },
};

export default nextConfig;

重启开发服务器。

这里有连个需要注意的点

第一个就是解决

env: {
    NEXT_PUBLIC_APP_ENV: APP_ENV,
    NEXT_PUBLIC_API_URL: apiUrl,
  },

是解决两个来源打架的问题

使用命令pnpm dev或者pnpm dev:test

然后在通过process.env.NEXT_PUBLIC_API_URL和process.env.NEXT_PUBLIC_ENV访问环境变量,就会得到不同环境下的值。

二、根据 APP_ENV 注入对应的 API 地址

const config = {
  development: {
    apiUrl: 'https://dev-api.example.com',
  },
  test: {
    apiUrl: 'https://test-api.example.com',
  },
  production: {
    apiUrl: 'https://api.example.com',
  },
};

const APP_ENV = process.env.APP_ENV ?? 'development';

export default {
  env: {
    NEXT_PUBLIC_APP_ENV: APP_ENV,
    NEXT_PUBLIC_API_URL: config[APP_ENV].apiUrl,
  },
};

这样:

process.env.NEXT_PUBLIC_API_URL

才会随着:

pnpm dev
pnpm dev:test
pnpm build:prod

自动切换。

对于 Next.js 项目,我通常会把所有环境配置集中到 src/config/env.ts,并通过 APP_ENV → next.config.ts → NEXT_PUBLIC_* 这一层映射来管理,而不是在多个 .env 文件里维护同一套前端配置。这样类型更安全,也更容易排查问题。

三、配置端口以及开发启动打开默认浏览器

先安装:

pnpm add -D concurrently wait-on open-cli cross-env

作用分别是:

依赖 用途
concurrently 同时执行多个命令
wait-on 等待端口或服务启动
open-cli 自动打开浏览器
cross-env 跨平台设置环境变量

然后修改 package.json

{
  "scripts": {
   "dev": "concurrently \"next dev -p 4400\" \"wait-on tcp:127.0.0.1:4400 && open-cli http://localhost:4400\"",
    "dev:test": "concurrently \"cross-env APP_ENV=test next dev -p 4400\" \"wait-on tcp:127.0.0.1:4400 && open-cli http://localhost:4400\"",
}

启动:

pnpm dev

或者:

pnpm dev:test

服务启动完成后会自动打开默认浏览器访问:

http://localhost:4400

为了避免端口写两遍,推荐抽成变量:

{
  "scripts": {
    "dev": "cross-env PORT=4400 concurrently \"next dev -p %PORT%\" \"wait-on http://localhost:%PORT% && open-cli http://localhost:%PORT%\""
  }
}

但这在 Windows 和 macOS/Linux 上变量写法不同,所以实际项目里很多人直接写死:

{
  "scripts": {
    "dev": "concurrently \"next dev -p 4400\" \"wait-on http://localhost:4400 && open-cli http://localhost:4400\""
  }
}

最简单也最稳定。

如果你已经有开发、测试、生产环境脚本,我推荐这样整理:

{
  "scripts": {
    "dev": "concurrently \"next dev -p 4400\" \"wait-on tcp:127.0.0.1:4400 && open-cli http://localhost:4400\"",
    "dev:test": "concurrently \"cross-env APP_ENV=test next dev -p 4400\" \"wait-on tcp:127.0.0.1:4400 && open-cli http://localhost:4400\"",
    "build:test": "cross-env APP_ENV=test next build",
    "build:prod": "cross-env APP_ENV=production next build",
    "start:test": "cross-env APP_ENV=test next start -p 4400",
    "start:prod": "cross-env APP_ENV=production next start -p 4400",
    "build": "next build",
    "start": "next start",
  }
}

这样执行 pnpm devpnpm dev:test 时都会自动打开浏览器。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐