0
# CSS Bundling
1
2
Bundle CSS files with dependency resolution, @import inlining, and asset tracking for complete CSS processing pipelines that combine multiple files into optimized output.
3
4
## Capabilities
5
6
### Bundle Function
7
8
Synchronously bundles a CSS file and its dependencies by inlining @import rules.
9
10
```typescript { .api }
11
/**
12
* Bundles a CSS file and its dependencies, inlining @import rules
13
* @param options - Bundle configuration options (same as transform but without code)
14
* @returns Bundle result with combined CSS and dependency information
15
*/
16
function bundle<C extends CustomAtRules>(
17
options: BundleOptions<C>
18
): TransformResult;
19
20
type BundleOptions<C extends CustomAtRules> = Omit<TransformOptions<C>, 'code'>;
21
```
22
23
**Usage Examples:**
24
25
```typescript
26
import { bundle } from "lightningcss";
27
28
// Basic CSS bundling
29
const result = bundle({
30
filename: "src/main.css", // Entry point CSS file
31
minify: true,
32
targets: {
33
chrome: 90 << 16,
34
firefox: 88 << 16
35
}
36
});
37
38
console.log(new TextDecoder().decode(result.code));
39
40
// Bundle with CSS modules
41
const moduleBundle = bundle({
42
filename: "src/components/index.css",
43
cssModules: true,
44
minify: true
45
});
46
47
console.log(moduleBundle.exports); // Combined CSS module exports
48
```
49
50
### Bundle Async Function
51
52
Asynchronously bundles CSS files with custom resolver support for advanced file loading scenarios.
53
54
```typescript { .api }
55
/**
56
* Bundles a CSS file and its dependencies asynchronously, inlining @import rules
57
* @param options - Async bundle configuration with optional custom resolver
58
* @returns Promise resolving to bundle result
59
*/
60
function bundleAsync<C extends CustomAtRules>(
61
options: BundleAsyncOptions<C>
62
): Promise<TransformResult>;
63
64
interface BundleAsyncOptions<C extends CustomAtRules> extends BundleOptions<C> {
65
resolver?: Resolver;
66
}
67
```
68
69
**Usage Examples:**
70
71
```typescript
72
import { bundleAsync } from "lightningcss";
73
74
// Async bundling with default file system resolver
75
const result = await bundleAsync({
76
filename: "src/styles.css",
77
minify: true,
78
sourceMap: true
79
});
80
81
// Custom resolver for non-file-system sources
82
const customResult = await bundleAsync({
83
filename: "virtual://main.css",
84
resolver: {
85
async resolve(specifier, originatingFile) {
86
// Custom resolution logic (e.g., resolve from database, URL, etc.)
87
if (specifier.startsWith('virtual://')) {
88
return specifier;
89
}
90
return path.resolve(path.dirname(originatingFile), specifier);
91
},
92
93
async read(file) {
94
// Custom file reading logic
95
if (file.startsWith('virtual://')) {
96
return await fetchFromDatabase(file);
97
}
98
return await fs.readFile(file, 'utf8');
99
}
100
}
101
});
102
```
103
104
### Custom Resolver Interface
105
106
Define custom file resolution and reading logic for advanced bundling scenarios.
107
108
```typescript { .api }
109
/** Custom resolver to use when loading CSS files. */
110
interface Resolver {
111
/** Read the given file and return its contents as a string. */
112
read?: (file: string) => string | Promise<string>;
113
114
/**
115
* Resolve the given CSS import specifier from the provided originating file to a
116
* path which gets passed to `read()`.
117
*/
118
resolve?: (specifier: string, originatingFile: string) => string | Promise<string>;
119
}
120
```
121
122
**Usage Examples:**
123
124
```typescript
125
import { bundleAsync } from "lightningcss";
126
import path from "path";
127
import fs from "fs/promises";
128
129
// URL-based resolver
130
const urlResolver: Resolver = {
131
async resolve(specifier, originatingFile) {
132
if (specifier.startsWith('http')) {
133
return specifier; // Keep URLs as-is
134
}
135
if (originatingFile.startsWith('http')) {
136
return new URL(specifier, originatingFile).href;
137
}
138
return path.resolve(path.dirname(originatingFile), specifier);
139
},
140
141
async read(file) {
142
if (file.startsWith('http')) {
143
const response = await fetch(file);
144
return await response.text();
145
}
146
return await fs.readFile(file, 'utf8');
147
}
148
};
149
150
const result = await bundleAsync({
151
filename: "https://cdn.example.com/styles.css",
152
resolver: urlResolver,
153
minify: true
154
});
155
156
// Package-based resolver
157
const packageResolver: Resolver = {
158
async resolve(specifier, originatingFile) {
159
if (specifier.startsWith('@')) {
160
// Resolve scoped packages from node_modules
161
return require.resolve(specifier + '/style.css');
162
}
163
return path.resolve(path.dirname(originatingFile), specifier);
164
},
165
166
async read(file) {
167
return await fs.readFile(file, 'utf8');
168
}
169
};
170
```
171
172
### Bundle Result Processing
173
174
Process the bundling results to extract combined CSS, source maps, and dependency information.
175
176
```typescript { .api }
177
// Bundle results use the same TransformResult interface
178
interface TransformResult {
179
/** The bundled and transformed CSS code. */
180
code: Uint8Array;
181
/** The generated source map, if enabled. */
182
map: Uint8Array | void;
183
/** Combined CSS module exports from all bundled files, if enabled. */
184
exports: CSSModuleExports | void;
185
/** CSS module references from all bundled files. */
186
references: CSSModuleReferences;
187
/** All dependencies found during bundling, if enabled. */
188
dependencies: Dependency[] | void;
189
/** Warnings that occurred during bundling. */
190
warnings: Warning[];
191
}
192
```
193
194
**Usage Examples:**
195
196
```typescript
197
import { bundle } from "lightningcss";
198
import fs from "fs";
199
200
const result = bundle({
201
filename: "src/main.css",
202
sourceMap: true,
203
cssModules: true,
204
analyzeDependencies: true,
205
minify: true
206
});
207
208
// Write bundled CSS
209
fs.writeFileSync('dist/bundle.css', result.code);
210
211
// Write source map if generated
212
if (result.map) {
213
fs.writeFileSync('dist/bundle.css.map', result.map);
214
}
215
216
// Process CSS module exports
217
if (result.exports) {
218
const moduleMap = Object.fromEntries(
219
Object.entries(result.exports).map(([key, value]) => [key, value.name])
220
);
221
fs.writeFileSync('dist/css-modules.json', JSON.stringify(moduleMap, null, 2));
222
}
223
224
// Log dependency information
225
if (result.dependencies) {
226
console.log('Bundle dependencies:');
227
result.dependencies.forEach(dep => {
228
console.log(` ${dep.type}: ${dep.url}`);
229
});
230
}
231
232
// Handle warnings
233
if (result.warnings.length > 0) {
234
console.warn('Bundle warnings:');
235
result.warnings.forEach(warning => {
236
console.warn(` ${warning.message} at ${warning.loc.filename}:${warning.loc.line}:${warning.loc.column}`);
237
});
238
}
239
```
240
241
### Bundling with Import Analysis
242
243
Enable dependency analysis during bundling to track @import and url() dependencies.
244
245
```typescript { .api }
246
interface DependencyOptions {
247
/** Whether to preserve `@import` rules rather than removing them. */
248
preserveImports?: boolean;
249
}
250
```
251
252
**Usage Examples:**
253
254
```typescript
255
const result = bundle({
256
filename: "src/main.css",
257
analyzeDependencies: {
258
preserveImports: false // Default: remove @import rules after inlining
259
},
260
minify: true
261
});
262
263
// Dependencies contain all @import and url() references
264
result.dependencies?.forEach(dep => {
265
if (dep.type === 'import') {
266
console.log(`Imported: ${dep.url} with media: ${dep.media}`);
267
} else if (dep.type === 'url') {
268
console.log(`Asset: ${dep.url}`);
269
}
270
});
271
```