如何从运行时已知的文件加载 Typescript 模块(在 angular2+electron 中)

How to load Typescript module from a file known at runtime (in angular2+electron)

我正在尝试写一些概念证明,以确定 "Angular2 in typescript + Electron" 是否会满足未来桌面应用程序项目的要求。

但我遇到了麻烦... 我是在努力实现不可能的目标还是有办法做到这一点?这是我的上下文:


短版:

我该怎么做运行:

@Injectable()
export class PluginManager {    
  getPluginComponentForEventType(eventtype: string): Type {
    //return is angular "Type", later consumed by Dynamic Loader
    var externalModule = require('../mtplugins/' + eventtype + 'plugin.ts');
    return externalModule.TheRenderer;
  }
}

没有出现此错误:

"../mtplugins/foorendererplugin.ts not declared as a dependency"

带上下文的长版本:

核心要求是一种 "dynamic frontend plugin system",我会这样称呼它。这意味着:我的 UI 的一部分必须在 运行 时可替换 - 但我不知道将提前插入那里的组件。

示例场景:

我的应用收到一个 "foo" 事件:

leEvent: { eventtype: 'foo', payload: '...' }

所以它会告诉它的插件管理器:嘿,我需要一个 UI 组件来渲染一个 'foo' 事件。

插件管理器搜索包含组件的'fooplugin.ts'文件从该文件动态加载组件class 和 returns 类型。如果现在没有foo插件,用户可以从插件市场下载这个文件到插件文件夹,然后再试。

我的应用程序然后使用 DynamicComponentLoader.loadIntoLocation 将这个动态加载的类型集成到 dom,然后告诉组件呈现(leEvent)。

这最后一部分在angular中动态加载组件没问题,我的痛点是插件管理器方法从文件加载class...到目前为止我得到的最好的东西是:

@Injectable()
export class PluginManager {    
  getPluginComponentForEventType(eventtype: string): Type {
    //return is angular "Type", later consumed by Dynamic Loader
    var externalModule = require('../mtplugins/' + eventtype + 'plugin.ts');
    return externalModule.TheRenderer;
  }
}

我 运行 我的 tsc 带有“--module commonjs”。

当我调用该方法时,它告诉我“../mtplugins/foorendererplugin.ts 未声明为依赖项”...好吧,我无法提前声明依赖项,因为它仅在 运行时间。


那么,有没有办法从仅在 运行 时间已知的文件中加载打字稿 classes? 在 Java 中,我想我会用类加载器来完成它,所以我觉得我需要打字稿的对应物 。我实际上认为我已经读过带有 commonjs 和 require() 的打字稿会支持这一点,所以也许这种机制和 angular 的 system.js 集成正在互相攻击?

我是 angular2、typescript、electron 和 node 的新手,所以如果我忽略了一些基本的东西,请原谅。


编辑

正如 Louy 所指出的,错误消息与打字稿无关。它是由 System.js...

抛出的

再次证明,花更多时间学习您想要使用的技术始终是一项不错的投资。事实上,我在这里犯了一个新手错误:混淆了不同的模块加载系统。我以为我必须使用 CommonJS 才能在 运行 时间加载外部模块,但是 运行 时间加载也得到了 System.js 的很好支持 - 这意味着:

而不是

require(..)

我只需要使用

declare var System: any; //System.js Loader
...
System.import('./app/' + eventtype+ 'plugin.js');

那么你所要做的就是让插件独立于应用程序核心的实际代码(因为这会导致模块混乱......并且无论哪种方式都是一种架构气味),而不是仅依赖于接口(Typescript ftw! ).

这就是您的可插拔 angular2 UI :)

所需的全部内容

为什么不制作一个对象字典呢?这样你就不会丢失类型。

// import all of them...
import pluginA from '../mtplugins/Aplugin.ts'

// add all here
const plugins: {[name: string]: /*typeof plugin*/} = {
  a: pluginA,
  // ...
}

// and then...

var externalModule = plugins[eventtype];