javascript - Hur importerar man ett lokalt monorepo TypeScript-paket i Angular-appar?


Jag försöker integrera ett Angular-projekt i ett PNPM workspace-monorepo som huvudsakligen innehåller en React-app. Här är katalogstrukturen

|-apps
|  |-react-app
|  |  |-package.json
|  |
|  |-angular-app (new)
|    |-package.json
|
|
|-packages
|  |-shared
|     |-index.ts
|     |-package.json
|
|-package.json
|-pnpm-workspace.yaml

Låt oss säga att det delade paketet har namnet @my-app/shared och att det har "main": "index.ts".

I react-app kan jag installera detta lokala paket och använda det direkt i min kod som följande

import { someValue } from '@my-app/shared';

Med viss justering av webpack-konfigurationen kan react-app inkludera den delade modulen i paketet korrekt.

Jag kunde dock inte lista ut hur man gör det i en Angular-app. Paketet kan installeras korrekt och allt, men när jag kör utvecklingsservern verkar det som att det inte inkluderar @my-app/shared i bundlen.

import { value } from '@my-app/shared';
console.log('xxx', value);

När jag inspekterade paketet verkar det som att Angular-kompilatorn inte bundlar modulen. Istället visar den bara platshållaren

Hur importerar man då ett lokalt paket i Angular? Jag tror att det behöver läggas till någon konfiguration i angular.json, men jag kunde inte hitta någon resurs. Alla källor där ute pekar på Angular Library genom ng generate library, vilket inte är vad jag letar efter eftersom @my-app/shared bara är enkla TypeScript-verktygsfunktioner.

Svar #1

Jag hade samma problem, jag undersökte varför, här är vad jag fann ⤵️

Det beror i princip på att TypeScript inte genererar några ts-filer som lagras i node_modules (du kan kolla det här).

När Angular kompilerar din applikation kompilerar det filer med TypeScript-kompilatorn: eftersom TypeScript upptäcker filen som ett externt bibliotek, exkluderas den, så ingenting genereras för denna fil.

Varför det fungerar med din react-app:

Jag antar att du var tvungen att ställa in allowTsInNodeModules till true, eller hur? ts-loader löser detta problem i webpack-pluginen, men @angular/cli implementerar ingen lösning.

Varför det fungerar med paths:

När TypeScript analyserar listan över filer att kompilera, kontrollerar det inte genom att titta på ett specifikt node_modules-mönster i filsökvägen:

  • Istället upprätthåller det en currentNodeModulesDepth-variabel (se här).
  • När vi använder paths ses currentNodeModulesDepth som lika med noll, eftersom TypeScript hittade en mappning och därför inte började titta på node_modules.
  • Så i det här fallet är det korrekt inkluderat i slutresultatet.

Observera att du kan förenkla din lösning med:

"paths": {
  "@my-app/*": ["../../packages/*"]
}

Så, du behöver inte lista alla beroenden, du kan använda * som en platshållare.

Svar #2

Jag har stött på samma problem. Tyvärr är det enda sättet jag har kunnat lösa det på genom att använda tsconfig-vägar.

Med antagande om ovanstående struktur:

|-apps
|  |-react-app
|  |  |-package.json
|  |
|  |-angular-app (new)
|    |-package.json
|    |-tsconfig.app.json
|
|
|-packages
|  |-shared
|     |-index.ts
|     |-package.json
|
|-package.json
|-pnpm-workspace.yaml

Observera filen på apps/angular-app/tsconfig.app.json

{
  "compilerOptions": {
    "paths": {
       "@my-app/shared": ["../../packages/shared/index.ts"]
    },
    // ... the rest of your options
  }
}

Detta har den olyckliga nackdelen att angular-appen måste kompilera om hela shared-paketet varje gång det sker en förändring. Enligt min åsikt är det bättre än inget. Om det finns ett bättre sätt, skulle jag gärna vilja veta det!