add config module

This commit is contained in:
liuyi 2025-06-06 13:39:02 +08:00
parent b2189a8c5f
commit 88ba3f5a16
4 changed files with 149 additions and 1 deletions

View File

@ -1,8 +1,11 @@
import { DynamicModule, Module } from '@nestjs/common';
import { Configure } from '../config/configure';
@Module({})
export class CoreModule {
static forRoot(): DynamicModule {
static async forRoot(configure: Configure): Promise<DynamicModule> {
await configure.store('app.name');
return {
module: CoreModule,
global: true,

View File

@ -0,0 +1,92 @@
import { BadGatewayException, Global, Module, ModuleMetadata, Type } from '@nestjs/common';
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
import { useContainer } from 'class-validator';
import { omit } from 'lodash';
import { ConfigModule } from '@/modules/config/config.module';
import { Configure } from '@/modules/config/configure';
import { DEFAULT_VALIDATION_CONFIG } from '@/modules/content/constants';
import { CoreModule } from '../core.module';
import { AppFilter } from '../providers/app.filter';
import { AppInterceptor } from '../providers/app.interceptor';
import { AppPipe } from '../providers/app.pipe';
import { App, CreateOptions } from '../types';
import { CreateModule } from './utils';
export const app: App = { configure: new Configure() };
export const createApp = (options: CreateOptions) => async (): Promise<App> => {
const { config, builder } = options;
await app.configure.initialize(config.factories, config.storage);
if (!app.configure.has('app')) {
throw new BadGatewayException('App config not exists');
}
const BootModule = await createBootModule(app.configure, options);
app.container = await builder({ configure: app.configure, BootModule });
if (app.configure.has('app.prefix')) {
app.container.setGlobalPrefix(await app.configure.get<string>('app.prefix'));
}
useContainer(app.container.select(BootModule), { fallbackOnErrors: true });
return app;
};
export async function createBootModule(
configure: Configure,
options: Pick<CreateOptions, 'globals' | 'providers' | 'modules'>,
): Promise<Type<any>> {
const { globals = {}, providers = [] } = options;
const modules = await options.modules(configure);
const imports: ModuleMetadata['imports'] = (
await Promise.all([
...modules,
ConfigModule.forRoot(configure),
await CoreModule.forRoot(configure),
])
).map((item) => {
if ('module' in item) {
const meta = omit(item, ['module', 'global']);
Module(meta)(item.module);
if (item.global) {
Global()(item.module);
}
return item.module;
}
return item;
});
if (globals.pipe !== null) {
const pipe = globals.pipe
? globals.pipe(configure)
: new AppPipe(DEFAULT_VALIDATION_CONFIG);
providers.push({ provide: APP_PIPE, useValue: pipe });
}
if (globals.intercepter !== null) {
providers.push({
provide: APP_INTERCEPTOR,
useClass: globals.intercepter ?? AppInterceptor,
});
}
if (globals.filter !== null) {
providers.push({
provide: APP_FILTER,
useClass: AppFilter,
});
}
return CreateModule('BootModule', () => ({
imports,
providers,
}));
}

View File

@ -1,3 +1,4 @@
import { Module, ModuleMetadata, Type } from '@nestjs/common';
import deepmerge from 'deepmerge';
import { isNil } from 'lodash';
@ -39,3 +40,18 @@ export function isAsyncFunction<T, P extends Array<any>>(
const AsyncFunction = (async () => {}).constructor;
return callback instanceof AsyncFunction === true;
}
export function CreateModule(
target: string | Type<any>,
metaSetter: () => ModuleMetadata = () => ({}),
): Type<any> {
let ModuleClass: Type<any>;
if (typeof target === 'string') {
ModuleClass = class {};
Object.defineProperty(ModuleClass, 'name', { value: target });
} else {
ModuleClass = target;
}
Module(metaSetter())(ModuleClass);
return ModuleClass;
}

37
src/modules/core/types.ts Normal file
View File

@ -0,0 +1,37 @@
import { ModuleMetadata, PipeTransform, Type } from '@nestjs/common';
import { NestFastifyApplication } from '@nestjs/platform-fastify';
import { Configure } from '../config/configure';
import { ConfigStorageOption, ConfigureFactory } from '../config/types';
export type App = {
container?: NestFastifyApplication;
configure: Configure;
};
export interface CreateOptions {
modules: (configure: Configure) => Promise<Required<ModuleMetadata['imports']>>;
builder: ContainerBuilder;
globals?: {
pipe?: (configure: Configure) => PipeTransform<any> | null;
intercepter?: Type<any> | null;
filter?: Type<any> | null;
};
providers?: ModuleMetadata['providers'];
config: {
factories: Record<string, ConfigureFactory<RecordAny>>;
storage: ConfigStorageOption;
};
}
export interface ContainerBuilder {
(params: { configure: Configure; BootModule: Type<any> }): Promise<NestFastifyApplication>;
}