microsoft / microsoft/TypeScript
Design Meeting Notes, 2026-07-23
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.3k
- Merge medio
- 2g 4h
- PR unite (30g)
- 132
Descrizione
# JavaScript Emit API
https://github.com/microsoft/typescript-go/pull/4699
* How would something like "compile on save" be reimplemented?
* Idea: LSP has `didSave` event, clients can listen and trigger a custom emit command
* Does emit in LSP make sense?
* We do expect it for the playground.
* Sounds like yes.
* Source maps?
* Should add those too.
* What's the (internal) API look like?
* `program.emit(emitOnly?: EmitOnly)` - file system (including VFS if supplied), whole program, respects emit-blocking options like `noEmit`, `noEmitOnError`, ...
* Some weirdness in interaction, e.g. `emitDeclarationOnly`
* `program.emitToString(emitOnly?: EmitOnly)` - in-memory string results, whole program, respects emit-blocking options
* Basically a string over IPC
* `program.getJavaScriptEmit(files?: readonly DocumentIdentifier[])` - in-memory string results, specific file selection, bypasses emit-blocking options
* In-memory, does not respect `noEmit`, `emitDeclarationOnly`, etc.
* `program.getDeclarationEmit(files?: readonly DocumentIdentifier[])` - (same)
* And EmitOnly is:
```ts
export enum EmitOnly {
All = 0,
OnlyJs = 1,
OnlyDts = 2,
}
```
* May have to consider how pre/post transformations work here, plus dynamically contributed content - recall that Angular might have been looking for this with ngc?
# Content Mappers
* https://github.com/microsoft/TypeScript/issues/63800#issuecomment-4919145963
* https://github.com/microsoft/typescript-go/pull/4712
```json5
// tsconfig.json
{
"compilerOptions": {
// ...
},
"contentMappers": [
{
"package": "vue-content-mapper",
"extensions": [".vue"],
}
],
"include": ["src"]
}
```
```json5
// node_modules/vue-content-mapper/package.json
{
"name": "vue-content-mapper",
"version": "1.0.0",
"tsContentMapper": {
"exec": ["node", "dist/server.js"],
"compilerOptions": ["module", "jsx", "jsxImportSource"]
}
}
```
* What kind of versioning contract can we provide here?
* Stuff like LSP/Language Server Protocol doesn't provide a version per se - it's all capabilities based. Looks like same with AHP/Agent Host Protocol.
* Can keep version, but stick close to that model.
* Why does this have to be a protocol instead of something like a potentially long-running process? Feels heavy.
* Don't want to have multiple invocations of the mapper.
* Cascading resolution: we don't always know which files the program itself includes (you can end up with `.vue` files outside of the program)
* Also, we have long-running things like `--watch` and LSP where the program state will change over time.
* These transforms are all supposed to be idempotent.
* One issue is: are these able to react to *their* configurations, and invalidate their resolution?
* We can react to the package itself changing, but not currently to configuration.
* Maybe we need something about config files that the plugin can watch.
* Do we allow this only for `--moduleResolution bundler` or for `--moduleResolution nodenext` and others?
* It works across everything.
* Top-level `contentMappers` field - how does this work with tsconfig inheritance?
* It currently doesn't.
* This does have some invasiveness in our LSP implementation.
* Two different spans in a `.ts` file can map to the same span in a `.vue` file.
* Also, want these operations to coalesce occasionally.
* So operations at Line X Column Y now potentially have multiple results!
* So some operations default to the first result (hover), some concatenate results (go-to-definition).
* This doesn't completely subsume Volar - Volar can mask/fix up errors.
* But you can build an LSP over this to do this if desired.
* What are examples of that funky LSP behavior?
* Take for example:
```vue
import { ref, computed } from "vue";
const count = ref(0); const label = ref("clicks");
const label = computed(() => count.value === 1 ? "click" : "clicks");
const doubled = computed(() => count.value *2);
function increment(): void {
count.value++;
}
{{ count }} {{ label }}
doubled = {{ doubled }}
+1
- {{ n }}
high
```
* Kinda remaps to...
```ts
// SCRIPT SETUP START:
export default createComponent({
// ...
setup(props) {
// VERBATIM-ISH SCRIPT BLOCK:
const count = ref(0);
// ...
// GENERATED AFTER SCRIPT:
return {
count,
};
});
// GENERATED FROM TEMPLATE BLOCK:
function render(props)
const { count } = props;
// usage of count
count;
}
```
* A reference to `count` in the `` block has a definition that doesn't exist in the original `.vue` source, but also has a mapping to have a mapping back to a node that is not the "true" definition site.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Questo è un resoconto di una riunione di progettazione, non un’attività di implementazione, e non indica file sorgente né test. Inizia leggendo le pull request collegate 4699 e 4712 e il commento all’issue TypeScript indicato. Per considerarlo completo, sarebbe necessario concordare un’API di emissione JavaScript e l’ambito del protocollo content-mapper prima di poter definire il lavoro di implementazione.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- javascript, typescript
- Ambito
- compilers, devtools
- Tipo di issue
- Funzionalità
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Stato di attività
- Tranquilla
- Chiarezza
- Da chiarire
- Idoneità per principianti
- 25/100