or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

babel-integration.mdindex.md

babel-integration.mddocs/

0

# Babel Integration

1

2

@vitejs/plugin-react provides flexible Babel integration allowing you to customize transformations with plugins, presets, and parser options. Babel is **lazy-loaded** and **only used when configured**, ensuring optimal performance when not needed.

3

4

## Performance Context

5

6

**When Babel is Used:**

7

8

| Babel Config | Dev Transformer | Prod Transformer | Speed | Use Case |

9

|--------------|----------------|------------------|-------|----------|

10

| None | esbuild/oxc | esbuild/oxc | Fastest | Standard React app |

11

| parserOpts only | esbuild/oxc | esbuild/oxc | Fast | Parsing experimental syntax |

12

| plugins/presets | Babel | Babel | Slower | Custom transformations needed |

13

14

**Key Principle:** Only use Babel when you need custom transformations that esbuild/oxc cannot handle. Parser-only features (parserOpts) don't trigger Babel transformation.

15

16

## API Reference

17

18

### Babel Configuration Options

19

20

Configure Babel transformations with plugins, presets, and other Babel options. The configuration can be static or dynamic based on the file being transformed.

21

22

```typescript { .api }

23

/**

24

* Babel transformation options for @vitejs/plugin-react

25

* Omits properties that are controlled internally by the plugin

26

*/

27

type BabelOptions = Omit<

28

TransformOptions,

29

'ast' | 'filename' | 'root' | 'sourceFileName' | 'sourceMaps' | 'inputSourceMap'

30

>;

31

32

interface Options {

33

/**

34

* Babel configuration applied in both dev and prod

35

* Can be a static options object or a function that returns options based on file context

36

*/

37

babel?: BabelOptions | ((id: string, options: { ssr?: boolean }) => BabelOptions);

38

}

39

40

// TransformOptions is from @babel/core and includes:

41

// - plugins, presets, overrides, parserOpts, babelrc, configFile, and more

42

// See: https://babeljs.io/docs/options

43

type TransformOptions = import('@babel/core').TransformOptions;

44

```

45

46

**Key BabelOptions properties:**

47

- `plugins?: PluginItem[]` - Babel transformation plugins to apply

48

- `presets?: PluginItem[]` - Babel presets to apply

49

- `overrides?: TransformOptions[]` - Conditional configuration based on file patterns

50

- `parserOpts?: ParserOptions` - Parser configuration (parsing only, no transformation)

51

- `babelrc?: boolean` - Enable .babelrc files (default: searches only if babel options set)

52

- `configFile?: boolean | string` - Enable babel.config.js files

53

- `generatorOpts?: GeneratorOptions` - Code generation options

54

- Full spec: https://babeljs.io/docs/options

55

56

### Normalized Babel Options

57

58

The internal representation of Babel options with guaranteed array types for plugins, presets, and overrides.

59

60

```typescript { .api }

61

/**

62

* Normalized Babel options object used internally and passed to plugin API hooks

63

*/

64

interface ReactBabelOptions extends BabelOptions {

65

/** Array of Babel plugins to apply */

66

plugins: Extract<BabelOptions['plugins'], any[]>;

67

/** Array of Babel presets to apply */

68

presets: Extract<BabelOptions['presets'], any[]>;

69

/** Array of Babel overrides for conditional configuration */

70

overrides: Extract<BabelOptions['overrides'], any[]>;

71

/** Parser options including plugins for syntax support */

72

parserOpts: ParserOptions & {

73

plugins: Extract<ParserOptions['plugins'], any[]>;

74

};

75

}

76

77

type ParserOptions = import('@babel/core').ParserOptions;

78

```

79

80

### Babel Plugin API Hook

81

82

Other Vite plugins can hook into the Babel configuration process to add or modify Babel options dynamically.

83

84

```typescript { .api }

85

/**

86

* API surface for Vite plugins to interact with @vitejs/plugin-react

87

*/

88

interface ViteReactPluginApi {

89

/**

90

* Hook to manipulate the Babel options

91

* Called before each file transformation

92

*/

93

reactBabel?: ReactBabelHook;

94

}

95

96

/**

97

* Callback function type for manipulating Babel configuration

98

*/

99

type ReactBabelHook = (

100

babelConfig: ReactBabelOptions,

101

context: ReactBabelHookContext,

102

config: ResolvedConfig

103

) => void;

104

105

/**

106

* Context object passed to ReactBabelHook callbacks

107

*/

108

type ReactBabelHookContext = {

109

/** Whether this is a server-side rendering transformation */

110

ssr: boolean;

111

/** File identifier being transformed */

112

id: string;

113

};

114

115

type ResolvedConfig = import('vite').ResolvedConfig;

116

```

117

118

**Example:**

119

```typescript

120

import type { Plugin, ResolvedConfig } from 'vite';

121

import type { ReactBabelOptions } from '@vitejs/plugin-react';

122

123

const babelModifierPlugin: Plugin = {

124

name: 'babel-modifier',

125

api: {

126

reactBabel(babelConfig, context, config) {

127

// Add plugins based on environment

128

if (!config.isProduction) {

129

babelConfig.plugins.push('babel-plugin-dev-only');

130

}

131

132

// Add SSR-specific transformations

133

if (context.ssr) {

134

babelConfig.plugins.push([

135

'babel-plugin-transform-imports',

136

{ /* ssr-specific options */ }

137

]);

138

}

139

140

// Add parser plugins for specific files

141

if (context.id.includes('experimental')) {

142

babelConfig.parserOpts.plugins.push('decorators-legacy');

143

}

144

145

// Modify presets

146

babelConfig.presets.push(['@babel/preset-env', {

147

targets: config.build.target

148

}]);

149

}

150

}

151

};

152

153

export default defineConfig({

154

plugins: [babelModifierPlugin, react()],

155

});

156

```

157

158

## Configuration Patterns

159

160

### Static Configuration

161

162

Use static configuration when Babel options are consistent across all files. This is more efficient as options are created once and reused.

163

164

```typescript

165

import react from '@vitejs/plugin-react';

166

import { defineConfig } from 'vite';

167

168

export default defineConfig({

169

plugins: [

170

react({

171

babel: {

172

plugins: ['babel-plugin-macros'],

173

presets: [

174

['@babel/preset-typescript', { isTSX: true, allExtensions: true }]

175

],

176

// Use .babelrc files

177

babelrc: true,

178

// Use babel.config.js files

179

configFile: true,

180

}

181

})

182

]

183

});

184

```

185

186

**Performance:** Config created once and reused across all files (most efficient).

187

188

### Dynamic Configuration

189

190

Use dynamic configuration when you need file-specific or context-specific Babel options.

191

192

```typescript

193

react({

194

babel: (id, { ssr }) => ({

195

plugins: [

196

// Add different plugins based on context

197

...(ssr ? ['babel-plugin-ssr'] : ['babel-plugin-client']),

198

// Conditional plugin for specific files

199

...(id.includes('legacy') ? ['@babel/plugin-transform-arrow-functions'] : []),

200

],

201

})

202

})

203

```

204

205

**Performance:** New config generated for each file transformation (slight overhead but more flexible).

206

207

### Parser Plugins for Proposed Syntax

208

209

Enable parsing (not transformation) of experimental ECMAScript features. This does NOT trigger Babel transformation - esbuild still handles the transformation.

210

211

```typescript

212

react({

213

babel: {

214

parserOpts: {

215

plugins: [

216

'decorators-legacy',

217

'classProperties',

218

'exportDefaultFrom',

219

]

220

}

221

}

222

})

223

```

224

225

**Note:** Parser plugins only enable *parsing* of syntax. Code transformation is handled by esbuild. To transform the code, use Babel transformation plugins.

226

227

**Common parser plugins:**

228

- `decorators-legacy` - Legacy decorator syntax

229

- `decorators` - TC39 decorators proposal

230

- `classProperties` - Class properties

231

- `classPrivateProperties` - Private class properties

232

- `classPrivateMethods` - Private class methods

233

- `exportDefaultFrom` - `export v from 'mod'`

234

- `exportNamespaceFrom` - `export * as ns from 'mod'`

235

- `functionBind` - Function bind operator `::`

236

- `pipelineOperator` - Pipeline operator `|>`

237

238

Full list: https://babeljs.io/docs/en/babel-parser#ecmascript-proposals

239

240

## Common Use Cases

241

242

### Adding Custom Babel Plugins

243

244

```typescript

245

react({

246

babel: {

247

plugins: [

248

'babel-plugin-macros',

249

['babel-plugin-styled-components', { displayName: true }],

250

'@babel/plugin-proposal-decorators',

251

]

252

}

253

})

254

```

255

256

### Using Babel Configuration Files

257

258

Enable reading from `.babelrc` or `babel.config.js`:

259

260

```typescript

261

react({

262

babel: {

263

babelrc: true,

264

configFile: true,

265

}

266

})

267

```

268

269

**Note:** By default, Babel config files are only searched when babel options are explicitly set.

270

271

### React Compiler Integration

272

273

Configure the React Compiler (experimental):

274

275

```typescript

276

// Auto-optimize all components

277

react({

278

babel: {

279

plugins: [

280

[

281

'babel-plugin-react-compiler',

282

{

283

// Target React version ('17', '18', or '19')

284

target: '19',

285

// Compilation mode: 'all' or 'annotation'

286

compilationMode: 'all',

287

}

288

]

289

]

290

}

291

})

292

293

// Annotation mode (only compile functions with "use memo" directive)

294

react({

295

babel: {

296

plugins: [

297

['babel-plugin-react-compiler', { compilationMode: 'annotation' }]

298

]

299

}

300

})

301

```

302

303

Then in your code:

304

305

```typescript

306

function ExpensiveComponent() {

307

"use memo"; // This component will be compiled

308

// ...

309

}

310

```

311

312

### Environment-Specific Configuration

313

314

Different Babel configs for SSR vs client:

315

316

```typescript

317

react({

318

babel: (id, { ssr }) => {

319

const plugins = ['babel-plugin-macros'];

320

321

// SSR-specific plugins

322

if (ssr) {

323

plugins.push('babel-plugin-dynamic-import-node');

324

}

325

326

// Client-specific plugins

327

if (!ssr) {

328

plugins.push('babel-plugin-react-lazy');

329

}

330

331

return { plugins };

332

}

333

})

334

```

335

336

### Conditional File-Based Configuration

337

338

```typescript

339

react({

340

babel: (id, options) => {

341

const config: BabelOptions = {

342

plugins: [],

343

presets: [],

344

};

345

346

// Legacy browser support for specific directories

347

if (id.includes('/legacy/')) {

348

config.presets!.push(['@babel/preset-env', {

349

targets: { ie: 11 }

350

}]);

351

}

352

353

// Modern syntax for modern bundles

354

if (id.includes('/modern/')) {

355

config.presets!.push(['@babel/preset-env', {

356

targets: { esmodules: true }

357

}]);

358

}

359

360

return config;

361

}

362

})

363

```

364

365

### Styled Components Example

366

367

```typescript

368

react({

369

babel: {

370

plugins: [

371

[

372

'babel-plugin-styled-components',

373

{

374

displayName: true,

375

fileName: true,

376

ssr: true,

377

}

378

]

379

]

380

}

381

})

382

```

383

384

### Emotion CSS Prop Support

385

386

```typescript

387

react({

388

jsxImportSource: '@emotion/react',

389

babel: {

390

plugins: ['@emotion/babel-plugin']

391

}

392

})

393

```

394

395

### Babel Macros Support

396

397

```typescript

398

react({

399

babel: {

400

plugins: ['babel-plugin-macros']

401

}

402

})

403

```

404

405

## Performance Optimization

406

407

### When Babel is Used

408

409

- **No plugins/presets configured**: Babel is skipped entirely; esbuild/oxc handles all transformations (fastest)

410

- **Only parserOpts configured**: Babel is used for parsing only; esbuild/oxc handles transformation (fast)

411

- **Plugins/presets configured**: Babel transformation is applied to matching files (slower)

412

- **Dynamic configuration**: New Babel options created for each file transformation (additional overhead)

413

- **Static configuration**: Options created once and reused (more efficient)

414

415

### Optimization Strategies

416

417

1. **Minimize Babel usage**: Only use Babel when necessary; let esbuild/oxc handle standard transformations

418

2. **Prefer parser plugins**: If you only need syntax parsing (not transformation), use parserOpts only

419

3. **Use static configuration**: Avoid function-based babel options when possible

420

4. **Limit file scope**: Use `include`/`exclude` options to reduce files processed by Babel

421

5. **Lazy loading**: Babel is only loaded when needed, so startup time is not affected if Babel is unused

422

423

### Static vs Dynamic Config Performance

424

425

**Static Configuration:**

426

```typescript

427

react({

428

babel: {

429

plugins: ['babel-plugin-macros'] // Created once, reused for all files

430

}

431

})

432

```

433

- Config created once during initialization

434

- Reused across all file transformations

435

- Best performance for consistent transformations

436

437

**Dynamic Configuration:**

438

```typescript

439

react({

440

babel: (id, { ssr }) => ({

441

plugins: ssr ? ['plugin-a'] : ['plugin-b'] // Created for each file

442

})

443

})

444

```

445

- New config generated for each file transformation

446

- More flexible for file-specific or context-specific needs

447

- Slight performance overhead per file

448

449

### Scope Limiting

450

451

Reduce the number of files processed by Babel:

452

453

```typescript

454

react({

455

// Only process files that need custom transformations

456

include: /src\/legacy\/.*\.tsx?$/,

457

babel: {

458

plugins: ['@babel/plugin-transform-arrow-functions']

459

}

460

})

461

```

462

463

## Babel Transformation Pipeline

464

465

Understanding the transformation pipeline helps optimize your configuration:

466

467

1. **File Matching**: File is checked against include/exclude patterns

468

2. **JSX Detection**: Plugin determines if Fast Refresh should be applied

469

3. **Plugin Assembly**: Babel plugins array is constructed:

470

- User-provided plugins (run first)

471

- React Refresh plugin (development only, if applicable)

472

- React JSX plugins (classic runtime development only)

473

4. **Parser Configuration**: Parser plugins for JSX, TypeScript, etc. are added

474

5. **Transformation**: Babel transforms the code with assembled configuration

475

6. **Refresh Wrapping**: Fast Refresh wrapper is added (development only, if applicable)

476

477

### Plugin Execution Order

478

479

Babel plugins run in a specific order:

480

481

1. **User plugins** (as configured in `babel.plugins`)

482

2. **User presets** (as configured in `babel.presets`, in reverse order)

483

3. **React Refresh plugin** (if in development and Fast Refresh applies)

484

4. **React JSX plugins** (if using classic runtime in development)

485

486

**Important:** Plugins run before presets, and plugins run in order while presets run in reverse order.

487

488

## Production Builds

489

490

In production builds:

491

- If no Babel plugins are configured, esbuild handles all transformations (fastest)

492

- If Babel plugins are configured, Babel transformation is applied

493

- Fast Refresh code is never included in production builds

494

- Only transformation plugins affect production; parser plugins do not

495

496

**Optimization tip:** Consider using different Babel configs for dev vs prod:

497

498

```typescript

499

react({

500

babel: (id, { ssr }) => {

501

const isDev = process.env.NODE_ENV === 'development';

502

503

return {

504

plugins: [

505

// Always included

506

'babel-plugin-macros',

507

// Dev-only plugins

508

...(isDev ? ['babel-plugin-dev-tools'] : []),

509

]

510

};

511

}

512

})

513

```

514

515

## Compatibility

516

517

### Babel Version

518

519

The plugin is compatible with Babel 7.x (specifically @babel/core ^7.28.4).

520

521

### TypeScript

522

523

TypeScript syntax is automatically handled by esbuild/oxc without configuration. You don't need `@babel/preset-typescript` unless you have specific TypeScript transformation requirements.

524

525

**When you might need @babel/preset-typescript:**

526

- Custom TypeScript transformation options

527

- Specific legacy TypeScript features not supported by esbuild

528

- Integration with other Babel plugins that expect TypeScript preset

529

530

**Example:**

531

```typescript

532

react({

533

babel: {

534

presets: [

535

['@babel/preset-typescript', {

536

isTSX: true,

537

allExtensions: true,

538

allowDeclareFields: true,

539

}]

540

]

541

}

542

})

543

```

544

545

### React Version

546

547

- **React >= 16.9**: Full support including Fast Refresh

548

- **React < 16.9**: Basic transformations work, but Fast Refresh is unavailable

549

550

### Node.js Version

551

552

Requires Node.js ^20.19.0 || >=22.12.0

553

554

## Troubleshooting

555

556

### Babel Not Being Applied

557

558

**Check:**

559

1. Babel options are actually configured (even `parserOpts` counts)

560

2. File matches `include` pattern (default: /\.[tj]sx?$/)

561

3. File doesn't match `exclude` pattern (default: /\/node_modules\//)

562

4. Babel dependencies are installed (`@babel/core` and any plugins/presets)

563

564

### Performance Issues with Babel

565

566

**If Babel is causing slow builds:**

567

568

1. **Verify Babel is necessary**: Check if you can use parserOpts only

569

2. **Use static config**: Replace function-based babel options with static object

570

3. **Limit file scope**: Use include/exclude to reduce processed files

571

4. **Remove unused plugins**: Each plugin adds transformation overhead

572

5. **Consider alternatives**: Check if esbuild can handle your transformations

573

574

### Plugin Conflicts

575

576

If you experience conflicts between Babel plugins:

577

578

1. **Check plugin order**: Plugins run in the order specified

579

2. **Review presets**: Presets run in reverse order and may contain conflicting plugins

580

3. **Use plugin options**: Some plugins have options to disable specific features

581

4. **Test in isolation**: Remove plugins one by one to identify conflicts

582

583

### Parser Plugin Not Working

584

585

**Common issues:**

586

587

1. **Using wrong plugin name**: Parser plugins have specific names (e.g., 'decorators-legacy' not 'decorator')

588

2. **Transformation expected**: Parser plugins only parse syntax; use transformation plugins for actual code transformation

589

3. **esbuild doesn't support**: Some experimental syntax isn't supported by esbuild even with parser plugins

590

591

**Solution:** Use a transformation plugin instead:

592

```typescript

593

react({

594

babel: {

595

plugins: ['@babel/plugin-proposal-decorators'] // Transformation plugin

596

}

597

})

598

```

599

600

## Reference

601

602

**Babel Documentation:** https://babeljs.io/docs/

603

**Parser Plugins:** https://babeljs.io/docs/en/babel-parser#ecmascript-proposals

604

**Transform Options:** https://babeljs.io/docs/options

605

**Plugin Development:** https://babeljs.io/docs/plugins

606