grass_compiler

The Rust engine that powers the grass Sass-to-CSS compiler, exposing its lexer, parser, evaluator, and serializer directly.

Library
Cargo
v0.13.4
591stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
38/100Needs Attention
Development Activity0
Maintenance0
Community64
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
67/100Good
Architecture85
Code Quality78
Innovation65
Learning Curve40

grass_compiler is the internal engine behind the grass crate, a from-scratch Rust implementation of a Sass/SCSS-to-CSS compiler that targets close compatibility with the dart-sass reference implementation. While the top-level grass crate offers a small, stable two-function API, grass_compiler exposes the full pipeline underneath it — lexer, multi-syntax parser, AST, tree-walking evaluator, native selector engine, and serializer — for tools that need lower-level control, such as custom builtin functions, alternate filesystem backends, or embedding a Sass compiler in a Rust program without shelling out to Node or Dart.

Because it backs a production compiler benchmarked at roughly twice the speed of dart-sass and tested on every release against thousands of commits of Bootstrap’s SCSS source, grass_compiler is a reasonable fit for build tooling, static site generators, and CSS pipelines written in Rust that want Sass support without a JavaScript or Dart runtime dependency. The crate deliberately ships frequent breaking changes as an explicitly “internal” surface, so consumers pin exact versions and treat it as an implementation detail of grass rather than a standalone stable API.

What You Get

  • Full compiler pipeline access - lexer, parser (SCSS/Sass/CSS), AST, evaluator, and serializer modules exposed as public APIs instead of a single opaque function.
  • Pluggable filesystem abstraction - Fs/StdFs/NullFs traits let you resolve @import/@use paths from anything, not just the local disk.
  • Custom builtin functions - the custom-builtin-fns feature flag exposes the Builtin and Visitor types needed to register your own Sass functions.
  • WebAssembly export support - an optional wasm-exports feature compiles the engine to WASM for use in JS-hosted tooling.
  • Structured, dart-sass-style errors - SassError/ErrorKind carry source spans so host tools can render Sass-style error output with carets and line context.

Common Use Cases

  • Embedding Sass compilation in a Rust build tool - a bundler or static site generator author calls grass_compiler directly to compile SCSS at build time without invoking dart-sass over a subprocess.
  • Building a custom Sass toolchain - a tooling author who needs custom builtin functions or a virtual filesystem uses the exposed Fs trait and Builtin API instead of the constrained top-level grass interface.
  • Compiling Sass to CSS inside WebAssembly - a browser-based playground or editor enables the wasm-exports feature to run the compiler client-side.
  • Powering downstream Rust crates - projects like grass itself and other Rust CSS tooling depend on grass_compiler as their evaluation engine rather than reimplementing a Sass parser.

Under The Hood

Architecture grass_compiler is a classic layered compiler: lexer.rs tokenizes source, dialect-specific recursive-descent parsers in parse/ (scss.rs, sass.rs, css.rs, sharing base.rs/stylesheet.rs) build a typed AST (ast/stmt.rs, expr.rs, mixin.rs, style.rs, media.rs), and evaluate::Visitor tree-walks that AST — resolving variables and scoping via evaluate/env.rs/scope.rs, arithmetic via bin_op.rs, and control flow (@each, @for, @while, @use/@forward) — to assemble an intermediate css_tree, which serializer.rs renders to a final CSS string under a configurable OutputStyle. A dedicated selector module implements Sass’s own selector nesting, extension (@extend), and superselector logic natively rather than delegating to an external CSS selector library. I/O is injected through Fs/Logger traits rather than hardcoded, and builtin/ registers global functions and modules (sass:math, sass:color, etc.) that plug into the same visitor. The central evaluate::visitor.rs is large and touched by nearly every language feature, which concentrates complexity but keeps the interpreter’s semantics in one place.

Tech Stack The crate targets Rust edition 2021 with an MSRV of 1.70 and has no networked or async dependencies — it’s a pure compiler library. Notable dependencies: codemap for source-span tracking behind dart-sass-style error messages, phf for perfect-hash builtin function lookup, indexmap for ordered Sass maps and keyword arguments, lasso for string interning (interner.rs), once_cell for lazily-initialized statics, and optional rand (feature random) and wasm-bindgen (feature wasm-exports). A sibling include_sass proc-macro crate depends on syn to compile Sass to CSS at Rust compile time. CI runs cargo test, cargo fmt --check, and cargo clippy -D warnings, plus a bootstrap job that diffs grass’s compiled output against the real dart-sass binary run over Bootstrap 5’s full SCSS source.

Code Quality No unit tests live inside grass_compiler’s own source tree; instead the sibling grass crate (the public wrapper) carries an extensive black-box suite of 85+ test files, one per language feature (selectors, math, modules, at-rules, interpolation, and more), that exercises grass_compiler’s behavior through the public API on every CI run. Error handling is explicit and typed rather than panic-based: SassResult<T> = Result<T, Box<SassError>> is used pervasively, with a SassErrorKind enum that carries source location and Unicode-handling context for dart-sass-style diagnostics. Naming follows conventional Rust snake_case module and function styles. CI enforces formatting and denies clippy warnings (-D warnings) plus #![deny(missing_debug_implementations)] at the crate root, and no unsafe code was observed in the modules reviewed.

API Design grass_compiler follows a two-tier design: a small top-level entry point (from_string/from_path plus Options) mirrors the public grass crate’s simple API, while sass_value, sass_ast, Visitor, Builtin, and the Fs/Logger traits are re-exported as an escape hatch for advanced embedding. Feature flags (random, wasm-exports, custom-builtin-fns, macro, nightly) keep the default build lean while letting consumers opt into extra capability. Documentation exists as module-level rustdoc comments and a runnable doctest in lib.rs demonstrating both library and CLI usage, but the crate’s own README is explicit that it “will see frequent breaking changes” and steers most users toward the stabler grass wrapper instead — a deliberate tradeoff of internal flexibility over external API stability.

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