Oxide (Oxide v0.2.1)

Copy Markdown View Source

Elixir bindings for Tailwind CSS Oxide — the Rust-powered content scanner.

Oxide scans source files in parallel to extract Tailwind CSS candidate class names. It powers the fast incremental rebuilds in Tailwind CSS v4.

Usage

Create a scanner, scan for candidates, then feed them to the Tailwind compiler to generate CSS.

# Create a scanner for your project
scanner = Oxide.new(sources: [%{base: "lib/", pattern: "**/*.heex"}])

# Full scan — returns all candidates found across all files
candidates = Oxide.scan(scanner)
# ["flex", "sm:bg-red-500", "hover:text-white", ...]

# Incremental scan — only returns NEW candidates from changed files
new = Oxide.scan_files(scanner, [%{file: "lib/app_web/live/page.ex", extension: "ex"}])

For one-off extraction without a scanner:

candidates = Oxide.extract(~s(class="flex bg-red-500"), "html")
# [%{value: "class", position: 0}, %{value: "flex", position: 7}, ...]

Summary

Functions

Extract candidates with byte positions from a string.

Get all files discovered by the scanner.

Get generated glob patterns for setting up file watchers.

Create a new scanner.

Full scan — walks filesystem, extracts all candidates.

Incremental scan — extract candidates from specific changed files.

Functions

extract(content, extension)

@spec extract(String.t(), String.t()) :: [Oxide.Candidate.t()]

Extract candidates with byte positions from a string.

Stateless — does not require a scanner. Useful for one-off extraction.

Examples

candidates = Oxide.extract(~s(class="flex bg-red-500"), "html")
[%Oxide.Candidate{value: "class", position: 0}, ...]

files(scanner)

@spec files(reference()) :: [String.t()]

Get all files discovered by the scanner.

globs(scanner)

@spec globs(reference()) :: [Oxide.Glob.t()]

Get generated glob patterns for setting up file watchers.

new(opts \\ [])

@spec new(keyword()) :: reference()

Create a new scanner.

Options

  • :sources — list of source entries, each a map or %Oxide.Source{} with :base, :pattern, and optional :negated (default false)

Examples

scanner = Oxide.new(sources: [
  %{base: "lib/", pattern: "**/*.{ex,heex}"},
  %{base: "assets/", pattern: "**/*.vue"}
])

scan(scanner)

@spec scan(reference()) :: [String.t()]

Full scan — walks filesystem, extracts all candidates.

Returns a sorted, deduplicated list of candidate strings. Subsequent calls only return candidates from files changed since the last scan.

scan_files(scanner, changed)

@spec scan_files(reference(), [map()]) :: [String.t()]

Incremental scan — extract candidates from specific changed files.

Returns only NEW candidates not seen in previous scans. This is what makes HMR fast.

Examples

new_candidates = Oxide.scan_files(scanner, [
  %{file: "lib/app_web/live/page.ex", extension: "ex"}
])

# Or with inline content (no filesystem read):
new_candidates = Oxide.scan_files(scanner, [
  %{content: ~s(class="flex mt-4"), extension: "html"}
])