当前位置: 首页 > article >正文

NestJS中使用DynamicModule构建插件系统

1. 介绍

在NestJS中,模块是组织代码的基本单元,它将相关的服务和控制器组织在一起。然而,在某些情况下,我们可能需要根据不同的条件动态加载模块,以满足不同的业务需求。这时,就可以使用DynamicModule了。

DynamicModule是NestJS提供的一种动态加载模块的方式,它允许我们在运行时动态地加载模块,下面就看看怎样通过DynamicModule构建插件系统。下面例子

  1. 创建了一个插件文件,其中定义了一些方法,用于动态加载;
  2. 创建了一个插件加载模块,用来加载上面的插件文件;
  3. 在主模块中,动态加载插件模块;
  4. 在主模块的controller中使用插件加载模块加载插件,并调用插件方法。

2. 创建插件文件

/tmp/test.js

module.exports = {
  helloworld: function () {
    console.log('load from dynamically loaded module!');
    return 'Hello World';
  },
  hello: function (name) {
    console.log('load from dynamically loaded module!');
    return 'Hello ' + name;
  },
};

3. 创建插件加载服务类

plugin-loader.service.ts

import { Inject, Injectable } from '@nestjs/common';
import * as path from 'path';
import * as vm from 'vm';
import * as fs from 'fs';

@Injectable()
export class PluginLoaderService {
  constructor(@Inject('PLUGIN_FILE') private readonly pluginFile: string) {}

  async loadPlugin(): Promise<any> {
    console.log('load plugin ...', path.resolve(this.pluginFile));

    const content = fs.readFileSync(path.resolve(this.pluginFile)).toString();

    const sandbox = {
      module: { exports: {} },
      console: console,
    };
    vm.createContext(sandbox);
    const script = new vm.Script(content, { filename: 'plugin-module.js' });
    script.runInContext(sandbox);

    return sandbox.module.exports;
  }
}
  • PluginLoaderService 用来根据传入的插件文件路径,使用vm加载之。

4. 创建插件加载模块

plugin.module.ts

import { DynamicModule, Module } from '@nestjs/common';
import { PluginLoaderService } from './plugin-loader.service';

@Module({})
export class PluginModule {
  static loadPlugin(file: string): DynamicModule {
    return {
      module: PluginModule,
      providers: [
        {
          provide: 'PLUGIN_FILE',
          useValue: file,
        },
        PluginLoaderService,
      ],
      exports: [PluginLoaderService],
    };
  }
}
  • PluginModule 用来加载插件文件,并返回一个DynamicModule,其中包含PluginLoaderService。
  • 在主模块中,可以通过调用PluginModule.loadPlugin(file)来动态加载插件文件。

5. 在主模块中使用插件加载模块

app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PluginModule } from './plugins/plugin.module';

import * as path from 'path';

@Module({
  imports: [
    PluginModule.loadPlugin('/tmp/test.js'),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
  • 在主模块中,通过调用PluginModule.loadPlugin(file)来动态加载插件文件,并将其作为模块导入。

6. 在控制器中使用插件

app.controller.ts

import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
import { PluginLoaderService } from './plugins/plugin-loader.service';

@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    private readonly pluginLoaderService: PluginLoaderService,
  ) {}

  @Get()
  async getHello() {
    const plugin = await this.pluginLoaderService.loadPlugin();
    console.log(plugin.helloworld());
    console.log(plugin.hello('kongxx'));

    return this.appService.getHello();
  }
}
  • 在控制器中,通过调用PluginLoaderService.loadPlugin()来加载插件,并调用插件的方法。

http://www.kler.cn/a/450251.html

相关文章:

  • es 3期 第18节-分页查询使用避坑的一些事
  • HTMLCSS:惊!3D 折叠按钮
  • 地址踩踏问题
  • ROS1入门教程6:复杂行为处理
  • 使用idea创建JDK8的SpringBoot项目
  • 信号仿真高级工程师面试题
  • EasyGBS国标GB28181公网平台P2P远程访问故障诊断:云端服务端排查指南
  • 微服务——技术选型与框架
  • PingCAP TiDB数据库专员PCTA认证笔记
  • 【杂谈】-为什么Python是AI的首选语言
  • C# winform 字符串通过枚举类型转成int类型的数据
  • 【全栈实战】基于 Vue3 + Wot Design Uni 动手封装组件
  • 低代码可视化-uniapp进销存销售表单-代码生成器
  • LeetCode 2605 从两个数字数组里生成最小数字
  • Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
  • Echarts的高级使用,动画,交互api
  • Vue3:uv-upload图片上传
  • LeetCode:101. 对称二叉树
  • Vue3 组件 view-shadcn-ui 2024.5.3 发布
  • 如何利用Java爬虫按关键字搜索苏宁易购商品
  • 精准提升:从94.5%到99.4%——目标检测调优全纪录
  • 搭建Docker Harbor仓库
  • Qt5 cmake引用private头文件
  • scrapy 融合selenium
  • web的五个Observer API
  • 过滤掉list中两个连续的元素