How to conditional bootstrap angular app?

只愿长相守 提交于 2019-12-10 11:28:19

问题


I am trying to bootstrap my angular 5 app based on conditions. Basically I have two modules MobileModule and WebModule which contains UI components of web and mobile separately.

I am trying to bootstrap MobileModule if user has opened the app in mobile browser otherwise WebModule.

Here is my main.ts source.

import { enableProdMode }         from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { environment }    from './environments/environment';

import { AppSettings }    from './app/core/app-settings';
import { MobileModule }   from './app/mobile/mobile.module';
import { WebModule }      from './app/web/web.module';


if (environment.production) {
    enableProdMode();
}


/*
 * Bootstrap mobile or web module based on mobile
 * or desktop client.
 */
if (AppSettings.isMobileDevice) {

  platformBrowserDynamic().bootstrapModule(MobileModule)
      .catch(err => console.log(err));
} else {

  platformBrowserDynamic().bootstrapModule(WebModule)
      .catch(err => console.log(err));
}

web.module.ts

import { BrowserModule }  from '@angular/platform-browser';
import { NgModule }       from '@angular/core';

import { AppRoutingModule } from './app-routing/app-routing.module';
import { CoreModule }       from '../core/core.module';
import { SharedModule }     from '../shared/shared.module';
import { AuthModule }       from './auth/auth.module';

import { SignupComponent }  from './auth/signup/signup.component';


@NgModule({
  imports: [
    BrowserModule,        // Support for common angular directives and services
    AppRoutingModule,     // Web routing controller module.
    CoreModule,           // Core modules
    SharedModule,         // Shared modules
    AuthModule,           // App authentication module (signup and login)
  ],
  declarations: [],
  providers: [],
  bootstrap: [SignupComponent]    // Bootstrap Signup component
})
export class WebModule { }

mobile.module.ts

import { BrowserModule }  from '@angular/platform-browser';
import { NgModule }       from '@angular/core';

import { AppRoutingModule } from './app-routing/app-routing.module';
import { CoreModule }       from '../core/core.module';
import { SharedModule }     from '../shared/shared.module';
import { AuthModule }       from './auth/auth.module';

import { SignupComponent }  from './auth/signup/signup.component';


@NgModule({
  imports: [
    BrowserModule,        // Support for common angular directives and services
    AppRoutingModule,     // Mobile app routing controller module
    CoreModule,           // Core modules
    SharedModule,         // Shared modules
    AuthModule,           // App authentication module (signup and login)
  ],
  declarations: [],
  providers: [],
  bootstrap: [SignupComponent]    // Bootstrap Signup component
})
export class MobileModule { }

The above approach is working fine with ng serve but when I try to run it using ng serve --aot option its throwing error in chrome console.

Uncaught Error: No NgModule metadata found for 'WebModule'.  
    at NgModuleResolver.resolve (compiler.js:20242)  
    at CompileMetadataResolver.getNgModuleMetadata (compiler.js:15195)  
    at JitCompiler._loadModules (compiler.js:34405)  
    at JitCompiler._compileModuleAndComponents (compiler.js:34366)  
    at JitCompiler.compileModuleAsync (compiler.js:34260)  
    at CompilerImpl.compileModuleAsync (platform-browser-dynamic.js:239)  
    at PlatformRef.bootstrapModule (core.js:5567)  
    at eval (main.ts:26)  
    at Object../src/main.ts (main.bundle.js:53)  
    at __webpack_require__ (inline.bundle.js:55)  

My project structure is

|-node_modules
|-src
   |-app
      |-core
      |-mobile
         |-mobile.module.ts
      |-shared
      |-web
         |-web.module.ts

I tried several things to conditionally bootstrap the app but no success. Any suggestion will be appreciated.


回答1:


I think Angular 5 does not support multiple root modules, because the way AOT (Ahead of Time compilation) currently works. It seems it only compiles the first module and its dependencies.

A workaround is to have a root module only for bootstrapping, and use Router with Guards, and lazy-loading only the desired module inside the root module.

References:

  • Related Issue: https://github.com/angular/angular-cli/issues/4624
  • Lazy-Loading Modules: https://angular.io/guide/lazy-loading-ngmodules



回答2:


After a lot research I found that we can only bootstrap single module at a time. Which means single root module per angular app.

However, since the time of angular lazy loading of modules we can load all feature modules dynamically. Hence, the idea is to load one root module and based on conditions you can load any sub-module dynamically.

Let's consider above example.

import { enableProdMode }         from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { environment }    from './environments/environment';
import { AppModule }      from './app/app.module';


if (environment.production) {
    enableProdMode();
}


/*
 * Bootstrap single root module
 */
platformBrowserDynamic().bootstrapModule(AppModule)
      .catch(err => console.log(err));

app.module.ts

import { BrowserModule }  from '@angular/platform-browser';
import { NgModule }       from '@angular/core';
import { RouterModule, Routes }     from '@angular/router';

import { CoreModule }       from '../core/core.module';
import { SharedModule }     from '../shared/shared.module';

import { AppComponent }  from './app.component';


const isMobileDevice = true; // Mobile device condition    


const routes: Routes = [
  {
    path        : 'app',
    loadChildren: isMobileDevice ? './mobile/mobile.module#MobileModule' : './web/web.module#WebModule'    // Conditionally load mobile or web module
  }
];


@NgModule({
  imports: [
    BrowserModule,        // Support for common angular directives and services
    RouterModule.forRoot(routes),
    CoreModule,           // Core modules
  ],
  declarations: [],
  providers: [],
  bootstrap: [AppComponent]    // Bootstrap Signup component
})
export class AppModule { }

Hope this helps to some other folks who wanted such behaviour in their angular app.



来源:https://stackoverflow.com/questions/49321475/how-to-conditional-bootstrap-angular-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!