javascript - 'package.json' er ikke under 'rootDir'
Jeg prøver å importere package.json i min TypeScript-applikasjon:
import packageJson from '../package.json';
Min tsconfig.json inneholder følgende:
{
"compilerOptions": {
"rootDir": "./src/"
"outDir": "./dist/",
"baseUrl": ".",
"resolveJsonModule": true
}
}
Problemet er at når jeg kompilere dette, får jeg
error TS6059: File '/path/to/package.json' is not under 'rootDir' '/path/to/app/src/'. 'rootDir' is expected to contain all source files.
Jeg er ikke sikker på om jeg forstår problemet, fordi både ./src/ og ./dist/ har samme overordnede .., så TypeScript kunne bare la import '../package.json' være, og det ville fungere fra enten rootDir eller outDir.
Uansett, jeg har prøvd følgende, med utilfredsstillende resultater:
- fjern
rootDir- kompileringen fungerer, mendistvil inneholdedist/src, noe jeg ikke vil - fjern
outDir- da blirsrcforurenset med.js-filer (og.js.maphvissourceMapvar sann) - legg til
@ts-ignore- kompileringen stopper filen som importerer../package.json
Hva er løsningen på denne begrensningen, for å beholde genererte filer i dist, og tillate import fra overordnet mappe til rootDir?
Svar #1
Dette er mulig, og det viser seg å være ikke vanskelig.
Grunnen til at løsningen ikke er åpenbar er fordi Typescript er avhengig av rootDir for å bestemme katalogstrukturen til outputen (se denne kommentaren fra Typescripts sjef), og kun kode som er inkludert i outputen eller i pakkens avhengigheter kan importeres.
- Hvis du setter
rootDirtil roten av prosjektet ditt, blirpackage.jsonsendt til roten avoutDirog kan importeres. Men da blir dine kompilertesrc-filer skrevet tiloutDir/src. - Hvis du setter
rootDirtilsrc, vil filer der inne kompileres til roten avoutDir. Men nå vil ikke kompilatoren ha et sted å avgipackage.json, så den gir "en feil fordi prosjektet ser ut til å være feilkonfigurert" (bossman's ord).
løsning: bruk separate Typescript-underprosjekter
Hvert Typescript-prosjekt er selvstendig, definert av sin egen tsconfig, med sin egen rootDir. Dette samsvarer med prinsippet om innkapsling.
Du kan ha flere prosjekter (f.eks. en hoved og et sett med biblioteker) hver i sin egen rootDir og med sin egen tsconfig. Avhengigheter mellom dem erklæres i den avhengiges tsconfig ved bruk av Typescript Project References.
Jeg innrømmer at begrepet "prosjekter" er et dårlig valg, da det intuitivt refererer til hele greia, men "moduler" og "pakker" er allerede tatt. Tenk på dem som underprosjekter så vil det gi mer mening.
For å løse ditt spesifikke problem, vil vi behandle src-mappen og rotmappen som inneholder package.json som separate prosjekter. Hvert av dem vil ha sin egen tsconfig.
Gi
src-mappen sitt eget prosjekt../src/tsconfig.json:{ "compilerOptions": { "rootDir": ".", "outDir": "../dist/", "resolveJsonModule": true }, "references": [ // this is how we declare a dependency from { "path": "../" } // this project to the one at the root dir` ] }Gi roten sin egen prosjekt.
./tsconfig.json:{ "compilerOptions": { "rootDir": ".", "outDir": ".", // if out path for a file is same as its src path, nothing will be emitted "resolveJsonModule": true, "composite": true // required on the dependency project for references to work }, "files": [ // by whitelisting the files to include, you avoid the default TS behavior, which "package.json" // will include everything, resulting in `src` being included in both projects (bad) ] }kjør
tsc --build srcog voilà!Dette vil bygge
src-prosjektet. Fordi det erklærer en referanse til rotprosjektet, vil det også bygge det, men kun hvis det er utdatert. Fordi rot-tsconfigen har samme katalog somoutDir, vil tsc rett og slett ikke gjøre noe medpackage.json, den ene filen det er konfigurert til å kompilere.
dette er flott for monorepoer
Du kan isolere moduler/biblioteker/underprosjekter ved å plassere dem i sin egen undermappe og gi dem sin egen tsconfig.
Du kan håndtere avhengigheter eksplisitt ved å bruke prosjektreferanser, samt modulere byggeprosessen:
Fra det lenkede dokumentet:
du kan forbedre byggetider betydelig
En etterlengtet funksjon er smarte inkrementelle bygg for TypeScript-prosjekter. I 3.0 kan du bruke
--build-flagget medtsc. Dette er effektivt et nytt inngangspunkt fortscsom oppfører seg mer som en byggeorkestrator enn en enkel kompilator.Å kjøre
tsc --build(tsc -bfor kort) vil gjøre følgende:- Finn alle refererte prosjekter
- du kan forbedre byggetidene betydelig
En etterlengtet funksjon er smarte inkrementelle bygg for TypeScript-prosjekter. I 3.0 kan du bruke
--build-flagget medtsc. Dette er effektivt et nytt inngangspunkt fortscsom oppfører seg mer som en byggekoordinator enn en enkel kompilator. Å kjøretsc --build(tsc -bfor kort) vil gjøre følgende:- Finn alle refererte prosjekter
- Finn ut om de er oppdaterte
- Bygg utdaterte prosjekter i korrekt rekkefølge
Ikke bekymre deg for rekkefølgen på filene du sender på kommandolinjen -
tscvil omorganisere dem om nødvendig slik at avhengigheter alltid bygges først.
håndheve logisk separasjon mellom komponenter
organiser koden din på nye og bedre måter.
Det er også veldig enkelt:
En rot
tsconfigfor delte alternativer og for å bygge alle underprosjekter med en enkeltsc --build-kommando (med--forcefor å bygge dem fra bunnen av)src/tsconfig.json{ "compilerOptions": { "outDir": ".", // prevents this tsconfig from compiling any files // we want subprojects to inherit these options: "target": "ES2019", "module": "es2020", "strict": true, ... }, // configure this project to build all of the following: "references": [ { "path": "./common" } { "path": "./projectA" } ] }Et "vanlig" bibliotek som blir hindret i å importere fra de andre delprosjektene fordi det ikke har noen prosjektreferanser
src/common/tsconfig.json{ "extends": "../tsconfig.json", //inherit from root tsconfig // but override these: "compilerOptions": { "rootDir": ".", "outDir": "../../build/common", "resolveJsonModule": true, "composite": true } }Et delprosjekt som kan importere common på grunn av den erklærte referansen.
src/projectA/tsconfig.json{ "extends": "../tsconfig.json", //inherit from root tsconfig // but override these: "compilerOptions": { "rootDir": ".", "outDir": "../../build/libA", "resolveJsonModule": true, "composite": true }, "references": [ { "path": "../common" } ] }
Svar #2
Vi kan sette resolveJsonModule til false og erklære en modul for *.json inne i typings.d.ts, som vil kreve JSON-filer som moduler, og det vil generere filer uten noen mappestruktur inne i dist-katalogen.
Monorepo-katalogstruktur
monorepo\
├─ app\
│ ├─ src\
│ │ └─ index.ts
│ ├─ package.json
│ ├─ tsconfig.json
│ └─ typings.d.ts
└─ lib\
└─ package.json
app/typings.d.ts
declare module "*.json";
app/src/index.ts
// Import from app/package.json
import appPackageJson from '../package.json';
// Import from lib/package.json
import libPackageJson from '../../lib/package.json';
export function run(): void {
console.log(`App name "${appPackageJson.name}" with version ${appPackageJson.version}`);
console.log(`Lib name "${libPackageJson.name}" with version ${libPackageJson.version}`);
}
run();
app/package.json-innhold
{
"name": "my-app",
"version": "0.0.1",
...
}
lib/package.json-innhold
{
"name": "my-lib",
"version": "1.0.1",
...
}
Nå, hvis vi kompilerer prosjektet ved å bruke tsc, vil vi få følgende dist-katalogstruktur:
app\
└─ dist\
├─ index.d.ts
└─ index.js
Og hvis vi kjører det med node ./dist, vil vi få utdataene fra både app og lib package.json-informasjonen:
node ./dist
App name "my-app" with version 0.0.1
Lib name "my-lib" with version 1.0.1
Du kan finne prosjektarkivet her: https://github.com/clytras/typescript-monorepo
Svar #3
Det finnes en ryddig tretrinns løsning med Node 16+ LTS og TypeScript 4.7+ for pakker som bruker ES-moduler i stedet for CommonJS.
Feltet "imports" i package.json definerer interne psevdopakker som kun kan importeres fra innenfor din faktiske pakke. Definer en intern importspesifikator, slik som #package.json i package.json:
{
"type": "module",
"exports": "./dist/index.js",
"imports": {
"#package.json": "./package.json"
}
}
Aktiver TypeScript-støtte for ES-moduler og JSON-importer i tsconfig.json:
{
"compilerOptions": {
"module": "nodenext",
// "moduleResolution" defaults to "nodenext", just made explicit here
"moduleResolution": "nodenext",
"resolveJsonModule": true,
}
}
Til slutt, importer #package.json fra TypeScript-modulen din:
import packageJson from '#package.json' assert { type: 'json' };
console.log(packageJson);
