0
# @tailwindcss/oxide
1
2
@tailwindcss/oxide is a high-performance Node.js package that provides CSS class scanning and extraction for TailwindCSS builds. Built with Rust and optimized for speed, it serves as the core scanning engine for TailwindCSS v4+ builds, enabling rapid file discovery and CSS candidate extraction across multiple platforms.
3
4
## Package Information
5
6
- **Package Name**: @tailwindcss/oxide
7
- **Package Type**: npm
8
- **Language**: Rust with Node.js bindings (NAPI)
9
- **Installation**: `npm install @tailwindcss/oxide`
10
11
## Core Imports
12
13
```javascript
14
const { Scanner } = require("@tailwindcss/oxide");
15
```
16
17
For TypeScript:
18
19
```typescript
20
import { Scanner } from "@tailwindcss/oxide";
21
```
22
23
## Basic Usage
24
25
```javascript
26
const { Scanner } = require("@tailwindcss/oxide");
27
28
// Create scanner with source configuration
29
const scanner = new Scanner({
30
sources: [
31
{
32
base: "./src",
33
pattern: "**/*.{html,js,jsx,ts,tsx,vue,svelte}",
34
negated: false
35
}
36
]
37
});
38
39
// Scan for CSS candidates
40
const candidates = scanner.scan();
41
console.log(candidates); // ["flex", "bg-blue-500", "text-center", ...]
42
43
// Get discovered files
44
const files = scanner.files;
45
console.log(files); // ["/path/to/src/component.jsx", ...]
46
```
47
48
## Architecture
49
50
@tailwindcss/oxide is built around several key components:
51
52
- **Native Performance**: Rust-based core with Node.js bindings for maximum scanning speed
53
- **Platform Support**: Pre-built binaries for Linux, macOS, Windows, FreeBSD, Android, and WebAssembly
54
- **File Discovery**: Git-aware file scanning with configurable glob patterns and ignore rules
55
- **Content Processing**: Support for 15+ file formats with specialized preprocessors
56
- **Pattern Optimization**: Intelligent glob pattern consolidation for efficient file watching
57
58
## Capabilities
59
60
### File Scanning
61
62
Core file discovery and CSS candidate extraction from configured source patterns.
63
64
```typescript { .api }
65
class Scanner {
66
constructor(options: ScannerOptions);
67
68
/** Scan configured sources and return all CSS candidates */
69
scan(): string[];
70
71
/** Scan specific files/content and return CSS candidates */
72
scan_files(changedContent: ChangedContent[]): string[];
73
74
/** Extract candidates with their UTF-16 character positions in content (converted from byte positions) */
75
get_candidates_with_positions(changedContent: ChangedContent): CandidateWithPosition[];
76
77
/** Get list of discovered files to scan */
78
get files(): string[];
79
80
/** Get optimized glob patterns for file watching */
81
get globs(): GlobEntry[];
82
83
/** Get normalized source patterns */
84
get normalized_sources(): GlobEntry[];
85
}
86
87
interface ScannerOptions {
88
/** Array of source patterns to scan */
89
sources?: SourceEntry[];
90
}
91
```
92
93
**Usage Examples:**
94
95
```javascript
96
const { Scanner } = require("@tailwindcss/oxide");
97
98
// Basic file scanning
99
const scanner = new Scanner({
100
sources: [
101
{ base: "./src", pattern: "**/*.html", negated: false },
102
{ base: "./components", pattern: "**/*.jsx", negated: false }
103
]
104
});
105
106
const allCandidates = scanner.scan();
107
console.log(allCandidates); // ["bg-blue-500", "text-lg", "flex", ...]
108
109
// Incremental scanning with changed files
110
const newCandidates = scanner.scan_files([
111
{ file: "./src/new-component.jsx", extension: "jsx" },
112
{ content: "<div class='bg-red-500'>Hello</div>", extension: "html" }
113
]);
114
console.log(newCandidates); // ["bg-red-500"]
115
116
// Get candidates with positions for editor integration
117
const withPositions = scanner.get_candidates_with_positions({
118
content: "<div class='flex bg-blue-500'>Content</div>",
119
extension: "html"
120
});
121
console.log(withPositions);
122
// [
123
// { candidate: "class", position: 5 },
124
// { candidate: "flex", position: 12 },
125
// { candidate: "bg-blue-500", position: 17 }
126
// ]
127
```
128
129
### Content Processing
130
131
Handles various file formats and content types for CSS candidate extraction.
132
133
```typescript { .api }
134
interface ChangedContent {
135
/** File path to scan (optional, use with file-based scanning) */
136
file?: string;
137
138
/** Direct content to scan (optional, use with content-based scanning) */
139
content?: string;
140
141
/** File extension for content processing */
142
extension: string;
143
}
144
```
145
146
**Supported File Extensions:**
147
148
- **Web**: html, htm, jsx, tsx, vue, svelte
149
- **JavaScript**: js, ts, json
150
- **Templates**: pug, haml, erb, heex, eex
151
- **Styling**: css (for CSS variable extraction)
152
- **Other**: clj, cljs, cljc, ex, exs, cshtml, razor, rb, slim, slang, rs
153
154
**Usage Examples:**
155
156
```javascript
157
// Scan file by path
158
const candidates1 = scanner.scan_files([
159
{ file: "./src/component.vue", extension: "vue" }
160
]);
161
162
// Scan raw content
163
const candidates2 = scanner.scan_files([
164
{
165
content: `
166
<template>
167
<div class="flex items-center justify-between p-4">
168
<h1 class="text-2xl font-bold">Title</h1>
169
</div>
170
</template>
171
`,
172
extension: "vue"
173
}
174
]);
175
176
// Mixed scanning
177
const candidates3 = scanner.scan_files([
178
{ file: "./dist/app.js", extension: "js" },
179
{ content: "<div class='bg-green-500'>Dynamic</div>", extension: "html" }
180
]);
181
```
182
183
### Pattern Configuration
184
185
Configure source patterns for automatic file discovery and scanning.
186
187
```typescript { .api }
188
interface SourceEntry {
189
/** Base directory path */
190
base: string;
191
192
/** Glob pattern for source detection */
193
pattern: string;
194
195
/** Whether this is a negation pattern */
196
negated: boolean;
197
}
198
199
interface GlobEntry {
200
/** Base directory path */
201
base: string;
202
203
/** Glob pattern relative to base */
204
pattern: string;
205
}
206
```
207
208
**Usage Examples:**
209
210
```javascript
211
// Multiple source patterns
212
const scanner = new Scanner({
213
sources: [
214
// Include all HTML and JS files in src
215
{ base: "./src", pattern: "**/*.{html,js}", negated: false },
216
217
// Include components directory
218
{ base: "./components", pattern: "**/*", negated: false },
219
220
// Exclude test files
221
{ base: "./src", pattern: "**/*.test.js", negated: true },
222
223
// Include external library
224
{ base: "./node_modules/ui-library", pattern: "**/*.js", negated: false }
225
]
226
});
227
228
// Get optimized globs for file watchers
229
const globs = scanner.globs;
230
console.log(globs);
231
// [
232
// { base: "./src", pattern: "**/*.{html,js}" },
233
// { base: "./components", pattern: "**/*" }
234
// ]
235
236
// Get normalized source patterns
237
const sources = scanner.normalized_sources;
238
console.log(sources);
239
// [
240
// { base: "./src", pattern: "**/*" },
241
// { base: "./components", pattern: "**/*" }
242
// ]
243
```
244
245
### Position Tracking
246
247
Extract CSS candidates with their exact positions in source content for editor integration.
248
249
```typescript { .api }
250
interface CandidateWithPosition {
251
/** The extracted CSS candidate string */
252
candidate: string;
253
254
/** UTF-16 character position in source content (converted from byte position) */
255
position: number;
256
}
257
```
258
259
**Usage Examples:**
260
261
```javascript
262
const sourceCode = `
263
<div class="flex items-center bg-blue-500 text-white p-4">
264
<span class="font-bold">Hello World</span>
265
</div>
266
`;
267
268
const candidates = scanner.get_candidates_with_positions({
269
content: sourceCode,
270
extension: "html"
271
});
272
273
console.log(candidates);
274
// [
275
// { candidate: "class", position: 6 },
276
// { candidate: "flex", position: 13 },
277
// { candidate: "items-center", position: 18 },
278
// { candidate: "bg-blue-500", position: 31 },
279
// { candidate: "text-white", position: 43 },
280
// { candidate: "p-4", position: 55 },
281
// { candidate: "class", position: 68 },
282
// { candidate: "font-bold", position: 75 }
283
// ]
284
```
285
286
## Platform Support
287
288
@tailwindcss/oxide includes pre-built native binaries for optimal performance:
289
290
- **Linux**: x64/arm64 (glibc and musl)
291
- **macOS**: x64/arm64
292
- **Windows**: x64/arm64
293
- **FreeBSD**: x64
294
- **Android**: arm64
295
- **WebAssembly**: Universal fallback
296
297
The package automatically downloads the appropriate binary during installation via the postinstall script. If no native binary is available, it falls back to WebAssembly.
298
299
## Error Handling
300
301
The Scanner gracefully handles common error conditions:
302
303
- **Missing files**: If a file specified in `ChangedContent.file` doesn't exist, it throws an error with "Failed to read file"
304
- **Invalid glob patterns**: Skips invalid patterns and processes valid ones
305
- **Platform binary failures**: Falls back to WebAssembly or alternative download methods
306
- **UTF encoding issues**: Handles various text encodings in source files
307
- **Permission errors**: Skips inaccessible files and continues scanning
308
- **Content validation**: Either `file` or `content` must be provided in `ChangedContent`, but not both
309
310
## Performance Features
311
312
- **Parallel Processing**: Multi-threaded file scanning using Rust's Rayon library
313
- **Git Integration**: Respects .gitignore files and git repository boundaries
314
- **Pattern Optimization**: Consolidates glob patterns to reduce file system operations
315
- **Incremental Scanning**: Supports changed content tracking for efficient rebuilds
316
- **Memory Efficiency**: Streaming file processing with candidate deduplication