David Hubner
David Hubner

Reputation: 95

Building angular using webpack not importing modules correctly

I have build a small example app to show off this issue. It seems when importing modules in the module declaration it does import the modules declarations. For example when I import the browser module it does not import NgIf, NgFor etc etc and when I import NgSelect it does not import any of its Schema or components. I am building the app without using angular-cli as I am currently migrating an app from angularjs to angular and moving it to use angular-cli would be an issue.

I have set up the webpack config like

const path = require('path'),
AngularWebpackPlugin = require('@ngtools/webpack'),
webpack = require('webpack'),
HtmlWebpackPlugin = require('html-webpack-plugin'),
WebpackDevServer = require('webpack-dev-server');

module.exports = {
    entry: {
        'test': { import: "./app/app.module.ts", filename: 'js/[name].bundle.min.js' },
    },
    mode: 'none',
    output: {
        path: path.resolve(__dirname, "dist"),
        clean: true
    },
    resolve: {
        //extensions: ['.ts', '...'],
        extensions: ['.tsx', '.ts', '.js', '.mjs', '.json']
    },
    optimization: {
    },
    plugins: [
        new webpack.ProvidePlugin({
            moment: 'moment'
        }),
        new HtmlWebpackPlugin({
            title: 'Test',
            template: './app/index.hbs',
            cache: false,
            hash: true,
            inject: false
        }),
        new AngularWebpackPlugin.AngularWebpackPlugin({
            'tsconfig': 'tsconfig.json',
            //"compilerOptions": {},
            "sourceMap": true,
            'jitMode': true
        })
    ],
    module: {
        rules: 
            [
                { 
                    test: /\.hbs$/i, 
                    use: "handlebars-loader",
                    exclude: /node_modules/, 
                },
                {
                    test: /\.[jt]sx?$/,
                    loader: '@ngtools/webpack',
                     include: /app[\\/]/,
                    exclude: [ /node_modules/ ]                
                },
                {
                    test: /\.[cm]?js$/,
                    use: {
                      loader: 'babel-loader',
                      options: {
                        cacheDirectory: true,
                        compact: false,
                        plugins: ['@angular/compiler-cli/linker/babel'],
                      },
                      
                    },
                },
                {
                    test: /\.template\.html$/,
                    exclude: /node_modules/,
                    use: 
                        [
                            {
                                loader: 'raw-loader',
                                options: 
                                {
                                    esModule: false,
                                },
                            }
                        ],   
                }, 
                {
                    test: /\.css$/i,
                    exclude: /node_modules/,
                    use: 
                        [  
                            {
                                loader: 'css-loader',
                                options: {
                                    import: false,
                                    url: false,
                                    modules: false
                                }
                            }    
                        ]
                }
            ],
        },
        devServer: {
            static: {
              directory: path.join(__dirname, 'dist'),
              watch: true
            },
            host: "localhost",
            compress: true,
            port: 5000,
            server: 'https',
            open: true,
            liveReload: false,
            hot: true,
            client: {
                overlay: true,
                progress: true,
            }
          }
}

and the angular test app is

app.module.ts

import 'zone.js';

import { NgSelectModule } from '@ng-select/ng-select';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

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

platformBrowserDynamic().bootstrapModule(AppModule)  
  .catch(err => console.error(err));   

app.component.ts

import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core';

@Component({
    selector: 'app-root',
    template: require('./app.template.html'),
})
export class AppComponent implements OnInit {
    public source = [ { id: 1, name: "moo" }]
    public selected = null;

    ngOnInit(): void {
        console.log("YAY!");        
    }
}

app.template.html

<!DOCTYPE html>
<html lang="en">
<head>
    <title ng-bind="title">T.I.E.R</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta content="IE=edge, chrome=1" http-equiv="X-UA-Compatible" />
</head>
<body>
    <app-root></app-root>
    <script defer src="js/test.bundle.min.js?904b25da0a6807f141ae"></script>
</body></html>

and my tsconfig is:

{
    "compileOnSave": false,
    "compilerOptions": {
      "baseUrl": "./",
      "outDir": "./dist/out-tsc",
      "resolveJsonModule": true,
      "forceConsistentCasingInFileNames": true,
      "strict": false,
      "noImplicitOverride": false,
      "noPropertyAccessFromIndexSignature": false,
      "noImplicitReturns": true,
      "noFallthroughCasesInSwitch": true,
      "sourceMap": true,
      "declaration": true,
      "emitDecoratorMetadata": true,
      "downlevelIteration": true,
      "experimentalDecorators": true,
      "moduleResolution": "Node",
      "importHelpers": true,
      "target": "ES2022",
      "module": "ES2022",
      "useDefineForClassFields": false,
      "lib": [
        "ES2022",
        "dom"
      ]
    },
    "angularCompilerOptions": {
      "enableI18nLegacyMessageIdFormat": false,
      "strictInjectionParameters": true,
      "strictInputAccessModifiers": true,
      "strictTemplates": true,
      "compilationMode": "partial"
    }
  }

As far as I can tell I am building the Ivy partials but I am getting the errors:

NG0304: 'ng-select' is not a known element (used in the 'AppComponent' component template):

  1. If 'ng-select' is an Angular component, then verify that it is a part of an @NgModule where this component is declared.
  2. If 'ng-select' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

and

NG0303: Can't bind to 'ngModel' since it isn't a known property of 'ng-select' (used in the 'AppComponent' component template).

  1. If 'ng-select' is an Angular component and it has the 'ngModel' input, then verify that it is a part of an @NgModule where this component is declared.
  2. If 'ng-select' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
  3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.

as if it is not imported. Apart from that angular is working fine. If I put NgIf in imports I can use it but it should be imported from BrowserModule or CommonModule.

Anyone have any ideas because I have spent 3 days on this and am about to stab my monitor?

Upvotes: 3

Views: 604

Answers (2)

StepanZ
StepanZ

Reputation: 21

You need to import the CommonModule from @angular/common in the module where your component is used. The CommonModule provides directives like *ngIf and *ngFor.

Open the module file where your component is declared, usually app.module.ts or a feature module.

Add CommonModule to the imports array if it isn't already imported.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; // Import this to use *ngIf, *ngFor

import { YourComponent } from './your-component.component';

@NgModule({
  declarations: [
    YourComponent
  ],
  imports: [
    CommonModule  // Add this to ensure *ngIf and *ngFor work
  ]
})
export class YourModule { }

If you are using

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
...
platformBrowserDynamic().bootstrapModule(AppModule)  
  .catch(err => console.error(err));

as LidiyaParshina suggested then try to set your jitMode to @angular/compiler in webpack.config.ts like this:

        new AngularWebpackPlugin.AngularWebpackPlugin({
            'tsconfig': 'tsconfig.json',
            //"compilerOptions": {},
            "sourceMap": true,
//            'jitMode': true
            'jitMode': '@angular/compiler'
        })

Otherwise you could have a problems.

For pipe translations in your app.module.ts you should put:

...
import { CommonModule } from '@angular/common'; // Import this to use *ngIf, *ngFor
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
...
function HttpLoaderFactory(http: HttpClient):TranslateHttpLoader {
  return new TranslateHttpLoader(http, '../i18n/', '.json');
}

...
@NgModule({
  imports: [
    BrowserModule,
    NgbModule,
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      },
    }),
...
  ],
...
})
export class IsbAppModule {}

and in your feature modules you should use:

...
import { NgbNavModule } from '@ng-bootstrap/ng-bootstrap';
import { NgSelectModule } from '@ng-select/ng-select';
import { TranslateModule } from '@ngx-translate/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
...
@NgModule({
  imports: [
    CommonModule,
    NgbNavModule,
    NgSelectModule,
    NgbModule,
    TranslateModule.forChild(), <--- Put this line
...
  ],
...
})
export class IsbCompanyModule {}

Hope it helps!

Upvotes: 0

Lidiya Parshina
Lidiya Parshina

Reputation: 324

Try to add to your module app.module.ts schemas: [CUSTOM_ELEMENTS_SCHEMA]

import 'zone.js';

import { NgSelectModule } from '@ng-select/ng-select';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        NgSelectModule,
    ],
    providers: [
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    bootstrap: [AppComponent]
})
export class AppModule {
}

platformBrowserDynamic().bootstrapModule(AppModule)  
  .catch(err => console.error(err));   

Upvotes: 0

Related Questions