Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Angular5源码分析]SystemJsNgModuleLoader做了什么? #3

Open
fulvaz opened this issue Apr 25, 2018 · 0 comments
Open

[Angular5源码分析]SystemJsNgModuleLoader做了什么? #3

fulvaz opened this issue Apr 25, 2018 · 0 comments

Comments

@fulvaz
Copy link
Owner

fulvaz commented Apr 25, 2018

[Angular源码分析]SystemJsNgModuleLoader做了什么?

既然公司用了, 那也至少慢慢深入学习了

在AOT模式下, 无论是import或者Sytem.import得到的module都无法直接使用compiler编译得到结果, 为什么?

下面探究SystemJsNgModuleLoader源码

判断是否处于AOT模式

this._compiler instanceof Compiler

因为AOT模式下运行时没有compiler实例

在JIT模式下, 编译模板的代码如下

 private loadAndCompile(path: string): Promise<NgModuleFactory<any>> {
    let [module, exportName] = path.split(_SEPARATOR);
    if (exportName === undefined) {
      exportName = 'default';
    }

    return System.import(module)
        .then((module: any) => module[exportName])
        .then((type: any) => checkNotEmpty(type, module, exportName))
        .then((type: any) => this._compiler.compileModuleAsync(type));
  }

与我们的使用方法是一致的.

AOT模式下:

private loadFactory(path: string): Promise<NgModuleFactory<any>> {
    let [module, exportName] = path.split(_SEPARATOR);
    let factoryClassSuffix = FACTORY_CLASS_SUFFIX;
    if (exportName === undefined) {
      exportName = 'default';
      factoryClassSuffix = '';
    }

    return System.import(this._config.factoryPathPrefix + module + this._config.factoryPathSuffix)
        .then((module: any) => module[exportName + factoryClassSuffix])
        .then((factory: any) => checkNotEmpty(factory, module, exportName));
  }

可见二者使用System.import导入模块的路径是完全不同的

比如在读取./a/a.module#AModule时,

AOT下实际读取路径是: ./a/a.module.ngfactory
JIT: ./a/a.module

源码中有this._config.factoryPathPrefixthis._config.factoryPathSuffix这两个配置, 这两个属性控制了加载的实际路径

默认配置如下:

const DEFAULT_CONFIG: SystemJsNgModuleLoaderConfig = {
  factoryPathPrefix: '',
  factoryPathSuffix: '.ngfactory',
};

那基本可以下结论是绕过SystemJsNgModuleLoader懒加载module是黑科技, 因为import的路径可能会随着angular版本变化而变化..(而且也没法注入SystemJsNgModuleLoaderConfig)

然后另一件事情也很绝望

    return System.import(this._config.factoryPathPrefix + module + this._config.factoryPathSuffix)
        .then((module: any) => module[exportName + factoryClassSuffix])
        .then((factory: any) => checkNotEmpty(factory, module, exportName));

在读取到module后, 获取module的工厂的方式是module[exportName + factoryClassSuffix] ---- factoryClassSuffix也是个变量.

好吧, 总结一下, 如果我想作死绕过SystemJsNgModuleLoader懒加载module, 那实际的代码如下:

manualCompileAot() {
    System.import('./a/a.module.ngfactory').then((m) => {
      const factory = m['AModuleNgFactory'];
      const module = factory.create(this.injector);
      const r = module.componentFactoryResolver;
      const cmpFactory = r.resolveComponentFactory(AComponent);

      // create a component and attach it to the view
      const componentRef = cmpFactory.create(this.injector);
      this.mainContainer.insert(componentRef.hostView);
    });
  }

加载路径后添加了.ngfactory, 在获取module工厂时添加了NgFactory后缀

嗯, 我不作死.

结论

绕过SystemJsNgModuleLoader是作死

补充

  1. 这么说AOT模式下通过去掉Compiler包降低包大小, 在打包时编译全部模板
  2. 在需要使用相应模板时, 是通过获取工厂, 然后使用工厂创建相应的模板.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant