问题
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