NestJS小技巧37-在NestJS中的动态模块加载:构建基于插件的系统

by 雪隐 from juejin.cn/user/143341...

文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可联系授权

原文链接

在现代化的后端开发中,伸缩和扩展是一个强健系统的特点。NestJS,基于它的组合式架构,为了可扩展应用提供了极好的功能。其中有一个极少被探索的技术,但是还很强大的功能就是动态模块加载。这个功能能够创建基于插件的系统,添加一个可扩展的新层到您的应用。在这篇文章中,我将在NestJS中探索动态模块加载。

为什么要使用动态模块加载?

设想一下,您正在构建一个电商平台。使用基于插件的系统可以允许第三方的开发者来添加一些特殊的功能比如各种支付接口或者运输计算器。基于这个构建,开发者创建插件作为独立的代码库,并且存储者能够轻松的通过提供插件Url来和这个平台进行组合。这使得核心功能可以在不更改核心平台代码的情况下进行动态扩展。比如,一个插件可能使用新的支付接口,通过在商店配置中指定插件的 URL,实现了无缝集成,使得应用能够动态加载和使用插件。

动态模块加载:概述

基于某种特定的配置,动态模块加载允许您的应用在运行时用来加载模块。当构建基于插件的系统,这是一个非常有用的功能,它使得第三方开发者能够通过编写插件来扩展您的应用。

制作插件

让我们来做一个简单的插件它通过log的方式来和我们打招呼。插件的代码,我放在了代码库,您可以随时查看。

js 复制代码
module.exports = {  
  hello: function() {  
    console.log('Hello from the dynamically loaded module!');  
    return "Hello From Plugin";  
  }  
};

在NestJS中实现动态加载

使用vm模块

我们可以使用vm模块来加载动态的模块:

ts 复制代码
import { Injectable } from '@nestjs/common';  
import axios from 'axios';  
import * as vm from 'vm';  
  
@Injectable()  
export class PluginLoaderService {  
  constructor(  
    @Inject('PLUGIN_URL') private readonly pluginUrl: string,  
  ) {}  
  
  async loadPlugin(): Promise<any> {  
    const response = await axios.get(pluginUrl);  
  
    const sandbox = {  
      module: { exports: {} },  
      console: console,  
    };  
    vm.createContext(sandbox);  
    const script = new vm.Script(response.data, { filename: 'plugin-module.js' });  
    script.runInContext(sandbox);  
  
    return sandbox.module.exports;  
  }  
}

这里,我首先创建了一个对象的沙箱,然后通过vm.createContent创建了新的上下文,使用vm.Script把插件代码编译成脚本,并且在沙箱内使用script.runInContext来执行这个脚本。这将使用插件中导出的 hello 函数填充 sandbox.module.exports,然后我们将其返回。

NestJS 模块包装插件

我们能够创建一个NestJS模块,它包装了插件,为我们的应用提供一个干净的接口。

ts 复制代码
import { Module, DynamicModule } from '@nestjs/common';  
import { PluginLoaderService } from './plugin-loader.service';  
  
@Module({})  
export class PluginModule {  
  static loadPlugin(url: string): DynamicModule {  
    return {  
      module: PluginModule,  
      providers: [  
        {  
          provide: 'PLUGIN_URL',  
          useValue: url,  
        },  
        PluginLoaderService,  
      ],  
      exports: [PluginLoaderService],  
    };  
  }  
}

在这个PluginModule,我们定义了一个静态loadPlugin方法它返回一个DynamicModule(动态模块)。这个loadPlugin方法有一个URL参数,这个参数是插件代码的地址。这个URL通过自定义Provider提供了PluginLoaderService,并且PluginLoaderService被导出所以它能注入到我们应用的其他模块。

Plugin模块的用法

在您的NestJS应用中使用PluginModule,我们需要在另一个我们想用插件模块进行动态导入。

这里是一个例子:

ts 复制代码
import { Module } from '@nestjs/common';  
import { AppController } from './app.controller';  
import { AppService } from './app.service';  
import { PluginModule } from './plugin/plugin.module';  
  
@Module({  
  imports: [  
    PluginModule.loadPlugin(  
      'https://gist.githubusercontent.com/sushilm2011/b870db4f49e6d7351366f9b3c8ce4c86/raw/282311b1ff27cce24e7f842ab4ae2015de7f241d/plugin-module.js'  
    ),  
  ],  
  controllers: [AppController],  
  providers: [AppService],  
})  
export class AppModule {}

最后一步:使用hello方法

为了在controller或service中使用插件加载的功能,您需要注入PluginLoaderService并且使用loadPlugin方法来访问这个被加载的插件:

ts 复制代码
import { Controller, Get } from '@nestjs/common';  
import { PluginLoaderService } from './plugin/plugin-loader.service';  
  
@Controller()  
export class AppController {  
  constructor(private readonly pluginLoaderService: PluginLoaderService) {}  
  
  @Get()  
  async getHello() {  
    const plugin = await this.pluginLoaderService.loadPlugin();  
    const greeting = plugin.hello();  
    return greeting;  
  }  
}

在浏览器中输入http://localhost:3000/访问nestjs服务,来看这个hello是否执行。本章代码

总结

NestJS 中的动态模块加载功能是增强应用可扩展性和可伸缩性的强大工具。通过利用这一功能,您可以为基于插件的系统创造一个肥沃的土壤,使第三方开发者能够为核心应用的功能做出贡献并进行扩展。本文中讨论的实际示例仅揭示了动态加载模块所具有的巨大潜力的冰山一角,为一个强大而繁荣的插件生态系统奠定了基础。

希望这次探索能激发一些关于如何在您的 NestJS 项目中利用动态模块加载的想法,最后别忘了,如果这篇文章对您们有帮助,请记得点赞和评论🙏!

相关推荐
逆旅行天涯3 分钟前
【Threejs】从零开始(六)--GUI调试开发3D效果
前端·javascript·3d
m0_7482552625 分钟前
easyExcel导出大数据量EXCEL文件,前端实现进度条或者遮罩层
前端·excel
长风清留扬1 小时前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
web147862107231 小时前
C# .Net Web 路由相关配置
前端·c#·.net
m0_748247801 小时前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
飞的肖1 小时前
前端使用 Element Plus架构vue3.0实现图片拖拉拽,后等比压缩,上传到Spring Boot后端
前端·spring boot·架构
青灯文案11 小时前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
m0_748254881 小时前
DataX3.0+DataX-Web部署分布式可视化ETL系统
前端·分布式·etl
求知若饥1 小时前
NestJS 项目实战-权限管理系统开发(六)
后端·node.js·nestjs
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps