You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Nest.js中实现自定义YAML配置变量的展开

Nest.js YAML配置变量未展开问题解决

问题重现

我有一个Nest.js应用,使用YAML配置文件管理嵌套结构的配置,而非扁平的.env文件。配置内容如下:

app:
  port: 3000
  url: http://localhost:${app.port}

配置加载逻辑:

import * as yaml from 'js-yaml';
import { readFileSync, join } from 'fs';

export default () => {
  return yaml.load(
    readFileSync(
      join(__dirname, 'env/config.local.yaml'),
      'utf8',
    ),
  ) as Record<string, any>;
};

AppModule中启用了expandVariables:

import configuration from './config/configuration';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
      expandVariables: true,
    }),
  ]
})
export class AppModule {}

通过ConfigService获取配置时,结果显示变量未展开:

App port: 3000, app url: http://localhost:${app.port}

原因分析

Nest.js的ConfigModule.forRoot中expandVariables选项仅对默认从.env文件加载的配置生效,自定义load函数返回的配置对象不会自动触发变量展开逻辑,因此YAML中的${app.port}无法被替换为实际值。

解决方案

方案一:利用@nestjs/config内置的expand函数

直接使用@nestjs/config提供的expand工具函数,在加载YAML后手动处理变量展开:

import * as yaml from 'js-yaml';
import { expand } from '@nestjs/config';
import { readFileSync, join } from 'fs';

export default () => {
  const rawConfig = yaml.load(
    readFileSync(join(__dirname, 'env/config.local.yaml'), 'utf8'),
  ) as Record<string, any>;
  // 手动调用expand处理变量插值
  return expand(rawConfig);
};

方案二:自定义变量替换逻辑

如果不想依赖内置工具,可以自己实现递归遍历配置对象的变量替换逻辑:

import * as yaml from 'js-yaml';
import { readFileSync, join } from 'fs';

// 递归替换配置中的${path}格式变量
const replaceConfigVariables = (config: Record<string, any>, rootConfig: Record<string, any>): Record<string, any> => {
  const processedConfig: Record<string, any> = {};

  for (const key in config) {
    if (typeof config[key] === 'object' && config[key] !== null) {
      processedConfig[key] = replaceConfigVariables(config[key], rootConfig);
    } else if (typeof config[key] === 'string') {
      // 匹配${xxx.xxx}格式的变量路径
      processedConfig[key] = config[key].replace(/\${([^}]+)}/g, (_, path) => {
        const pathSegments = path.split('.');
        let value = rootConfig;
        // 按路径层级获取对应值
        for (const segment of pathSegments) {
          value = value[segment];
          if (value === undefined) break;
        }
        return value ?? _; // 找不到则保留原变量字符串
      });
    } else {
      processedConfig[key] = config[key];
    }
  }

  return processedConfig;
};

export default () => {
  const rawConfig = yaml.load(
    readFileSync(join(__dirname, 'env/config.local.yaml'), 'utf8'),
  ) as Record<string, any>;
  return replaceConfigVariables(rawConfig, rawConfig);
};

方案三:使用支持变量插值的YAML解析库

比如使用Serverless生态中的YAML解析工具,它原生支持配置变量展开:

  1. 安装依赖:
npm install @serverless/utils
  1. 修改配置加载逻辑:
import { yamlParse } from '@serverless/utils';
import { readFileSync, join } from 'fs';

export default () => {
  const configContent = readFileSync(join(__dirname, 'env/config.local.yaml'), 'utf8');
  // Serverless的yamlParse自动处理变量插值,注意YAML中变量路径需改为${self:app.port}
  return yamlParse(configContent) as Record<string, any>;
};

对应的YAML配置需要调整变量写法:

app:
  port: 3000
  url: http://localhost:${self:app.port}

内容的提问来源于stack exchange,提问作者kurochenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:50:57