html - Custom Library-komponenten är inte ett känt element, men appen kompileras och körs


Problemet

Mina HTML-filer varnar för att mina egna komponenter/pipes 'inte är ett känt element'. Men att bygga och köra applikationen fungerar som avsett, och de egna komponenterna/pipes fungerar. Dissonansen mellan att komponenterna fungerar men visas som fel är irriterande och kan vara svår att hantera. Jag vet att detta är en liten sak, men jag vill verkligen inte se fel i mina HTML-filer när det inte finns några fel.

Sammanfattning

Jag har två separata Angular-projekt; ett Angular-bibliotek som jag använder med min Angular-applikation. Biblioteket exporterar flera egna komponenter, pipes och tjänster som applikationen använder. Jag har inte publicerat detta bibliotek via npm, istället använder jag npm-link för att ge applikationen åtkomst till biblioteket. Detta verkar fungera eftersom alla tjänster/komponenter som definieras i mina applikationskomponenter fungerar och inte ger några felmeddelanden. Men så snart jag lägger något från mitt bibliotek i min template-fil blir den selektorn understruken och en varning visas.

Filerna

/*Library Module*/
@NgModule({
  declarations: [
    ThemeToggleComponent,
    // Other custom components/pipes
  ],
  exports: [
    ThemeToggleComponent,
    // Other components needed in templates files
  ]
})
export class MyCommonModule {}
  
/*
 * Public API Surface of my-common library
 */

export * from './lib/my-common.module';
/*
 * Many other components, services, pipes, etc etc
 */
export * from './lib/theme-toggle/theme-toggle.component';

/* Consuming Application module */
import { MyCommonModule } from 'my-common';

@NgModule({
  imports: [
    MyCommonModule,
  ],
  declarations: [
    MyComponent,
  ],
})
export class MyModule {}
/* Template of MyComponent, my.component.html */
<div>
  <my-theme-toggle (darkThemeSelected)="toggleTheme($event)"></my-theme-toggle>
</div>

Filen ovan kommer att ha alla rader som refererar till mina anpassade komponenter understrukna i rött med felmeddelandet 'my-theme-toggle' är inte ett känt element: ...om det är det, kontrollera att det är en del av modulen.

Försök att fixa

Jag har provat flera saker, men utan resultat

  • Att inte använda NPM-länk och bara kopiera biblioteket som skapats av ng-packagr till node-modulerna i min applikation
  • Bygger om och länkar om/startar om allt
  • Söker efter andra S.O-frågor: de flesta frågor handlar om byggfel eftersom importen/exporten faktiskt var felaktig.

Mina magkänslor

Jag tror att detta är ett problem med paths-kompilatoralternativet i tsconfig.json i den konsumerande applikationen. Genom all min forskning är detta det enda som dyker upp mer än något annat. Jag har för närvarande ingen sökväg inställd, eftersom allt fungerar. Mitt gemensamma bibliotek ser ut och fungerar som vilket annat node_module-bibliotek som helst, förutom detta problem.

Min andra tanke är att eftersom allt fungerar och körs, kan problemet vara att vs-code inte förstår importen, eller något i den stilen. Även om jag tror att detta är osannolikt.

Bakgrunden

Båda Angular-projekten är på version 9, rc7. Jag använder ng-packagr för att bygga mitt bibliotek. Jag använder Visual Studio Code, och vid tidpunkten för skrivandet är jag på den senaste utgåvan.

REDIGERA Detta problem försvann efter uppgradering till Angular 11, jag tror att flera av de andra problemen kan lösas med det, men detta känns som det bästa alternativet.

Svar #1

Det är ett importproblem, 99,99 % av tiden!

Jag har sett den här frågan ställas på lite olika sätt på olika sajter, både inom och utanför Stack Overflow. Jag kan säga att det troligen inte är ett problem med Angular Language Service.

Det finns tre skäl till att detta kan hända

  1. hur du har exporterat den saknade komponenten från biblioteket, t.ex. kontrollera om du:

    • Lade till export * from <your-component> i din public-api.ts-fil
    • Lade till din komponent i exports i Biblioteksmodulen som exporterar den
  2. hur du importerar Biblioteks-Komponenten, t.ex. kontrollera om du:

    • länkade biblioteket? cd /path/to/<ditt-bibliotek> && npm link
    • länkade applikationen?: cd /path/to/app && npm link <your-library>
    • lade till biblioteket NgModule(s) YourLibraryModule till imports:[] i din applikations huvud-NgModule
  3. Du kanske glömde att deklarera föräldrakomponenten i din App NgModule!!

    • Den här är enorm och nämns inte ofta. I Angular 10, 11 kan du glömma att lägga till Applikationskomponenten i declarations som refererar till den saknade bibliotekskomponenten, och språkservicen/kompilatorn kommer att klaga på att Bibliotekskomponenten saknas, men nämner inte att App-komponenten är exporterat på fel sätt!

Varför startar Angular Language Service om?

Ibland kan felet förändras när du startar om språktjänsten (t.ex. starta om VSCode). För scenario 3 som jag nämnde ovan blir felet:

Error: Cannot determine the module for class YourAppComponent in YourApp/src/app/components/your-app-component/your-app-component.component.ts! Add YourAppComponent to the NgModule to fix it

Och voilà!! Du ser det verkliga problemet och att fixa det är enkelt!

Svar #2

För att åtgärda problemet måste du för närvarande bygga med produktionsflaggan --prod, eftersom Angular Language Server i sitt nuvarande tillstånd inte fungerar med Ivy-byggnader. Som standard bygger den angular prod-byggnaden utan Ivy. Så när den byggs skapas en lib.metadata.json-fil. Detta är filen som språkservern använder för att få pluginet att fungera.

  1. I ditt bibliotek, skapa en build ng build <lib> --prod

    • lägg till --watch-flaggan för att övervaka förändringar
  2. I ditt bibliotek, skapa en länk cd dist sedan npm link

    • Jag skapade en package.json i dist-mappen och skapade länken där eftersom mitt bibliotek har flera moduler i det. Detta kommer att tillåta dig att göra

      • import { ModuleAComponent } from '<lib>/moduleA'
      • Jag skapade en package.json i dist-mappen och skapade länken där eftersom mitt bibliotek har flera moduler i det. Detta kommer att tillåta dig att göra
      • import { ModuleAComponent } from '<lib>/moduleA'

      • import { ModuleADirective } from '<lib>/moduleA'
    • Observera: Mappen du länkar måste ha en package.json, annars kommer den att använda projektets rot eftersom det är den närmaste package.json
    • Om du gör samma sak är vägarna nedan i korrekt format, annars kanske de inte är det och du kan försöka: "lib": ["./node_modules/lib", "./node_modules/lib/*"]
  3. I din applikation, länka till paketet npm link <lib>
  4. I din applikation, skapa en path i din tsconfig.base.json (Sökvägen kan vara olika beroende på hur du skapade din länk)
  5. I din applikation, starta om Angular-språkservern
{
  "compilerOptions": {
    "paths": {
      "lib/*": [
        "./node_modules/lib/*"
      ]
    }
  }
}

Relaterade artiklar