@wyw-in-js/babel-preset

Babel preset that bridges classic Babel build pipelines to WyW-in-JS's Oxc-based zero-runtime CSS-in-JS transform.

Tool
npm
v2.5.1
323stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
82/100Excellent
Development Activity96
Maintenance100
Community56
Maturity48
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
73/100Good
Architecture78
Code Quality80
Innovation58
Learning Curve75

@wyw-in-js/babel-preset is a Babel preset that bridges classic Babel-based build pipelines to WyW-in-JS’s newer Oxc-powered transform engine. Instead of running zero-runtime CSS-in-JS extraction directly inside Babel’s plugin visitor, it serializes the file’s code and plugin options, spawns a synchronous child process that runs the real @wyw-in-js/transform API, and splices the resulting AST and metadata back into the Babel file — so libraries built on wyw-in-js (Linaria, Griffel-style processors, dx-styles) keep working under toolchains still configured through .babelrc or babel.config.js.

The package is explicitly a compatibility shim: it emits a one-time deprecation warning pointing users toward bundler-native integrations (Vite, Webpack, esbuild, Rollup, Turbopack) or the async transform() API for new projects, and exists primarily to keep existing Babel-driven setups working while teams migrate off Linaria or older wyw-in-js versions.

What You Get

  • A Babel preset (wywInJS) you drop into presets alongside existing Babel config
  • A synchronous bridge to @wyw-in-js/transform’s Oxc-backed extraction, run out-of-process via spawnSync
  • Automatic serialization validation that throws a clear, path-specific error when plugin options contain functions, symbols, or other non-serializable values
  • A one-time deprecation warning nudging you toward bundler-native integrations or the transform() API for new setups

Common Use Cases

  • Migrating off Linaria’s Babel plugin without immediately rewriting bundler config
  • Legacy Jest/CRA-style toolchains that only understand Babel presets, not bundler plugin hooks
  • Validating the Oxc transform’s output before switching to dedicated Vite/Webpack/esbuild loaders
  • Keeping CI pipelines pinned to Babel-based builds working while planning a cutover to native bundler integrations

Under The Hood

Architecture The package is a thin adapter: index.ts exports a Babel preset function that, gated by babel.caller(isEnabled), registers a single plugin whose real work happens entirely in its pre(file) hook. That hook builds a transform payload (encoding function/symbol-valued eval.globals through a dedicated codec in globals.ts), validates it is recursively JSON-serializable, and hands it to a synchronous child process (spawnSync) running a standalone runner script that calls the real transform() API from @wyw-in-js/transform inside a fresh cache collection. The parent process then re-parses the returned code with Babel’s own parseSync, splices the new AST into the file, and reshapes the transform’s metadata into Babel’s expected shape. There is no plugin composition beyond this single wrapped plugin — correctness rests entirely on the serialize → subprocess → deserialize → AST-splice round trip.

Tech Stack TypeScript, ESM-only (Node >=22 engine), built via a repo-wide Oxc/esbuild script and tsc for declaration files, orchestrated by Turborepo across a Bun-managed monorepo. Direct runtime dependencies are minimal and precise: @babel/core for AST/transform types plus workspace siblings @wyw-in-js/shared and @wyw-in-js/transform (which itself pulls in oxc-parser, oxc-resolver, oxc-transform, happy-dom, cosmiconfig, and stylis). Linting runs through a shared @wyw-in-js/eslint-config/library preset, and CI runs on Bun with a frozen lockfile install, build, and ESLint pass.

Code Quality Tests live in a single __tests__/index.test.ts file using Jest-style APIs, covering deprecation-warning throttling and function-valued config loading through the sync runner, and reuse fixtures from the sibling transform package rather than duplicating a test CSS processor. Error handling is explicit and user-facing throughout — non-serializable options and subprocess/JSON failures all raise descriptive, [wyw-in-js]-prefixed errors that name the exact option path — and TypeScript runs in strict mode via project references split between library and spec configs. No swallowed errors were found.

What Makes It Unique The package’s one genuinely interesting idea is architectural: rather than reimplementing the Oxc-based transform as an in-process synchronous Babel visitor, it spawns a real child process and does a full serialize/deserialize round trip, including a bespoke encode/decode scheme that lets function and symbol values cross that boundary by stringifying and re-evaluating function sources. That’s a legitimate answer to a real sync/async impedance mismatch, but the package is explicit that it is a deprecated stopgap rather than forward-looking design — it exists to unblock Babel-only pipelines during migration, not to introduce new capability.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search