0
votes

We have a shared const file that imports all of the components for out application, and two separate app modules for server side pre-rendering as posted below:

Debug works fine, but in release we get this error on this webpack command:

"node node_modules/webpack/bin/webpack.js --env.prod"

"ERROR in Type AppComponent app.component.ts is part of the declarations of 2 modules: AppModule in app.module.client.ts and AppModule in app.module.server.ts! Please consider moving AppComponent in app.component.ts to a higher module that imports AppModule in app.module.client.ts and AppModule in app.module.server.ts. You can also create a new NgModule that exports and includes AppComponent in app.component.ts then import that NgModule in AppModule in app.module.client.ts and AppModule in app.module.server.ts."

I know it has to do with declaring my components twice from the Shared file, but if I make the shared a module, and import it to server and client, the build breaks at runtime because it can't discern the angular components for some reason. I'm still learning with angular 4 so can someone help with how I am supposed to correctly set up a shared module into a server side and client side app module for a publish build?

app.module.shared.ts

import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { ButtonsModule } from '@progress/kendo-angular-buttons';
import { GridModule } from '@progress/kendo-angular-grid';
import { SliderModule, SwitchModule } from '@progress/kendo-angular-inputs';
import { TabStripModule } from '@progress/kendo-angular-layout';
import { AutoCompleteModule, DropDownListModule } from '@progress/kendo-angular-dropdowns';
import { DateInputsModule } from '@progress/kendo-angular-dateinputs';
import { InputsModule } from '@progress/kendo-angular-inputs';

import { MonacoEditorComponent } from './components/monaco-editor/monaco-editor.component';
import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
import { HomeComponent } from './components/home/home.component';
import { ClientsComponent } from './components/clients/clients.component';
import { EditConfigComponent } from './components/edit-config/edit-config.component';
import { AddClientComponent } from './components/add-client/add-client.component';
import { AddIntegrationComponent } from './components/add-integration/add-integration.component';
import { MsgInfoComponent } from './components/msg-info/msg-info.component';
import { AppFooterComponent } from './components/app-footer/app-footer.component';

import { ClientIntegrationService } from './client-integration.service';
import { UserService } from './user.service';
import { User } from './user';
import { Roles } from './roles';

import { RoleGuard } from './guards/role-guard';
import { ClientConfigurationGuard } from './guards/client-configuration-guard';
import { BaseMappingGuard } from './guards/base-mapping-guard';
import { AddIntegrationGuard } from './guards/add-integration-guard';
import { EditUserGuard } from './guards/edit-user-guard';



export const sharedConfig: NgModule = {
    bootstrap: [ AppComponent ],
    declarations: [
        AppComponent,
        NavMenuComponent,
        HomeComponent,
        ClientsComponent,
        EditConfigComponent,
        AddClientComponent,
    ],
    imports: [
        AppRoutingModule,
        FormsModule,
        HttpModule,
        ButtonsModule,
        GridModule,
        SliderModule,
        TabStripModule,
        AutoCompleteModule,
        DropDownListModule,
        SwitchModule,
        DateInputsModule,
        InputsModule
    ],
    providers: [ClientIntegrationService,
        UserService,
        User,
        RoleGuard,
        ClientConfigurationGuard,
        BaseMappingGuard,
        AddIntegrationGuard,
        EditUserGuard
    ]
};

app.module.client.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { GridModule } from '@progress/kendo-angular-grid';
import { bootloader } from '@angularclass/bootloader';
import { sharedConfig } from './app.module.shared';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';


@NgModule({
    bootstrap: sharedConfig.bootstrap,
    declarations: [sharedConfig.declarations],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        FormsModule,
        HttpModule,
        GridModule,
        ...sharedConfig.imports
    ],
    providers: [
        { provide: 'ORIGIN_URL', useValue: location.origin },
        sharedConfig.providers
    ]
})
export class AppModule{
}

export const platformRef = platformBrowserDynamic();

export function main() {
    return platformRef.bootstrapModule(AppModule);
}

bootloader(main);

app.module.server.ts

import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { sharedConfig } from './app.module.shared';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
    bootstrap: sharedConfig.bootstrap,
    declarations: sharedConfig.declarations,
    imports: [
        ServerModule,
        NoopAnimationsModule,
        ...sharedConfig.imports
    ],
    providers: sharedConfig.providers
})
export class AppModule {
}
2

2 Answers

1
votes

I think your problem comes basically from the [sharedConfig.declarations] part. It seems like an unusual way of implementing Server and Client modules. Have you tried having the declarations only on your AppModule? (what you declared in app.module.client.ts.

If it helps, here is my standard implementation using three different modules (AppModule, BrowserAppModule and ServerAppModule). I basically just declare everything on my AppModule and then simply import that module into the other two, along with whatever they each need. None of them declares anything, but both bootstrap the AppComponent.


app.module.ts

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        AppRoutingModule,
        CommonModule,
        SharedModule
    ],
    providers: [
        MyCustomService
    ],
    exports: [
        AppComponent
    ]
})
export class AppModule {
}

browser.app.module.ts

@NgModule({
    bootstrap: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        AppModule
    ]
})
export class BrowserAppModule {
}

server.app.module.ts

@NgModule({
    bootstrap: [
        AppComponent
    ],
    imports: [
        ServerModule,
        AppModule
    ]
})
export class ServerAppModule {
}
0
votes