Динамическая загрузка модуля Typescript во время выполнения - PullRequest
0 голосов
/ 25 мая 2018

Я определил абстрактный BaseClass в проекте NodeJS Typescript, и у меня есть список производных классов, которые реализуют и расширяют это BaseClass.

// baseModule.ts
export abstract class BaseClass {
  constructor() {}
  abstract method(): void;
}

export interface ModuleConstructor<T extends BaseClass> {
  new (): T
}

export function createModule<T extends BaseClass>(type: ModuleConstructor<T>): T {
  return new type();
}

Я пытаюсь найти способпрограммно во время выполнения создайте экземпляр одного из этих классов.

Ограничение здесь заключается в том, что я хотел бы иметь возможность добавить новый файл myDerivedClass.ts в папку моего проекта и автоматически включить его в список.доступных модулей во время выполнения.

Рабочий процесс разработчика будет следующим: 1) создать новый файл myNewModule.ts 2) создать и экспортировать класс, расширяющий BaseClass 3) сохранить myNewModule.ts до ./myModules

// ./myModules/myNewModule.ts
export class MyModule extends BaseClass {
  constructor() {
    super()
  }

  method() {
    //Do something custom
  }
}

Поток времени выполнения (в идеале без необходимости перестраивать) будет 1) Пользователь выбирает из списка доступных модулей 2) createModule Функция Factory создает новый экземпляр выбранного модуля и передает его как экземпляр

// someOtherClass.ts

const modules = require('./myModules/*') //<- Something to this effect
import { BaseClass, createModule, ModuleConstructor } from './BaseClass'

export class SomeOtherClass {
  public mod: BaseClass
  constructor(mod: ModuleConstructor) {
    this.mod = createModule(mod)
  }
}

for (let m in modules) {
  console.log(modules[m].name);
}

let someObj = SomeOtherClass(modules[m]);
someObj.mod // <- instance of derived class.

1 Ответ

0 голосов
/ 25 мая 2018

Вот решение, которое я в конечном итоге использовал, возможно, есть более простой способ.

1) Создание функции динамического загрузчика модулей 2) Используйте модуль NodeJS fs для сканирования каталога, содержащего модули3) Итерация по каждому файлу и динамический импорт файла в массив

// BaseModule.ts
import * as path from 'path'
import { promisify } from 'utils'

const readdirAsync = promisify(fs.readdir);

export async function loadModules() {
  let files = await readdirAsync(path.resolve(__dirname, 'rel/path/to/modules'));
  let imports = await Promise.all(files.map(file => (
    import(path.resolve(__dirname, '..', './exchanges/brokers', file))))
  )

  // this next part will depend on how you're exporting within
  // the module. In my case, each module has an "export class"
  // statement. Typically you would "import { className } from 'moduleName'"

  let moduleNames: { [name: string]: number } = {};
  let modules: ModuleConstructor<BaseClass>[] = [];
  for (let i in imports) {
    Object.keys(imports[i]).forEach((key: string) => {
      moduleNames[key] = modules.length;
      modules.push(imports[i][key])
    })
  }
  return [moduleNames, modules];
}


// someOtherClass.ts
import { BaseClass, loadModules, ModuleConstructor } from './BaseClass'

export class SomeOtherClass<T extends BaseClass> {
  public mod: T
  constructor(mod: T ) {
    this.mod = mod;
  }
}

loadModules()
  .then(([moduleNames, modules]: [string[], ModuleConstructor<BaseClass>[]] => {

    // not necessary, but just for purpose of demonstration
    let names: string[] = Object.keys(moduleNames);
    let name = names[0]; // pick one of the module names

    // use the name dictionary as a lookup into the constructor array
    let someObj = SomeOtherClass(new modules[moduleNames[name]]);
    someObj.mod // <- instance of derived class.
  })
  .catch((err) => {
    console.log(err.message);
  });

После этого я понял, что пакет NPM systemJS обрабатывает динамический загрузчик.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...