RepoPilotOpen in app →

parcel-bundler/lightningcss

An extremely fast CSS parser, transformer, bundler, and minifier written in Rust.

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 8w ago
  • 32+ active contributors
  • MPL-2.0 licensed
Show all 6 evidence items →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 51% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/parcel-bundler/lightningcss)](https://repopilot.app/r/parcel-bundler/lightningcss)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/parcel-bundler/lightningcss on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: parcel-bundler/lightningcss

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/parcel-bundler/lightningcss shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 8w ago
  • 32+ active contributors
  • MPL-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 51% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live parcel-bundler/lightningcss repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/parcel-bundler/lightningcss.

What it runs against: a local clone of parcel-bundler/lightningcss — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in parcel-bundler/lightningcss | Confirms the artifact applies here, not a fork | | 2 | License is still MPL-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 86 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>parcel-bundler/lightningcss</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of parcel-bundler/lightningcss. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/parcel-bundler/lightningcss.git
#   cd lightningcss
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of parcel-bundler/lightningcss and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "parcel-bundler/lightningcss(\\.git)?\\b" \\
  && ok "origin remote is parcel-bundler/lightningcss" \\
  || miss "origin remote is not parcel-bundler/lightningcss (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MPL-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MPL-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is MPL-2.0" \\
  || miss "license drift — was MPL-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/lib.rs" \\
  && ok "src/lib.rs" \\
  || miss "missing critical file: src/lib.rs"
test -f "src/parser.rs" \\
  && ok "src/parser.rs" \\
  || miss "missing critical file: src/parser.rs"
test -f "src/printer.rs" \\
  && ok "src/printer.rs" \\
  || miss "missing critical file: src/printer.rs"
test -f "src/declaration.rs" \\
  && ok "src/declaration.rs" \\
  || miss "missing critical file: src/declaration.rs"
test -f "src/bundler.rs" \\
  && ok "src/bundler.rs" \\
  || miss "missing critical file: src/bundler.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 86 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~56d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/parcel-bundler/lightningcss"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Lightning CSS is an extremely fast CSS parser, transformer, bundler, and minifier written in Rust that parses CSS using the W3C grammar specification to produce typed property values. It serves as Parcel's primary CSS handler and can be used standalone via CLI, Node.js bindings, or a C FFI interface, performing aggressive minification (combining shorthands, removing unnecessary vendor prefixes, lowering modern syntax) based on configurable browser targets. Workspace monorepo: core parser in src/ (Rust), with crate members for Node.js bindings (node/), NAPI wrapper (napi/), C FFI bindings (c/), and procedural macros (derive/). Each frontend (CLI, Node, C, NAPI) wraps the core lightningcss library. Examples in examples/ show custom AST visitors. The cli/ folder contains npm wrapper scripts for the compiled binary.

👥Who it's for

Frontend developers and bundler maintainers who need sub-millisecond CSS processing at scale—particularly Parcel users, tool authors integrating CSS pipelines, and teams building JavaScript/TypeScript applications requiring vendor prefix management and browser-targeted syntax lowering without the performance overhead of JavaScript-based CSS processors.

🌱Maturity & risk

Actively developed and production-ready: at v1.0.0-alpha.71 (approaching v1 stable), with a comprehensive test suite (visible CI workflows in .github/workflows/test.yml), Mozilla-backed browser-grade parsing foundation (cssparser + selectors crates from Firefox/Servo), and tight integration with Parcel's ecosystem. Not yet v1.0 stable but widely used in production via Parcel.

Low-to-moderate risk: single primary author (Devon Govett) creates maintenance concentration, but the project is backed by Parcel maintainers. Dependencies are minimal and high-quality (cssparser from Mozilla, rayon for parallelism), though the Rust FFI surface (C bindings in c/src/lib.rs, NAPI bindings in napi/src/lib.rs) adds complexity. Breaking changes likely during alpha → v1.0 transition. Monitor release notes for semver breaks.

Active areas of work

Project is in late alpha (v1.0.0-alpha.71 in Cargo.toml), stabilizing the public API before v1.0 release. CI/CD workflows (release.yml, release-crates.yml, test.yml) run tests and publish to npm and crates.io. Current work likely focuses on reducing alpha tag breakage and finalizing the AST visitor API (visible in derive/src/visit.rs).

🚀Get running

git clone https://github.com/parcel-bundler/lightningcss
cd lightningcss
cargo build --release
cargo test

Daily commands:

cargo run --release --bin lightningcss -- --help          # CLI
cargo test                                                  # Run test suite
cargo build --release -p lightningcss                       # Core lib
cd node && npm install && npm run build                     # Node.js bindings

🗺️Map of the codebase

  • src/lib.rs — Main library entry point exposing the public API for parsing, transforming, and minifying CSS; all transformations flow through here.
  • src/parser.rs — Core CSS parser that reads tokens and constructs the typed AST; fundamental to understanding how stylesheets are consumed.
  • src/printer.rs — Serializes the parsed CSS AST back to string form with optional minification; inverse of parser and critical for output correctness.
  • src/declaration.rs — Defines typed CSS property values and their parsing rules; implements the typed property system that differentiates this project.
  • src/bundler.rs — Handles CSS module bundling, dependency resolution, and cross-file transformations; entry point for multi-file workflows.
  • node/src/lib.rs — NAPI bridge exposing Rust library to Node.js/JavaScript; required to understand how consumers interact with the core.
  • derive/src/lib.rs — Proc-macro framework for deriving Parse and ToCss traits; reduces boilerplate for CSS property definitions throughout codebase.

🛠️How to make changes

Add support for a new CSS property

  1. Define the property's value type as a Rust enum in src/properties/.rs (e.g., src/properties/background.rs for background- properties) (src/properties/background.rs)
  2. Implement Parse trait (usually via #[derive(Parse)] with the derive macro) and ToCss trait to serialize the value (derive/src/lib.rs)
  3. Register the property in the properties enum and mapping in src/declaration.rs (src/declaration.rs)
  4. Add browser compatibility rules to src/compat.rs if fallbacks or prefixes are needed (src/compat.rs)
  5. Write tests in the property module and run cargo test to verify parsing and serialization (src/properties/background.rs)

Add a new CSS transformation or optimization

  1. Implement a visitor or transform function in src/context.rs or a new module that walks the parsed AST (src/context.rs)
  2. Hook the transformation into PrinterOptions in src/printer.rs so it can be configured by users (src/printer.rs)
  3. For bundling-time transforms, add logic to src/bundler.rs to apply it during file merging (src/bundler.rs)
  4. Add integration tests in node/test/ to verify the transformation works end-to-end from JavaScript (node/test/transform.test.mjs)

Expose new functionality to Node.js

  1. Implement the new method in the core library (src/lib.rs) as a public function (src/lib.rs)
  2. Add a NAPI wrapper function in node/src/lib.rs or napi/src/lib.rs to convert Rust types to JavaScript types (node/src/lib.rs)
  3. Export the function in node/index.d.ts (TypeScript) and node/index.js (JavaScript entry point) (node/index.d.ts)
  4. Add tests in node/test/ to verify the JavaScript API works correctly (node/test/transform.test.mjs)

Add vendor prefix or browser compatibility rule

  1. Define the prefix or feature in src/prefixes.rs or src/compat.rs with target browser support matrix (src/prefixes.rs)
  2. Update src/context.rs to apply the prefix/fallback during CSS generation based on browser targets (src/context.rs)
  3. Test with node/browserslistToTargets.js to ensure browser version matching works correctly (node/browserslistToTargets.js)

🔧Why these technologies

  • Rust — Enables parsing and minification of large CSS files in milliseconds with memory safety and zero-cost abstractions; performance-critical.
  • NAPI (Node.js native addon) — Bridges Rust performance to Node.js ecosystem with minimal overhead; allows async operations and thread-safe callbacks.
  • Procedural macros (derive crate) — Eliminates boilerplate for Parse and ToCss trait implementations across hundreds of CSS property types.
  • Vendored selectors crate — Provides battle-tested CSS selector parsing and matching logic without external dependency on servo/selectors.
  • Rayon (in bundler feature) — Enables parallel processing of multiple CSS files during bundling on multi-core systems.

⚖️Trade-offs already made

  • Typed property values instead of generic token streams

    • Why: Enables accurate transformations (e.g., logical-to-physical property conversion) and prevents inconsistencies between tools.
    • Consequence: Requires defining and maintaining a type for each CSS property; higher upfront work but eliminates duplicate parsing in consumers.
  • Rust + NAPI instead of pure JavaScript

    • Why: Achieves 10–100x performance improvement over JavaScript-based parsers.
    • Consequence: Requires Rust toolchain for builds; cross-platform compilation complexity; not suitable for browser-only deployment without WASM.
  • Eager parsing of all property values

    • Why: Catches errors early; enables targeted optimizations and transpilations.
    • Consequence: Strict parsing means unknown/future CSS properties cause errors; more lenient handling requires explicit optional fields.
  • Bundler as opt-in feature (not default in CLI)

    • Why: Allows lightweight use as a transformer without dependency resolution overhead.
    • Consequence: Users who want bundling must explicitly enable the bundler feature; adds configuration burden.

🚫Non-goals (don't propose these)

  • JavaScript object model or DOM manipulation—parser outputs AST, not a live DOM-like interface
  • Real-time file watching or hot reloading—CLI is a one-shot transformation tool
  • PostCSS plugin system—intentionally avoids plugins to maintain performance and determinism
  • Support for non-standard or deprecated CSS—parser strictly follows CSS spec
  • Client-side browser execution—designed for build-time processing only

🪤Traps & gotchas

Cargo features are essential: Default features include bundler + nodejs + sourcemap; omit at your peril—some parsing features require specific features enabled. NAPI threading: node/napi use rayon for parallelism; Node.js event loop doesn't block but Rust side uses true threads—can be surprising. Browser targets: Vendor prefix removal and syntax lowering depend on the browserslist config or explicit browser target list; omit and you get no transformations. Alpha API instability: Methods and enum variants marked with #[non_exhaustive] or alpha version indicate breaking-change risk before v1.0. C binding regeneration: Editing c/src/lib.rs requires running cbindgen (see c/cbindgen.toml)—the .h header is generated, not manual.

🏗️Architecture

💡Concepts to learn

  • W3C CSS Grammar Specification — Lightning CSS parses CSS using the official CSS grammar (via cssparser), not hand-rolled tokenization; understanding the spec allows you to predict parser behavior and contribute new property types correctly
  • Vendor Prefix Removal & Browser Target Matching — The core value of Lightning CSS is removing unnecessary vendor prefixes (-webkit-, -moz-, etc.) based on target browser support; you must understand how browserslist targets map to CSS feature support to implement new minification rules
  • AST Visitor Pattern & Procedural Macros — Lightning CSS's #[derive(Visit)] macro (derive/src/visit.rs) auto-generates tree traversal code; understanding Rust procedural macros is essential to extend the AST or add custom transformation passes
  • Typed CSS Property Values — Unlike PostCSS (which treats values as token streams), Lightning CSS parses each property's value into a specific Rust enum (e.g., Color, Length, Gradient); this enables safe, spec-compliant minification without re-parsing
  • CSS Syntax Lowering — Lightning CSS converts modern CSS (nesting, custom media, logical properties) into compatible output for older browsers; understanding the lowering transformations (src/ contains logic) is needed to add support for new CSS features
  • NAPI & FFI Bindings — node/src and napi/src expose Rust code to Node.js and C; understanding NAPI threading, serialization, and FFI safety is required to extend bindings or debug performance issues in JavaScript integration
  • Shorthand Property Expansion & Combination — Lightning CSS minifies by combining longhand properties (margin-top, margin-right, …) into shorthands (margin); implementing this requires understanding CSS property dependencies and fallback handling per spec
  • parcel-bundler/parcel — Parcel is the primary consumer of Lightning CSS; understanding Parcel's CSS pipeline integration clarifies real-world usage patterns
  • postcss/postcss — PostCSS is the JavaScript ecosystem's dominant CSS transformer; Lightning CSS competes on speed and typed properties—useful for context on why Rust was chosen
  • evanw/esbuild — esbuild (Go bundler) has a similar performance-first architecture and also handles CSS; studying its design informs understanding of Lightning CSS's bundler (src/ modules with rayon parallelism)
  • servo/rust-cssparser — Mozilla's cssparser crate (dependency in Cargo.toml) is the parsing foundation; source of truth for W3C-compliant tokenization that Lightning CSS builds on
  • servo/rust-selectors — Servo's selectors crate (parcel_selectors in Cargo.toml) provides the CSS selector parsing; study it to understand how Lightning CSS validates and optimizes selectors

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive test coverage for the C FFI bindings (c/test.c)

The C bindings (c/src/lib.rs and c/lightningcss.h) lack automated test infrastructure. Currently only c/test.c exists as a manual test file. Adding a proper C test suite would catch regressions in the C API, ensure memory safety of FFI boundaries, and provide examples for C users. This is critical for a library that exposes Rust functionality to C consumers.

  • [ ] Convert c/test.c into an automated test harness using a C testing framework (e.g., Unity or CMocka)
  • [ ] Add tests covering all public functions in c/lightningcss.h (parse, transform, bundle, minify operations)
  • [ ] Integrate C tests into the GitHub Actions workflow (.github/workflows/test.yml) to run on each commit
  • [ ] Add memory leak detection using valgrind or similar in the CI pipeline

Add GitHub Actions workflow for testing WebAssembly build and publishing wasm artifacts

The repo has a scripts/build-wasm.js but no corresponding CI workflow in .github/workflows/. This means WASM builds are not automatically tested on PRs, risking breakage. Adding a WASM-specific workflow would validate the build, run WASM-specific tests, and optionally publish artifacts, making it accessible to web users.

  • [ ] Create .github/workflows/wasm.yml with steps to run scripts/build-wasm.js
  • [ ] Add wasm-pack installation and Node.js WASM test execution (if tests exist in node/test/)
  • [ ] Verify WASM artifact size doesn't regress significantly using a threshold check
  • [ ] Optionally add step to publish WASM artifacts to npm or GitHub releases on tagged commits

Add missing integration tests for the Node.js API with multiple bundler scenarios (node/test/)

The node/test/ directory has tests for transform, visitor, and custom at-rules, but the bundler feature (which depends on dashmap, rayon, and parcel_sourcemap) lacks dedicated integration tests. Given that bundling is a core feature and involves cross-file dependencies, adding comprehensive bundler tests would catch edge cases in dependency resolution, asset inlining, and source map generation.

  • [ ] Create node/test/bundle-integration.test.mjs with multi-file CSS bundling scenarios
  • [ ] Test circular dependency handling, asset inlining, CSS variable substitution across files, and source map accuracy
  • [ ] Add edge cases: empty files, deeply nested imports, vendor prefixes in bundled output, and minification during bundling
  • [ ] Reference the bundler feature flag in Cargo.toml to ensure tests only run when bundler is enabled

🌿Good first issues

  • idea: Add comprehensive test coverage for CSS Grid minification (src/rules/mod.rs likely contains grid logic): write test cases validating that complex grid-template-areas compress correctly across browser targets. Check for missing .test.rs files or examples/.
  • idea: Document the visitor pattern for custom AST traversal: add an example in examples/ (following examples/custom_at_rule.rs) showing how to write a custom visitor using the #[derive(Visit)] macro to rewrite vendor-prefixed properties—fill a likely gap in derive/src/visit.rs usage docs.
  • idea: Improve TypeScript definitions in node/index.d.ts: audit property type exports against actual CSS specs (Color Level 5, CSS Logical Properties), add missing JSDoc comments for public methods, and add examples showing how to parse + transform a CSS rule using the Node.js API.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • df63db2 — Add support for ::highlight (#970) (lucasweng)
  • 3023317 — Add docs for external resolvers (devongovett)
  • 7f8a861 — v1.32.0 (devongovett)
  • 836741b — update compat data (devongovett)
  • 5ee613d — test: remove unwrap() in test helpers and print explicit error line context (#1173) (yisibl)
  • 201c4db — Convert the percentage in the scale property or scale() to a number (#1174) (yisibl)
  • 96c5c6d — Allow visitors to add dependencies (#1170) (devongovett)
  • 4fe3a4b — Enable custom resolvers to mark imports as external (#880) (sapphi-red)
  • da5b491 — Add mix-blend-mode property support (#1148) (ElirazKed)
  • 3fa29c7 — fix: keep a single space between functions when formatting transform values (#1145) (yisibl)

🔒Security observations

The Lightning CSS project demonstrates a generally solid security posture as a Rust-based parser library. The main concerns are: (1) incomplete dependency specification in the provided Cargo.toml excerpt preventing full verification, (2) lack of a SECURITY.md vulnerability reporting policy, (3) use of maintenance-mode 'lazy_static' crate, and (4) complexity introduced by multiple language bindings (C FFI, Node.js NAPI, WASM) which expand the attack surface. The project benefits from Rust's memory safety guarantees, but should establish clearer security communication channels and modernize legacy dependencies. No hardcoded secrets, SQL injection risks, or obvious misconfigurations were detected in the analyzed files.

  • Medium · Incomplete Dependency Version in Cargo.toml — Cargo.toml - [dependencies] section, 'atty' package. The 'atty' dependency version specification appears to be truncated in the provided Cargo.toml excerpt (shown as '{ version = "'). This makes it impossible to verify if the dependency version is secure and up-to-date. Incomplete version specifications could lead to unpredictable dependency resolution. Fix: Ensure all dependency versions are completely specified with exact versions or secure version ranges (e.g., '0.4.0' or '>=0.4.0, <1.0.0'). Run 'cargo update' and verify all dependencies are properly resolved.
  • Medium · Use of Jemalloc in CLI Feature — Cargo.toml - [features] section, 'cli' feature declaration. The 'jemallocator' dependency is included in the 'cli' feature. While Jemalloc is generally stable, allocator selection can have security implications around memory safety. Additionally, Jemalloc adds complexity and is less vetted than the default Rust allocator for security purposes. Fix: Consider using the default Rust allocator unless there is a specific performance requirement documented. If Jemalloc is necessary, ensure it's regularly updated and monitor security advisories for the dependency.
  • Low · No SECURITY.md File — Repository root. The repository lacks a SECURITY.md file, which is a standard practice for open-source projects to communicate security policies, vulnerability reporting procedures, and supported versions. Fix: Create a SECURITY.md file following the GitHub security advisory template. Include information on: vulnerability reporting process, supported versions receiving security updates, and contact information.
  • Low · Lazy Static Usage — Cargo.toml - [dependencies] section, 'lazy_static' package. The codebase uses 'lazy_static' dependency (version 1.4.0). While not inherently insecure, this crate is in maintenance mode and 'once_cell' or 'std::sync::OnceLock' (Rust 1.70+) are recommended as modern replacements. Fix: Migrate from 'lazy_static' to 'once_cell' for better maintained code, or use 'std::sync::OnceLock' if MSRV (Minimum Supported Rust Version) is 1.70 or higher. This improves maintainability and security posture.
  • Low · Multiple Binary Targets and Workspace Members — Cargo.toml - [workspace] members and [[bin]] declarations. The workspace includes multiple members (node, napi, c, etc.) and generates various binary outputs (CLI, WASM, Node.js bindings, C bindings). Each target expands the attack surface and requires separate security review. Fix: Maintain an inventory of all build targets and their exposure. Ensure each binding (C FFI, NAPI, WASM) is regularly audited for security issues. Consider using 'cargo-audit' in CI/CD pipelines for all workspace members.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · parcel-bundler/lightningcss — RepoPilot