microsoft / microsoft/TypeScript

Resolving multiple package.json "main" fields

Aperta
#21,423 26 commenti 114 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Awaiting More Feedback Scenario: Monorepos & Cross-Project References Suggestion
Lingua principale
Go
Stelle
111k
Fork
14.3k
Merge medio
2g 4h
PR unite (30g)
132

Descrizione

TL;DR: A new compiler option mainFields for selecting multiple fields in package.json instead of just package.json#main.


There are lots of related issues to this one (which I link to below), but I want to focus on just this specific proposal.


Packages often look like this:

{
  "name": "my-package",
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js"
  "source": "src/index.ts"
}

Notice how we have multiple fields which specify multiple entry points. These entry points all refer to the same code, just in different compile states and configurations.

Many tools use these fields in order to find the entry point that they care about. For example, tools like Webpack and Rollup will use package.json#module in order to find ES modules. Other tools will use fields like package.json#source (or src) for local package development.

While these fields aren't part of the official Node module resolution algorithm. They are a community convention which has proven to be useful in lots of scenarios.

For TypeScript, one such scenario that this would be useful for is with multi-package repos or "monorepos". These are repositories where the code for multiple npm packages exist and are symlinked together locally.

/project/
  package.json
  /packages/
    /package-one/
      package.json
      /node_modules/
        /package-two/ -> ../../package-two (symlink)
    /package-two/
      package.json

Inside each package, you'll generally have a src/ directory that gets compiled to dist/

/package-two/
  package.json
  /src/
    index.ts
  /dist/
    index.js
    index.d.ts

Right now it is really painful to use TypeScript with one of these repos. This is because TypeScript will use the package.json#main to resolve to the packages dist folders. The problem with this is that the dist folders might not exist and if they do exist they might not be compiled from the most recent version of src.

To work around this today you can add a index.ts file in the root of each of your packages to point to the right location and make sure that the root index.ts file does not get shipped to npm.

/package-two/
  index.ts
  /src/index.ts
// package-two/index.ts
export * from './src/index'

It sucks that you need this file, and if you ever forget to create it in a new package, you'll revert back to really crap behavior.

If, instead of all that, TypeScript supported a new compiler option mainFields which looked like:

{
  "compilerOptions": {
    "mainFields": ["source", "main"]
  }
}

Note: Webpack has this same configuration option

You could add package.json#source (in addition to package.json#main) and resolve it to the right location locally.

The algorithm would look like this:

For each mainField:

  1. Check if the package.json has a field with that name
  2. If the package.json does not have the field, continue to next mainField
  3. If it field exists, check for a file at that location.
  4. If no file at that location exists, continue to the next mainField
  5. If the file exists, use that file as the resolved module and stop looking

I think this is the relevant code:

https://github.com/Microsoft/TypeScript/blob/b363f4f9cd6ef98f9451ccdcc7321d151195200b/src/compiler/moduleNameResolver.ts#L987-L1014

Related Issues:

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia dalla logica di risoluzione dei moduli in src/compiler/moduleNameResolver.ts alle righe collegate. Traccia come viene selezionato attualmente package.json#main e come vengono definite e propagate le opzioni del compilatore. Il lavoro è completato quando un’opzione mainFields può provare nell’ordine i campi del pacchetto elencati, ignorare i campi o i target mancanti e usare il primo target esistente.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
typescript
Ambito
compilers
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Specificata chiaramente
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.