Frontend TypeScript (tsc-rs)
bext ne fait pas appel au tsc, SWC ou esbuild officiel pour son travail TypeScript. L'ensemble de l'interface TS/TSX → JS est tsc-rs, un compilateur TypeScript à partir de zéro écrit en Rust. Il réside dans son propre espace de travail (ts-rs sur disque, publié sous le nom de chaîne d'outils tsc-rs) et est consommé par bext à la fois en tant qu'ensemble de caisses de bibliothèque (en cours, pour le travail AST) et en tant que sous-processus --pipe. (pour l'émission TSX→JS réelle).
Cette page mappe l'espace de travail tsc-rs et documente exactement comment bext le connecte. Pour savoir où il se trouve dans un rendu, voir le Pipeline de rendu PRISM.
Pourquoi un compilateur personnalisé#
Le PRISM passe de compilation a besoin d'un véritable AST TypeScript : il plie les sous-arbres JSX statiques en concaténations de chaînes en inspectant les nœuds analysés et en épissant le texte source d'origine. Cela nécessite un analyseur :
- rapide — il s'exécute à chaque compilation de route froide, à l'intérieur de la requête chemin;
- intégrable — appelable en tant que bibliothèque Rust, pas en tant que sous-processus Node, pour les pass AST ; et
- convivial pour les outils — tsc-rs propose des modes de préservation **
(
preserveTypeAnnotations,preserveComments) et un émetteur préservant le texte source qui conserve le formatage d'origine pour les nœuds qui ne nécessitent aucune transformation.
tsc-rs se décrit comme un compilateur axé sur les outils plutôt que comme un clone tsc octet par octet. La parité signalée à la révision épinglée est
~92 % de la suite de tests du compilateur (92,2 %) et ~85 % de conformité (85,0 %) ; le vérificateur de type est intentionnellement incomplet ( bext utilise uniquement l'analyseur/classeur/émetteur, pas le vérificateur).
L'espace de travail tsc-rs#
Le compilateur est un pipeline par étapes classique, une caisse par étape :
source ─▶ scanner ─▶ parser ─▶ binder/symbols ─▶ checker/types ─▶ emitter ─▶ JS
(tokens) (SourceFile) (SymbolTable) (TypeId) (EmitOutput)
Caisses de base du compilateur#
| Caisse | Rôle |
|---|---|
tsc_rs_ast |
Tous les types de nœuds AST : SourceFile, Stmt / StmtKind, Expr / ExprKind, TypeNode, nœuds JSX, Span, Diagnostic, CompilerOptions. NodeId / SymbolId / TypeId sont u32 ; les identifiants ≤24 octets sont stockés en ligne ( CompactString ) et les énumérations de types de nœuds sont épinglées en taille (≤32 octets) par des assertions au moment de la compilation. |
tsc_rs_scanner |
Lexer — tokeniseurs de streaming ( TsScanner ) et par lots ( Scanner ) ; scan_all_with_comments() pour l'outillage. |
tsc_rs_parser |
Analyseur de descente récursive → SourceFile. API publique : parse(file_name, source) (JSX activé automatiquement pour .tsx / .jsx ) et parse_with_jsx(file_name, source, jsx_enabled). |
tsc_rs_symbols |
Binder - fait entrer l'AST dans un SymbolTable avec un ScopeGraph et un ReferenceKind. Public : bind(file) -> SymbolTable. |
tsc_rs_types |
Tapez système + inférence ( check, is_assignable, faits de rétrécissement du flux de contrôle). Non utilisé par bext. |
tsc_rs_resolver |
Résolution du module Nœud + Classique → ResolvedModule. |
tsc_rs_emitter |
Émetteur JS / source-map / .d.ts préservant le texte source. Public : emit, emit_strip_types, emit_strip_types_jsx(file, jsx, jsx_import_source) et variantes pour les consts/const-enum inter-fichiers inlining. Renvoie EmitOutput { javascript, source_map, declaration_file }. |
tsc_rs_project |
Gestion de tsconfig.json, orchestration multi-fichiers (rayon), .tsbuildinfo incrémentielle, références de projet ( -b ). |
Caisses d'outillage, de serveur et de satellite#
| Caisse | Rôle |
|---|---|
tsc_rs_cli |
Le binaire tsc-rs — compilation, les lecteurs --watch, --lsp et le mode --pipe bext. |
tsc_rs_server |
LSP JSON-RPC roulé à la main (diagnostics, survol, accès à la définition, références, complétions, renommage, formatage). |
tsc_rs_query |
QueryEngine — une façade d'outils unifiée sur analyseur/classeur/résolveur/vérificateur, utilisée par tsc_rs_project et le LSP. |
tsc_rs_incremental |
Métadonnées de construction incrémentielle + détection des modifications ChangeReason. |
tsc_rs_constraints |
Solveur expérimental de graphe de contraintes ("expliquer pourquoi le type X est Y"). |
tsc_rs_control_flow |
Primitives CFG expérimentales construites une fois lors de la liaison et réutilisées. |
tsc_rs_harness |
Infrastructure de test de base/Oracle (compilateur + tests LSP fourslash). |
tsc_rs_bench |
Benchmarks de critères pour scanner / analyseur / émetteur / pipeline. |
tsc_rs_openapi |
Génère des spécifications OpenAPI à partir des routeurs tRPC par analyse statique (Zod → JSON Schema). |
tsc_rs_analyze |
Analyse statique Monorepo - graphique d'importation, cycles, code mort, externes - analyse + résolution uniquement, aucune vérification. |
tsc_rs_wasm |
Liaisons wasm-bindgen exposant compile() / validate() pour une utilisation navigateur/bord/intégrée. |
Comment bext dépend de tsc-rs#
bext-core déclare quatre caisses tsc-rs comme dépendances git épinglées à une révision ( crates/bext-core/Cargo.toml ) :
tsc_rs_parser = { git = "https://github.com/bext-stack/ts-rs.git", rev = "651ef98c" }
tsc_rs_ast = { git = "https://github.com/bext-stack/ts-rs.git", rev = "651ef98c" }
tsc_rs_emitter = { git = "https://github.com/bext-stack/ts-rs.git", rev = "651ef98c" }
tsc_rs_symbols = { git = "https://github.com/bext-stack/ts-rs.git", rev = "651ef98c" }
La racine de l'espace de travail ( bext/Cargo.toml ) redirige ensuite ces dépôts git vers la caisse sœur locale avec un [patch] afin que le développement quotidien s'appuie sur l'arborescence de travail :
[patch."https://github.com/bext-stack/ts-rs.git"]
tsc_rs_ast = { path = "../ts-rs/crates/tsc_rs_ast" }
tsc_rs_parser = { path = "../ts-rs/crates/tsc_rs_parser" }
tsc_rs_emitter = { path = "../ts-rs/crates/tsc_rs_emitter" }
tsc_rs_symbols = { path = "../ts-rs/crates/tsc_rs_symbols" }
Conséquence pratique : édite ../ts-rs et reconstruit bext récupère immédiatement vos modifications. – la version épinglée n'a d'importance que pour les versions CI/release propres qui n'ont pas l'extraction sœur. Les autres caisses bext ( bext-turbopack, bext-server ) ne dépendent pas directement de tsc-rs - elles l'atteignent via bext-core pour les passes AST et via le binaire tsc-rs ** pour l'émission.
Deux modes d'intégration#
bext utilise tsc-rs de deux manières distinctes, et la division est l'élément clé à comprendre.
Mode 1 — caisses de bibliothèque (passes AST en cours)#
Les transformations sources qui doivent inspecter ou réécrire le code l’analysent avec tsc_rs_parser et parcourent les
nœuds tsc_rs_ast dans le même processus. Aucun de ces chemins n’émet de JavaScript : ils modifient la chaîne source ou construisent un manifeste annexe, puis transmettent le résultat au mode 2 pour la transpilation.
| Fichier bext | API tsc-rs utilisées | Ce que ça fait |
|---|---|---|
bext-core/src/transform/prism_compile.rs |
tsc_rs_parser::parse + tsc_rs_ast::{JsxElement, JsxAttribute, JsxChild, Expr, Stmt, …} |
Le Passe de compilation et de repliement PRISM. Transforme le JSX statique en concaténation de chaînes en remplaçant les plages d’octets du code source d’origine. |
bext-core/src/transform/react_semantics.rs |
tsc_rs_parser::parse + tsc_rs_symbols::{bind, ScopeGraph, ReferenceKind} |
Le seul consommateur du lieur : il construit un manifeste des portées et références pour la passe du compilateur React et la détection des limites RSC. |
bext-core/src/transform/prism_signals.rs |
tsc_rs_parser::parse + tsc_rs_ast |
La transformation JSX de "use signals". Voir Signaux. |
bext-core/src/transform/rsc_directives.rs |
tsc_rs_parser::parse |
Détecte et réécrit "use client" / "use server" pour le chemin RSC. |
bext-core/src/transform/{flow_extract,cache_directive,server_boundary,import_strip}.rs |
tsc_rs_ast::SourceFile déjà analysé |
Extraction des directives et suppression des imports ; reçoit l’AST de mod.rs::maybe_parse_ast à la demande, uniquement si le code source contient une chaîne déclencheuse. |
bext-core/src/framework/prism_data.rs |
tsc_rs_parser::parse (dans catch_unwind) |
Analyse les exports des routes : loader, action, metadata. Voir Données PRISM. |
bext-core/src/runtime/typescript.rs |
tsc_rs_parser::parse + tsc_rs_emitter::emit_strip_types |
strip_types() : le seul chemin interne au processus qui utilise directement l’émetteur, pour de courts extraits TypeScript qui ne justifient pas un aller-retour par le pipe. |
La règle d’analyse à la demande dans transform/mod.rs::maybe_parse_ast limite volontairement le coût : l’AST n’est construit que lorsque la source contient "use flow", "use server", "use client", "use cache" ou le nom d’un paquet interdit. Les fichiers qui n’en ont pas besoin évitent entièrement l’analyse.
Si vous extrayez ts-rs à côté de bext, toutes les modifications AST prennent effet sur le prochain cargo build — le [patch] dans la racine de l'espace de travail redirige automatiquement les dépôts git épinglés vers votre arborescence locale. Vous n'avez pas besoin de modifier la révision épinglée pendant le développement.
Mode 2 — le travailleur tsc-rs --pipe (le vrai TSX → JS)#
La transpilation réelle — TSX → CommonJS évaluée par V8 — est effectuée par un sous-processus de longue durée tsc-rs --pipe, géré par
TscRsPipeWorker dans bext-turbopack/src/direct.rs :
- une requête JSON délimitée par une nouvelle ligne par module :
{ filename, source, options }→{ output, imports, dynamic_imports, exports, source_map }; - Broches
PipeOptionstarget: es2022,module: commonjset JSX mode (reactclassique oureact-jsxautomatique lorsquejsx_import_sourceest défini ); - le travailleur enregistre le mtime du binaire et **réapparaît automatiquement lorsque vous reconstruisez tsc-rs **, afin que les modifications du frontend s'appliquent sans redémarrer bext ;
- un pool de travailleurs (
BEXT_TURBOPACK_PIPE_POOL_SIZE, par défaut 1) permet des modules distincts se transpirent en parallèle.
bext-turbopack::direct::transform_module est la façade ; les trois chemins de compilation du serveur bext ( ssr_compile_native,
rsc_server_compile_native, rsc_client_build_native ) y transitent tous, avec un sous-processus tsc-rs fork par appel comme solution de secours si le tuyauteur n'est pas disponible.
Le mode Pipe existe pour éviter fork+exec sur chaque module — une route froide avec des dizaines d'importations transitives paierait autrement une génération de processus par fichier.
Division du travail (la version en un paragraphe)#
tsc-rs le binaire effectue le vrai transpile TSX → JS (Mode 2). tsc-rs la bibliothèque (
tsc_rs_parser+tsc_rs_ast, plustsc_rs_symbolspour la sémantique React) est l'interface AST pour les bext. passes source en cours (Mode 1), qui réécrivent le texte source avant le binaire le transpile. Turbopack /le bundler fait le module résolution, marche de fermeture transitive et assemblage de paquets - et non la transformée TS par module. SWC est utilisé uniquement par le Passe Compilateur React, pas pour le décapage genres.
Références croisées#
- Pipeline de rendu PRISM — où les étapes d'analyse/pliage/émission s'exécutent dans une requête.
- Transformer le pipeline — tous les transformation de la source, dans l'ordre, avec la division AST-vs-string.
- Passe de compilation PRISM — le titre consommateur du tsc-rs AST.
- Référence de caisse — le côté bext de le graphe de dépendance.
- Indicateurs de construction et de fonctionnalités — comment le
Les fonctionnalités
turbopack/react-compilerbloquent ces chemins.