angularcomponentsangular-universalangular-moduleng2-semantic-ui

Angular import works great in one module, but does not work in another one


I got an angular4 & Universal application with a app.module and a app.browser.module/app.server.module.

App.Module has all app configuration and bootstrap. app.browser.module call modules that are used in the browser, to avoid breaking the universal build.

Link for the project repo on Github

When I import an external lib (ng2-semantic-ui) into app.browser.module, the app does does not recognize ng2-semantic-ui directives, but when I import it into 'app.module' it does.

This is my modules structure:

app.module.ts

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

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { SuiModule } from 'ng2-semantic-ui';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
  ],
  imports: [
    BrowserModule.withServerTransition({appId: 'app.id'}),
    SuiModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.browser.module.ts

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

import { AppModule } from './app.module';
import { AppComponent } from './app.component';   
import { SuiModule } from 'ng2-semantic-ui';

@NgModule({
  imports: [
    BrowserAnimationsModule,
    AppModule,
    SuiModule,
  ],
  bootstrap: [AppComponent]
})
export class AppBrowserModule {}

When I import SuiModule inside app.module the app recognize its directives, but when I take it out to app.browser.module, it doesn't. Why?

The Error

compiler.es5.js:1690 Uncaught Error: Template parse errors:
'sui-sidebar' is not a known element:
1. If 'sui-sidebar' is an Angular component, then verify that it is part of this module.
2. If 'sui-sidebar' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("

P.S. BrowserAnimationsModule are recognized in the app when I import them inside app.browser.module.


Solution

  • Your problem came from the module hierarchy of Angular. What you are trying is to build a building and on the second floor you add a room (your about component), then you add a window on the third floor (semantic ui) and you want it added on your room on the second floor. In your case, you declare the about.component to your app.module and you try to use on your about.components some semantic components that you import later on on your app.browser.module when you import also the app.module.

    To fix it, you either have to move your component declarations to your app.browser.module:

    import { NgModule } from '@angular/core';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    
    import { AppModule } from './app.module';
    import { AppComponent } from './app.component';
    
    import { HomeComponent } from './home/home.component';
    import { AboutComponent } from './about/about.component';
    
    /*Code that breaks the NG APP when importing SUI on app.browser.module, but works well when imported on app.module*/
    import {SuiModule} from 'ng2-semantic-ui';
    
    @NgModule({
      imports: [
        BrowserAnimationsModule,
        AppModule,
        SuiModule,
      ],
      declarations: [HomeComponent,
                    AboutComponent],
      bootstrap: [ AppComponent ]
    })
    export class AppBrowserModule {}
    

    or you do it on your app.module:

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    
    import { AppComponent } from './app.component';
    
    import { FormsModule } from '@angular/forms';
    import { HttpModule } from '@angular/http';
    import { AppRoutingModule } from './app-routing.module';
    
    import { HomeComponent } from './home/home.component';
    import { AboutComponent } from './about/about.component';
    
    /*Code that breaks the NG APP when importing SUI on app.browser.module, but works well when imported on app.module*/
    import {SuiModule} from 'ng2-semantic-ui';
    
    
    @NgModule({
      declarations: [
        AppComponent,
        HomeComponent,
        AboutComponent
      ],
      imports: [
        BrowserModule.withServerTransition({appId: 'ngcli-universal-seed-app'}),
        FormsModule,
        HttpModule,
        AppRoutingModule,
        SuiModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    

    You can use the architecture you want (although is a good thing to stick to the one @angular proposes) as long as the page that is consuming a component has that component imported in his module (directly or via another module).

    Edit

    Searching for a solution on this problem, I found an interesting page about Angular Universal Server Side Rendering here.

    In the article I have found the link to a boilerplate that I found is better structured than the one you are using and up to date. You can find it here. I recommend you to use this one since is better structured and it works.

    Last I added your semantic-ui code to about page of this boilerplate, imported the module into their about.module, compiled the universal app and run it, everything works fine.

    I dropped for you the boilerplate with the working added code here

    To conclude, the problem was coming either from the boilerplate structure you were using or some dependency conflict when building. Also, I find the Google documentation on universal apps not complete and outdated.