Skip to content

import() feature doesn't work in production script to load modules or plugins dynamically #7703

Closed
@khaled-ansary

Description

@khaled-ansary

Bug Report or Feature Request (mark with an x)

- [ ] bug report -> please search issues before submitting
- [ ] feature request

Versions.

$ ng -v
_ _ ____ _ ___
/ \ _ __ __ _ _ | | __ _ _ __ / | | | |
/ △ \ | '
\ / _ | | | | |/ _ | '
| | | | | | |
/ ___ | | | | (
| | || | | (| | | | || | | |
// __| ||_, |_,||_,|| _|||
|___/
@angular/cli: 1.4.1
node: 6.10.0
os: win32 x64
@angular/animations: 4.3.6
@angular/common: 4.3.6
@angular/compiler: 4.3.6
@angular/core: 4.3.6
@angular/forms: 4.3.6
@angular/http: 4.3.6
@angular/platform-browser: 4.3.6
@angular/platform-browser-dynamic: 4.3.6
@angular/router: 4.3.6
@angular/upgrade: 4.3.6
@angular/cli: 1.4.1
@angular/compiler-cli: 4.3.6
@angular/language-service: 4.3.6
typescript: 2.4.2

node --version
v6.10.0

Repro steps.

I am developing a plugin based app where plugins are loading dynamically. At the beginning, the plugins are unknown by the app i.e. the plugins are stored in a folder in the app. Now, I tried to load the plugin modules dynamically using import() method and compile to load the module and entryComponents using the following code.

export class DynamicComponent {    
        injector: Injector;
        compiler: Compiler;
        @ViewChild('container', {read: ViewContainerRef}) 
        container: ViewContainerRef; 
        componentRef: any; 

        constructor(private compFactoryResolver: ComponentFactoryResolver, injector: Injector,
            private apiService: apiService) {

            this.injector = ReflectiveInjector.resolveAndCreate(COMPILER_PROVIDERS, injector);
            this.compiler = this.injector.get(Compiler);
        }
        addWidget(){

          apiService.getMoudleUrls().subscribe( module_url=>{
            let module_= import(module_url); //e.g './data-widget/data-widget.module'    
            module_.then(module_data =>{

            const keys = Object.getOwnPropertyNames( module_data );
            let moduleFactories = this.compiler.compileModuleAndAllComponentsSync(module_data[keys[1]]);
            const moduleRef = moduleFactories.ngModuleFactory.create(this.injector);
            const componentFactory = moduleFactories.componentFactories
             .find(e => e.selector === 'data-widget'); // find the entry component using selector       
            this.componentRef = this.container.createComponent(componentFactory, null, moduleRef.injector);

            const newItem: WidgetComponent = this.componentRef.instance; 
       },
      error=>{});
     }
    }

Example module and components of the plugins are

data-widget.module.ts

@NgModule({
  imports: [ ...,
  declarations: [DataWidget],
  exports: [DataWidget],    
  providers:    [],
   entryComponents: [DataWidget]               
})
export class DataWidgetModule {
    constructor(private widgetService: widgetService) {
      widgetService.register('weather', DataWidget);   
    }        
 }
data-widget.component:

@Component({
   selector: 'data-widget',
   templateUrl: 'data-widget.component.html'
   })
   export class DataWidget{}

its working perfectly in developing mode with typescript. The problem start in production generated script. I build the project using ng build --prod and get Javascript bundles.
I tried two process to transpile typescript to javascript

  1. plugins library in javascript format using https://github.com/jvandemo/generator-angular2-library. and
  2. build plugins using tsc command

Then I tried to add the plugins by providing the URLs of the index.js (generated by no 1. process) and also tried to give URL of data-widget.module.js (generated by no 2. process). But I am failed to load the plugins and getting an error like ERROR Error: Uncaught (in promise): Error: No NgModule metadata found for 'undefined'.

The log given by the failure.

ERROR Error: Uncaught (in promise): Error: No NgModule metadata found for 'undefined'.
Error: No NgModule metadata found for 'undefined'.
at t.resolve (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t.getNgModuleMetadata (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t._loadModules (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t._compileModuleAndAllComponents (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t.compileModuleAndAllComponentsSync (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at main.f86f90a36f2a8d2bd8a0.bundle.js:1
at t.invoke (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at Object.onInvoke (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t.invoke (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at r.run (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at t.resolve (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t.getNgModuleMetadata (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t._loadModules (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t._compileModuleAndAllComponents (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t.compileModuleAndAllComponentsSync (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at main.f86f90a36f2a8d2bd8a0.bundle.js:1
at t.invoke (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at Object.onInvoke (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t.invoke (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at r.run (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at c (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at c (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at polyfills.d1f049ba48d63f223a98.bundle.js:1
at t.invokeTask (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at Object.onInvokeTask (vendor.6269afbd95f1ed5b8299.bundle.js:1)
at t.invokeTask (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at r.runTask (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at o (polyfills.d1f049ba48d63f223a98.bundle.js:1)
at

Desired functionality.

Would like to load modules or plugins dynamically in production generated script as it loaded in developing mode.

Mention any other details that might be useful.

To make import() feature work, the following changes are necessary.

  1. typescript version 2.4
  2. in tsconfig.json file, change module: esnext

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions