@swc/plugin-emotion

The official SWC compiler plugin that compiles Emotion's css-in-js calls at build time instead of at runtime.

Tool
npm
v16.0.0
389stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
68/100Good
Development Activity80
Maintenance36
Community72
Maturity56
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
69/100Good
Architecture78
Code Quality74
Innovation70
Learning Curve55

@swc/plugin-emotion is the official SWC compiler plugin for the Emotion css-in-js library. It is a Rust reimplementation of babel-plugin-emotion, compiled to a portable WASM module that SWC loads during compilation to rewrite css, styled, keyframes, and Global JSX calls, attach dev-friendly labels, and emit inline source maps.

Because it runs as a native compiler pass rather than a JavaScript transform, it avoids the per-file overhead of Babel plugins while producing configuration-compatible output with Next.js’s built-in Emotion support, making it a drop-in choice for teams moving off Babel or configuring SWC directly via .swcrc.

What You Get

  • A precompiled WASM binary plugin — no Rust toolchain needed to consume it
  • Compile-time transforms for Emotion’s css, styled, keyframes, and Global JSX primitives
  • Configuration shape compatible with Next.js’s built-in Emotion compiler option
  • An extensible importMap option for registering custom or wrapped Emotion re-exports

Common Use Cases

  • Enabling readable dev-mode class labels for Emotion-styled components in a Next.js or direct-SWC build
  • Replacing babel-plugin-emotion when migrating a build pipeline from Babel to native SWC
  • Registering internal design-system wrapper modules via the import map so they receive the same css-in-js transform as official Emotion imports

Under The Hood

Architecture The package is split into a thin WASM entry crate (src/lib.rs) and a separate transform crate, swc_emotion (transform/src/lib.rs). The entry crate parses the plugin’s JSON configuration with serde, folds Next.js-style options (sourceMap, autoLabel, labelFormat) into the transform crate’s EmotionOptions, and hands the program AST to swc_emotion::emotion(...), which builds an SWC Pass via fn_pass and applies it with fold_with. The transform crate itself separates concerns further with an import_map submodule that expands a registry of official Emotion modules (@emotion/react, @emotion/styled, @emotion/css, @emotion/native, @emotion/primitives) plus any user-supplied custom import mappings into a lookup table the visitor consults before deciding whether a file needs rewriting at all.

Tech Stack Written in Rust against swc_core with the ecma_plugin_transform feature, compiled to the wasm32-wasip1 target so it loads inside SWC’s plugin runtime with no Rust toolchain required by consumers. Supporting crates include regex and once_cell for lazily-compiled label-sanitization patterns, base64/byteorder/swc_sourcemap for building inline source maps, and rustc-hash’s FxHashMap for the import-map lookups. The npm-facing package.json is a thin wrapper (main: swc_plugin_emotion.wasm) with a single runtime dependency on @swc/counter, built via pnpm/cargo build --target wasm32-wasip1 inside the shared swc-project/plugins Cargo workspace.

Code Quality Testing is split across two harnesses: transform/tests/fixture.rs runs SWC’s fixture/snapshot testing framework over a comprehensive set of named fixture directories (comments, compress, import-map, css-in-callback, namespace-import, and dedicated regression fixtures for past GitHub issues), while __tests__/wasm.test.ts exercises the compiled .wasm output end-to-end through Vitest snapshots. Configuration errors surface via .expect(...) panics at the plugin boundary rather than typed Result handling, which is a reasonable trade-off for a compiler plugin but offers no graceful degradation. No dedicated linter config is visible beyond the workspace-level Rust lint settings.

API Design The plugin’s configuration object deliberately mirrors babel-plugin-emotion’s shape (sourceMap, autoLabel, labelFormat) and the exact options Next.js already exposes for its built-in Emotion support, so teams adopting it face effectively zero new API surface. The importMap escape hatch is the one piece of genuine extensibility, letting consumers teach the transform about wrapper modules without forking the plugin.

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