This page provides an overview of Bun's JavaScript and TypeScript toolchain: the stages through which source code passes from raw text to a compiled output. It covers the lexer, parser, AST, transformation passes, bundler, and code printer.
For the module resolution subsystem that feeds file paths into the parser, see page Module System and Resolution. For JSX transformation and TypeScript decorator support in depth, see page JSX and TypeScript Support. For the bundler's chunk-linking and output generation details, see page Bundler Architecture. For the CSS parser and bundler, see page CSS Parser and Bundler.
The toolchain operates as a multi-stage pipeline. When running bun build or any file through the runtime, source files pass through each stage in order.
Bun JavaScript/TypeScript Toolchain Pipeline
Sources: src/js_parser/p.rs2-187 src/bundler/bundle_v2.zig107-160 src/js_printer/lib.rs1-100
The lexer lives in the js_lexer module (referenced as crate::lexer throughout the parser codebase). It converts raw UTF-8 source bytes into a token stream. The Lexer<'a> struct is embedded directly in the P parser struct as the lexer field.
Key behaviors:
| Feature | Detail |
|---|---|
| Token type | js_lexer::T enum (e.g., T::TClass, T::TAt, T::TFunction) |
| Lifetime | 'a — borrows the source buffer for zero-copy string slices |
next() | Advances to the next token |
expect() / unexpected() | Emit parse errors via the Log pointer |
has_pure_comment_before | Set when /* @__PURE__ */ precedes an expression |
The lexer does not run as a separate pass. The parser drives it inline: each parse_* function calls lexer.next() to consume tokens as needed.
Sources: src/js_parser/p.rs51-64 src/js_parser/parse/parse_stmt.rs6-12
P StructThe parser is the P struct, defined in src/js_parser/p.rs60-143 It is generic over two const parameters:
| Parameter | Meaning |
|---|---|
TYPESCRIPT | When true, TypeScript-specific syntax (enums, decorators, type annotations) is parsed and stripped. |
SCAN_ONLY | When true, the parser extracts import records without building a full AST; used for fast dependency scanning. |
'a | Lifetime covering both the arena allocator and borrowed source/log references. |
JSX transform mode is not a const generic. It is stored as the jsx_transform: JSXTransformType field at runtime to avoid excessive monomorphization.
P Struct Key Fields
Sources: src/js_parser/p.rs50-100 src/js_parser/p.rs178-193
Statement parsing dispatches via parse_stmt, which is a thin dispatcher over per-token t_* helpers. Each helper is annotated for inlining based on frequency:
t_semicolon, t_function, t_var, t_const) are #[inline] src/js_parser/parse/parse_stmt.rs46-168t_enum, t_at for decorators) are #[cold] #[inline(never)] src/js_parser/parse/parse_stmt.rs62-128TypeScript syntax, such as enum or @decorator, is gated by the TYPESCRIPT const generic src/js_parser/parse/parse_stmt.rs69-80
Sources: src/js_parser/parse/parse_stmt.rs27-184
The AST is composed of three primary node types, all arena-allocated:
| Type | Enum variant prefix | Role |
|---|---|---|
Expr | E::* | Expressions (calls, identifiers, literals, binary ops, JSX, etc.) |
Stmt | S::* | Statements (if, for, return, import, export, etc.) |
Binding | B::* | Destructuring patterns in let, const, function params |
The Ref type is an index into the parser's symbol table. Import/export tracking uses ImportRecord structs stored in the import_records field of P src/js_parser/p.rs101-149
Sources: src/js_parser/p.rs32-45 src/ast/expr.rs
After parsing, the AST is walked by visitor methods. These are defined across several files:
| File | Responsibility |
|---|---|
src/js_parser/visit/visit_expr.rs | Expression visitor: visit_expr, handles defines, macros, JSX transform. |
src/js_parser/visit/visit_stmt.rs | Statement visitor: handles exports, scope management. |
src/js_parser/scan/scan_side_effects.rs | Simplified pass over the AST to classify expression side effects. |
The visitor pass is where most code transformations occur:
interface, type alias declarations).process.env.NODE_ENV and user-defined define keys are replaced test/bundler/transpiler/transpiler.test.js6-21<Component /> syntax to factory calls.Sources: src/js_parser/p.rs180-187 src/js_parser/scan/scan_side_effects.rs
The bundler is BundleV2, defined in src/bundler/bundle_v2.zig107 It orchestrates parallel parsing, module graph construction, linking, and output.
BundleV2 Key Structures
Sources: src/bundler/bundle_v2.zig107-160 src/bundler/bundle_v2.rs63-143
BundleV2 manages transpilers for different targets, such as server, client, and SSR src/bundler/bundle_v2.rs67-87 The client_transpiler is used for browser-bound bundles when Server Components are enabled.
BundleV2 traverses the import graph to identify reachable files. It uses a PathToSourceIndexMap to deduplicate modules by path src/bundler/bundle_v2.zig48-54 The bundler handles barrel optimization by tracking requested exports to deduplicate and detect cycles src/bundler/bundle_v2.zig153-157
Sources: src/bundler/bundle_v2.zig48-160 src/bundler/bundle_v2.rs132-142
The code printer is in src/js_printer/lib.rs It serializes the AST back to JavaScript text, producing both the output code and an optional source map.
The analyze_transpiled_module submodule defines binary records emitted alongside the JS output src/js_printer/lib.rs77-140 These records (e.g., DeclaredVariable, ImportInfoSingle, ExportInfoLocal) allow the linker to understand module structure without re-parsing.
Source maps are generated during the printing process, correlating output positions with original source locations src/js_printer/lib.rs50
Sources: src/js_printer/lib.rs1-140
Parser and bundler behavior is controlled by extensive options:
Transpiler or BundleV2 options test/bundler/transpiler/transpiler.test.js6-21minifySyntax and minifyIdentifiers trigger aggressive AST simplifications test/bundler/bundler_minify.test.ts63-104esm, cjs, iife, and internal formats test/bundler/expectBundled.ts200Sources: test/bundler/expectBundled.ts147-220 test/bundler/transpiler/transpiler.test.js6-38
js_lexer, the P struct, and TypeScript stripping.Expr/Stmt node types and visitor patterns.BundleV2 internals and linking logic.js_printer and source map details.Refresh this wiki
This wiki was recently refreshed. Please wait 7 days to refresh again.