typescript - Bygga angular med webpack importerar inte moduler korrekt
Jag har byggt en liten exempelapp för att visa detta problem. Det verkar som att när man importerar moduler i modulteckningen så importeras inte modulens deklarationer. Till exempel, när jag importerar browser-modulen importeras inte NgIf, NgFor osv. och när jag importerar NgSelect importeras ingen av dess scheman eller komponenter. Jag bygger appen utan att använda angular-cli eftersom jag för närvarande migrerar en app från angularjs till angular och att flytta den till att använda angular-cli skulle vara ett problem.
Jag har ställt in webpack-konfigurationen som
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,
}
}
}
och det angulära testprogrammet är
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.mall.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>
och min tsconfig är:
{
"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"
}
}
Så vitt jag kan se bygger jag Ivy-partialerna, men jag får felen:
NG0304: 'ng-select' är inte ett känt element (använt i 'AppComponent'-komponentens mall):
- Om 'ng-select' är en Angular-komponent, kontrollera då att den är en del av ett @NgModule där denna komponent är deklarerad.
- Om 'ng-select' är en webbkomponent, lägg då till 'CUSTOM_ELEMENTS_SCHEMA' till '@NgModule.schemas' för denna komponent för att undertrycka detta meddelande.
och
NG0303: Kan inte binda till 'ngModel' eftersom det inte är en känd egenskap hos 'ng-select' (använd i 'AppComponent'-komponentens mall).
- Om 'ng-select' är en Angular-komponent och den har inmatningen 'ngModel', kontrollera då att den är en del av en @NgModule där denna komponent är deklarerad.
- Om 'ng-select' är en webbkomponent, lägg då till 'CUSTOM_ELEMENTS_SCHEMA' till '@NgModule.schemas' för denna komponent för att undertrycka detta meddelande.
- För att tillåta vilken egenskap som helst, lägg till 'NO_ERRORS_SCHEMA' i '@NgModule.schemas' för denna komponent.
som om det inte är importerat. Förutom det fungerar Angular bra. Om jag lägger NgIf i imports kan jag använda det men det borde importeras från BrowserModule eller CommonModule.
Någon som har några idéer eftersom jag har spenderat 3 dagar på det här och är på väg att sticka kniven i min skärm?
Svar #1
Försök att lägga till i din modul 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));
Svar #2
Du behöver importera CommonModule från @angular/common i modulen där din komponent används. CommonModule tillhandahåller direktiv som *ngIf och *ngFor.
Öppna modul-filen där din komponent är deklarerad, vanligtvis app.module.ts eller en funktionell modul.
Lägg till CommonModule i importarrayen om det inte redan är importerat.
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 { }
Om du använder
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
...
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
som LidiyaParshina föreslog, försök då att ställa in din jitMode till @angular/compiler i webpack.config.ts på detta sätt:
new AngularWebpackPlugin.AngularWebpackPlugin({
'tsconfig': 'tsconfig.json',
//"compilerOptions": {},
"sourceMap": true,
// 'jitMode': true
'jitMode': '@angular/compiler'
})
Annars kan du få problem.
För röröversättningar i din app.module.ts bör du skriva:
...
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 {}
och i dina funktionsmoduler bör du använda:
...
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 {}
Hoppas det hjälper!
