[v6] Rework the SWC setup: native Flow support and a modernized getJsTransformRules
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 5/5
- Tempo stimato
- Più di una settimana
- Idoneità per principianti
- 30/100
- Tipo di issue
- Refactoring
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- react-native, typescript
- Ambito
- build-system, tooling
Direzione di ricerca
Leggi gli entry point correnti getJsTransformRules, getSwcLoaderOptions e getFlowTransformRules, quindi verifica la limitazione del parser di Rspack descritta qui. Usa tests/integration e la coverage proposta con tester-app o config-matrix come punti di partenza per la validazione. Il lavoro è completo quando sono disponibili un percorso Flow v6 concordato, regole e opzioni aggiornate, documentazione e coverage per componenti, hook, enum e import inutilizzati.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Motivation
Re.Pack's SWC-native pipeline (getJsTransformRules → getSwcLoaderOptions + getFlowTransformRules) strips Flow types in a separate JavaScript pass (flow-remove-types behind @callstack/repack/flow-loader) before handing sources to builtin:swc-loader. SWC can now parse and strip Flow natively (jsc.parser.syntax: "flow", docs) — landed via swc#11685, shipped in @swc/core 1.15.21 (March 2026), with React Native parity fixes continuing through 1.15.46 (current). That makes the extra pass redundant — and it is already broken on modern React Native.
Part of #1414 (Roadmap to V6), which lists "use swc built in flow removal".
The current Flow pass is broken on RN ≥ 0.81
flow-remove-types only erases type annotations. It does not desugar Flow's component / hook syntax or Flow enums — the keywords stay behind, producing invalid JavaScript that SWC then refuses to parse. React Native ships component syntax in core since 0.81 (Libraries/Components/View/View.js:25: component View(), so getJsTransformRules() cannot build RN 0.81+. Reproduced with the workspace versions ([email protected], @swc/[email protected]):
flow-remove-types keeps the component keyword; swc parse of the output:
x Expected ';', '}' or <eof> (View.js:25)
swc one-pass { syntax: 'flow', jsx: true, enums: true, components: true }: OK
This goes unnoticed because nothing in this repo exercises getJsTransformRules — templates/ and all tester apps use @callstack/repack/babel-swc-loader. The Rspack migration guide does document getJsTransformRules + flow-loader as the setup to adopt, though (the Metro guide embeds the babel-swc-loader templates and is unaffected).
The extra pass is also the slowest part of the pipeline
Stripping all 455 .js files in react-native/Libraries (4.6 MB): flow-remove-types 659 ms (strip only, single-threaded JS) vs SWC flow mode 209 ms serial / 59 ms parallel — for strip plus full transform. Dropping the loader also removes a parse → print → source-map round trip per Flow module and the flow-remove-types + hermes-parser install footprint.
What SWC's Flow mode covers
Verified on @swc/[email protected] with { syntax: 'flow', jsx: true, enums: true, components: true }:
- Annotations,
import type,opaque type,declare,export type *— stripped (parity withflow-remove-types). component/hook— desugared correctly (flow-remove-typesemits invalid JS).- Flow enums — transpiled (
flow-remove-typespasses them through verbatim), but not to theflow-enums-runtimerepresentation — see behaviour notes below. enumsandcomponentsare not default — without them these constructs are parse errors.requireDirectivemust stay off to match our currentall: true(with it, files without a@flowpragma get no stripping at all).
Blocker: Rspack does not expose syntax: "flow"
True on every published version — verified on 1.6.0 and 2.0.0-alpha.1 (unknown variant 'flow', expected 'ecmascript' or 'typescript'), and latest 2.1.6 / main has no flow variant in SwcLoaderParserConfig either. Bumping to Rspack 2 does not fix it. Rspack main is already on swc_core = "72.0.0"; the gap is a Cargo feature: SWC gates the Flow parser behind base_flow (swc_core → swc/flow → swc_ecma_parser/flow), and rspack_loader_swc doesn't enable it. The upstream fix is one feature flag, the corresponding SwcLoaderParserConfig type, and a detectSyntax mapping decision for .flow / .js.flow. Precedent for this kind of ask: rspack#13843 (swc_core bump + exposing jsc.preserveSymlinks) was accepted and shipped.
Fallback if upstream is slow: route Flow-typed modules through a Re.Pack loader backed by standalone @swc/core, which has the feature compiled in. babelSwcLoader's lazyGetSwc already resolves rspack.experiments.swc → @rspack/core → @swc/core, so the plumbing exists. Costs the JS↔Rust boundary again, but stays single-pass and works on webpack too.
Behaviour differences vs Babel
- Unused value imports are elided by default. SWC's flow mode applies TypeScript-style import elision (
import Unused from './u'; console.log(1)→console.log(1)).jsc.transform.verbatimModuleSyntax: truefixes this — verified it preserves unused value imports while still strippingimport typeandtypespecifiers. Set it and pin with a regression test. - Flow enums don't use
flow-enums-runtime. SWC emits a TS-style object IIFE. Member access matches Flow semantics, but the runtime API (.members(),.cast(),.isValid(),.getName()) doesn't exist on the result. RN core doesn't call those methods today; needs a documented caveat (and a check when bumping RN). exportDefaultFromis unavailable undersyntax: "flow"(export v from './v'→ parse error), whilegetParserOptionsenables it for all.js(RN's preset includes@babel/plugin-proposal-export-default-from). Soflowcannot blanket-replaceecmascriptfor.js— keep it scoped to Flow-typed modules until SWC supports the combination.
Other issues in getSwcLoaderOptions / getJsTransformRules
Independent of Flow, worth fixing in the same pass:
developmentis tied to the JSX runtime, notmode.getJSCTransformOptionssetsdevelopment: jsxRuntime === 'classic', so with the defaultautomaticruntime dev builds always getjsxinstead ofjsxDEV(verified) — losing__source/__self, accurate component stacks, and "open in editor". RN's preset addsjsx-source/jsx-selfwheneverdev. Should followmode.- The six-branch
oneOfcollapses under Rspack 2.detectSyntax: 'auto'(new in 2.0.0) infers the parser from the extension, leaving only the sourcemaps-off-for-node_modulessplit;tsRules/tsxRulesare byte-identical today anyway. Unrecognized extensions map to{ syntax: 'typescript', tsx: true }, so.flowneeds an explicit branch either way. env.targets: { node: 24 }is a sentinel, not a target ("assume everything supported, re-add viaenv.include"). It works but drifts silently, and Rspack 2 derives loader targets from the top-leveltargetwhen unset. Re-deriveenv.include(16 entries) from the current RN preset and write down each inclusion/omission — e.g.transform-react-display-nameis missing from both SWC paths, and the preset's regenerator-gated trio (optional-catch-binding,nullish-coalescing,for-of) is dev+Hermes-only, so omitting it may be correct but should be a written decision.lazyImportsdefaults tofalse, while RN's preset defaultslazyto itslazy-importsallowlist.isModuleis never set (babelSwcLoadersets it from Babel'ssourceType;isModule: 'unknown'is probably right here).getSwcParserConfig(babelSwcLoader) andgetParserOptions(getSwcLoaderOptions) are near-duplicates with different answers (exportDefaultFrom). Fold into one shared helper.getCodegenTransformRuleskeeps its Babel pass —@react-native/babel-plugin-codegenhas no SWC equivalent — but the "must run before Flow stripping" ordering constraint deserves a re-check once SWC parses Flow natively.
babel-swc-loader
Stays as-is — it is the default in templates/ and every tester app, and it is correct by construction (it reads the project's real Babel config and only offloads transforms it can prove equivalent). Follow-up once Flow support is available: teach swc.ts to map transform-flow-strip-types / transform-flow-enums / syntax-hermes-parser to jsc.parser.syntax: 'flow' (+ enums, components), so RN core files go through SWC instead of falling back to Babel — the biggest remaining Babel fallback for a stock RN app.
Scope
Upstream
- Rspack: file the issue/PR enabling
base_flowinrspack_loader_swc, exposing the flow parser options inSwcLoaderParserConfig, and deciding thedetectSyntaxmapping for.flow - SWC: file the issue for
exportDefaultFromundersyntax: "flow"
Core
- Switch
getFlowTransformRulesfromflow-loaderto SWC-native Flow (or the@swc/core-backed fallback loader), keeping theFLOW_TYPED_MODULESinclude/exclude surface; setverbatimModuleSyntax: true - Decide the fate of
@callstack/repack/flow-loader(public export) — deprecate as escape hatch or drop in v6 - Rewrite
getJsTransformRulesondetectSyntax: 'auto', collapsing theoneOf - Drive
jsc.transform.react.developmentfrommode - Re-derive
env.includefrom the current RN preset; alignlazyImports/isModuledefaults - Fold
getSwcParserConfigandgetParserOptionsinto one helper - Drop the
flow-remove-typesdependency once nothing uses it
v5 patch (independent of v6)
- Stop
getJsTransformRulesemitting invalid JS forcomponent/hook/ enums on RN ≥ 0.81 — either the SWC path orbabel-plugin-syntax-hermes-parser+babel-plugin-transform-flow-enumsinflow-loader
Apps, tests, docs
- Add a tester-app variant or config-matrix entry that actually builds with
getJsTransformRules— this class of bug is invisible today -
tests/integrationcoverage forcomponent/hook/ Flow enums in anode_modulesdependency; regression test pinning unused-import preservation - Update
flow-loader,get-flow-transform-rules,get-swc-loader-options,get-js-transform-rulesdocs and the Rspack migration guide; note the minimum Rspack version in the v5 → v6 migration guide
Open questions
- Wait on upstream Rspack, or ship the
@swc/core-backed loader first (works today, keeps webpack) and switch tobuiltin:swc-loaderwhen the feature flag lands? - Does
getJsTransformRulesremain a second-class alternative tobabel-swc-loader, or does v6 make it the default intemplates/? #1414 targets Rspack 2+ as a minimum, which makes it viable as a default for the first time — but only if it becomes the path we actually test.
- Lingua principale
- TypeScript
- Stelle
- 1.9k
- Fork
- 164
- Merge medio
- 10g 13h
- PR unite (30g)
- 10
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.
Altre issue di callstack/repack
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 78/100
-
json as string in JS bundle Aperta
Difficoltà 5/5 Più di una settimana Idoneità per principianti 35/100
-
Dev server progress goes backwards mid-compilation (non-monotonic percentage forwarded to reporters) Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 70/100
-
Difficoltà 3/5 1-2 giorni Idoneità per principianti 78/100
-
area:repack type:feature
Difficoltà 5/5 Più di una settimana Idoneità per principianti 42/100
Tutte le issue di callstack/repack
Issue simili
-
Difficoltà 1/5 1-3 ore Idoneità per principianti 88/100
motiondivision/motion#3849 ·
-
Add: S Play Event HD Apertacheck:passed streams:add
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
-
LiteLLM proxy response_cost (x-litellm-response-cost) is never applied to ChatModelOutput.cost Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
i-am-bee/beeai-framework#1697 · 1 reazione ·
-
Support bun dedupe Apertaenhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
antfu/node-modules-inspector#214 ·