Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,296 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZigCSS — Native by design. Correct by contract.

ZigCSS

Build npm License: MIT

Native by design. Fast on purpose. Correct by contract.

Compile CSS. Keep the meaning.

Five languages in. One deterministic compiler out.

ZigCSS is an experimental native Zig CSS compiler built for low-overhead builds, deterministic output, and semantics-preserving transforms. It treats CSS like a language—not a string to rewrite until it looks smaller.

The current source snapshot compiles CSS, SCSS, indented Sass, Less, and Stylus through self-contained native Zig paths. All five machine rows are native-graduated; executable plugin parity remains outside the contract.

Website · Input/output lab · Get started · Documentation · npm · Releases

Experimental prerelease: ZigCSS 0.6.0-rc.2 is published through its immutable matching tag as a GitHub prerelease and on npm next. npm latest remains the stable 0.3.0 line; evaluate the prerelease before production.

Native dependency-free migration

Publication of the provider-backed 0.5 candidate was cancelled before tagging. Dart Sass 1.101.0, Less 4.6.7, and Stylus 0.64.0 remain development-only reference oracles. They judge differential tests but do not enter the compiler, release archives, installed production graph, or compilation runtime.

The current native package contract has zero dependencies and zero optionalDependencies. The compiler itself starts no child process, performs no network access, and requires no runtime download. Five archive and offline-package jobs cover Linux x64/arm64, macOS x64/arm64, and Windows x64.

Publication is verified: nativeReleaseReady: true remains bound to exact version 0.6.0-rc.2 after all nine pre-tag evidence surfaces passed. GitHub prerelease and npm next publication are verified from the one immutable tag workflow; the published package carries npm provenance, and npm latest remains unchanged.

NATIVE-008 closed the finite source-capability inventory. NATIVE-009 graduates the four preprocessor machine rows together and closes the exact release terminal with five native archives, 25 release assets, one GitHub prerelease, and npm next; executable plugin parity remains outside the contract.

Why ZigCSS

What matters ZigCSS contract
Native execution All five source inputs share native Zig compilation paths; the JavaScript delivery shim only invokes the binary.
Semantic safety Transform classes stay unavailable until equivalence, idempotence, and independent-parser gates pass.
Failure behavior Compilation is atomic. An error, cancellation, limit, or allocation failure returns no partial CSS.
Determinism Replay, batch order, parallel workers, source maps, diagnostics, and packaging have executable checks.
Ownership CSS, diagnostics, dependencies, source maps, module exports, and profile data share one explicit result lifetime.
Delivery Linux x64/arm64, macOS x64/arm64, and Windows x64 archive paths are tested.

Your CSS deserves a real compiler: bounded input, a recovery-disabled parser, explicit transforms, strict output validation, and an atomic write at the end.

Install

Install the public five-language prerelease:

npm install --save-dev zigcss@next

Compile CSS:

npx zigcss input.css -o dist/output.css --minify

Input:

.button {
  color: #08100b;
  background: #c8ff55;
}

Output:

.button{color:#08100b;background:#c8ff55}

Successful commands exit 0; compilation and I/O failures exit 1; usage or configuration failures exit 2.

Five syntaxes, one CSS destination

The published prerelease exposes explicit native CLI selection while keeping executable plugin boundaries separate from language graduation.

Input Source snapshot execution path Machine migration state
CSS (.css) Native ZigCSS tokenizer/parser native-graduated
SCSS (.scss) Native Sass-family parser/evaluator native-graduated
Sass (.sass) Native Sass-family parser/evaluator native-graduated
Less (.less) Native Less parser/evaluator native-graduated
Stylus (.styl) Native Stylus parser/evaluator native-graduated

native-graduated means the pinned corpus, negative/resource, deterministic, generated-CSS, product-routing, package, five-target, documentation, release, and publication gates pass on the same immutable candidate. It does not grant executable provider or plugin extension points.

To build the published five-language source snapshot locally:

git clone https://github.com/vyakymenko/zigcss.git
cd zigcss
zig build

zig-out/bin/zigcss --syntax css styles.css -o dist/styles.css --minify
zig-out/bin/zigcss --syntax scss styles.scss -o dist/styles.css --minify
zig-out/bin/zigcss --syntax sass styles.sass -o dist/styles.css --minify
zig-out/bin/zigcss --syntax less styles.less -o dist/styles.css --minify
zig-out/bin/zigcss --syntax stylus styles.styl -o dist/styles.css --minify

--syntax is deliberate: the compiler does not infer a native preprocessor route from the filename alone. Imports stay inside the entry directory and explicitly admitted load paths.

Arbitrary Sass plugins, custom functions and importers, Less JavaScript and plugins, Stylus plugins and evaluator hooks, and executable project code remain outside the native product contract.

zig-out/bin/zigcss --syntax scss src/app.scss \
  --load-path src/tokens \
  --source-map \
  --minify \
  -o dist/app.css

See the format compatibility matrix, CSS compatibility matrix, and current capability status.

Benchmarks

ZigCSS is engineered for a low-overhead native path, but this project does not turn a laptop stopwatch into a marketing multiplier.

The benchmark program is already executable and publication-gated:

Evidence gate Required proof
Semantic equivalence Every timed output must pass independent CSS admission before its timing is accepted.
Workload coverage Small, medium, and large deterministic corpora are versioned and checksum-bound.
Execution modes Cold CLI, warm CLI, in-process API, allocator memory, and throughput stay separately labeled.
Statistics 43 ordered series and 860 raw observations are retained—never only the winning median.
Hardware The publishable archive must come from dedicated, non-emulated, controlled Linux x64 hardware.
Reproduction Source SHA, runner identity, tool versions, raw report, manifest, digest, and artifact link are sealed together.

Current status: the pipeline is ready, but the final controlled runner archive does not exist yet. Timing, ranking, throughput, memory, and ratio numbers remain unpublished until that evidence lands.

Read the benchmark report and publication contract. When the controlled archive passes, the report and this section can be generated from retained evidence instead of hand-edited hype.

Compiler pipeline

source bytes
    ↓
bounded lexer and parser
    ↓
typed, safety-classed transforms
    ↓
recovery-disabled CSS validation
    ↓
owned result + atomic output

The source-built executable is written to zig-out/bin/zigcss and routes all five inputs through native Zig code. The package JavaScript wrapper only locates and invokes the installed native binary; it does not host language semantics. Reference providers and their host remain development-only differential tools.

JavaScript wrapper

The installed package exports a thin launcher. It forwards the closed CLI arguments to the packaged binary, preserves exit and signal behavior, and implements no parser, evaluator, provider host, or fallback. A public programmatic JavaScript preprocessor API is not claimed by this snapshot.

Zig API

The stable zigcss.compile example remains CSS-only. It returns one owned compile result; call deinit exactly once.

const std = @import("std");
const zigcss = @import("zigcss");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();

    var result = try zigcss.compile(
        gpa.allocator(),
        "input.css",
        ".notice { color: red; }",
        .{ .format = .minified },
    );
    defer result.deinit();
    if (result.diagnostics.len != 0) return error.InvalidCss;

    var buffer: [1024]u8 = undefined;
    var writer = std.fs.File.stdout().writer(&buffer);
    try writer.interface.writeAll(result.css);
    try writer.interface.flush();
}

The explicitly experimental zigcss.experimental_native namespace covers the finite SCSS, indented Sass, Less, and Stylus source set. This compiled example parameterizes all four rows, keeps resolver roots explicit, checks exact deterministic CSS, and deinitializes every owned result:

const std = @import("std");
const zigcss = @import("zigcss");

const native = zigcss.experimental_native;

const Example = struct {
    syntax: native.Syntax,
    filename: []const u8,
    source: []const u8,
    expected: []const u8,
};

const examples = [_]Example{
    .{ .syntax = .scss, .filename = "example.scss", .source = "$color: red; .card { color: $color; }", .expected = ".card{color:red}" },
    .{ .syntax = .sass, .filename = "example.sass", .source = "$color: red\n.card\n  color: $color\n", .expected = ".card{color:red}" },
    .{ .syntax = .less, .filename = "example.less", .source = "@color: red; .card { color: @color; }", .expected = ".card{color:red}" },
    .{ .syntax = .stylus, .filename = "example.styl", .source = "color = red\n.card\n  color color\n", .expected = ".card{color:#f00}" },
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const root = try std.fs.cwd().realpathAlloc(allocator, ".");
    defer allocator.free(root);

    var buffer: [1024]u8 = undefined;
    var writer = std.fs.File.stdout().writer(&buffer);
    inline for (examples) |example| {
        const entry = try std.fs.path.join(allocator, &.{ root, example.filename });
        defer allocator.free(entry);
        var result = try native.compile(allocator, entry, example.source, .{
            .syntax = example.syntax,
            .root_paths = &.{root},
            .format = .minified,
        });
        defer result.deinit();
        if (result.diagnostics.len != 0 or !std.mem.eql(u8, result.css, example.expected)) {
            return error.UnexpectedNativeResult;
        }
        try writer.interface.print("{s}\n", .{result.css});
    }
    try writer.interface.flush();
}

The same documentation gate executes the five committed files under examples/native through the source-built binary with explicit --syntax. Neither example invokes a provider, child language engine, plugin, network service, or runtime download.

build.zig.zon gives the source package stable identity zigcss. The build module exposes helpers.addCssCompile for declared CSS inputs and generated outputs. See examples/build-integration.

Build and verify

Use Zig 0.15.2:

npm ci
zig build
zig build test --summary all
zig build test -Doptimize=ReleaseSafe --summary all
npm run test:preprocessor-product
npm run test:formats

The native migration boundary is machine-readable and fail-closed:

npm run test:native-contract
npm run check:native-contract

ADR-013 defines the self-contained native frontend contract.

Editor integration

The experimental CSS LSP covers bounded JSON-RPC framing, full document sync, UTF-16 positions, pull diagnostics, and syntax-aware open-document features.

Its release checks pass large-document, Unicode, malformed-request, leak, and editor-integration gates.

  • The VS Code preview uses Marketplace version 0.6.0 for the current CSS core mapping and requires a separately installed ZigCSS binary.
  • The Neovim configuration uses the built-in LSP client and an explicit trusted executable path.

Neither integration bundles a compiler binary.

Editor integrations remain CSS-only today. They do not silently execute preprocessor plugins or project code.

Project status

  • Native prerelease: 0.6.0-rc.2 is published from its immutable tag on GitHub and npm next; it remains experimental.
  • CSS core: native-graduated.
  • SCSS, indented Sass, Less, and Stylus: native-graduated after parser/evaluator, pinned conformance, native product-routing, package, five-target, and pre-tag release gates.
  • Production package closure: verified with zero production dependencies and no provider or host bytes; the compiler itself starts no child process and performs no network access.
  • Reference engines: retained only as exact development oracles and excluded from production bytes and runtime execution.
  • Public capability graduation: all seven predeclared NATIVE-008 surfaces match native evidence; NATIVE-009 binds the exact published identity and verified two-channel terminal.
  • Controlled comparative benchmark: waiting for the dedicated Linux x64 archive.
  • Publication: verified through the single authorized immutable tag outcome, one GitHub prerelease with 25 assets, and npm next with provenance; npm latest remains 0.3.0.

The development plan and durable execution ledger remain in the repository until the native roadmap, release, and benchmark gates close.

Contributing

Bring a minimal source input, expected semantics, actual output or diagnostic, and the relevant language-engine version. Run the focused language gate plus Debug and ReleaseSafe before opening a pull request.

High-value contributions include reduced compatibility cases, independent CSS validation, fuzz seeds, controlled benchmark runner capacity, and integrations that preserve the closed execution boundary.

License

MIT. See LICENSE.

About

Fast, zero-dependency CSS compiler built with Zig. Compile-time optimizations and minimal runtime overhead.

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages