Как сделать условную загрузку угловым приложением?

Я пытаюсь загрузить свое угловое приложение в зависимости от условий. В основном у меня есть два модуля MobileModule а также WebModule который содержит компоненты пользовательского интерфейса веб и мобильных отдельно.

Я пытаюсь загрузить MobileModule если пользователь открыл приложение в мобильном браузере, в противном случае WebModule,

Вот мой main.ts источник.

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 { }

Вышеуказанный подход работает нормально с ng serve но когда я пытаюсь запустить его с помощью ng serve --aot Опция его выдачи ошибки в консоли Chrome.

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)  

Моя структура проекта

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

Я попробовал несколько вещей, чтобы условно загрузить приложение, но безуспешно. Любое предложение будет оценено.

1 ответ

Я думаю, что Angular 5 не поддерживает несколько корневых модулей, потому что в настоящее время работает AOT (Ahead of Time compilation). Кажется, он только компилирует первый модуль и его зависимости.

Обходной путь - иметь корневой модуль только для начальной загрузки, использовать Маршрутизатор с защитой и ленивую загрузку только нужного модуля внутри корневого модуля.

Рекомендации:

Добился условной загрузки модуля в main.ts используя fileReplacements в файле angular.json, создав объект в конфигурации, и в нем я добавил замены, как показано ниже:

"fileReplacements": [
    {
        "replace": "src/environments/environment.ts",
        "with": "src/environments/environment.lib.ts"
    },
    {
        "replace": "src/main.ts",
        "with": "src/main.lib.ts"
    }
]

Вышесказанное решило мою проблему.

Надеюсь, это кому-то поможет.

Спасибо...

После долгих исследований я обнаружил, что мы можем загружать только один модуль за раз. Что означает один корневой модуль на угловое приложение.

Однако, с момента угловой отложенной загрузки модулей, мы можем динамически загружать все функциональные модули. Следовательно, идея состоит в том, чтобы загрузить один корневой модуль, и в зависимости от условий вы можете загружать любой субмодуль динамически.

Давайте рассмотрим приведенный выше пример.

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 { }

Надеюсь, это поможет другим людям, которые хотели такого поведения в своем угловом приложении.

Другие вопросы по тегам