A CSS parser, transformer, and minifier written in Rust with Node.js bindings
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Bundle CSS files with dependency resolution, @import inlining, and asset tracking for complete CSS processing pipelines that combine multiple files into optimized output.
Synchronously bundles a CSS file and its dependencies by inlining @import rules.
/**
* Bundles a CSS file and its dependencies, inlining @import rules
* @param options - Bundle configuration options (same as transform but without code)
* @returns Bundle result with combined CSS and dependency information
*/
function bundle<C extends CustomAtRules>(
options: BundleOptions<C>
): TransformResult;
type BundleOptions<C extends CustomAtRules> = Omit<TransformOptions<C>, 'code'>;Usage Examples:
import { bundle } from "lightningcss";
// Basic CSS bundling
const result = bundle({
filename: "src/main.css", // Entry point CSS file
minify: true,
targets: {
chrome: 90 << 16,
firefox: 88 << 16
}
});
console.log(new TextDecoder().decode(result.code));
// Bundle with CSS modules
const moduleBundle = bundle({
filename: "src/components/index.css",
cssModules: true,
minify: true
});
console.log(moduleBundle.exports); // Combined CSS module exportsAsynchronously bundles CSS files with custom resolver support for advanced file loading scenarios.
/**
* Bundles a CSS file and its dependencies asynchronously, inlining @import rules
* @param options - Async bundle configuration with optional custom resolver
* @returns Promise resolving to bundle result
*/
function bundleAsync<C extends CustomAtRules>(
options: BundleAsyncOptions<C>
): Promise<TransformResult>;
interface BundleAsyncOptions<C extends CustomAtRules> extends BundleOptions<C> {
resolver?: Resolver;
}Usage Examples:
import { bundleAsync } from "lightningcss";
// Async bundling with default file system resolver
const result = await bundleAsync({
filename: "src/styles.css",
minify: true,
sourceMap: true
});
// Custom resolver for non-file-system sources
const customResult = await bundleAsync({
filename: "virtual://main.css",
resolver: {
async resolve(specifier, originatingFile) {
// Custom resolution logic (e.g., resolve from database, URL, etc.)
if (specifier.startsWith('virtual://')) {
return specifier;
}
return path.resolve(path.dirname(originatingFile), specifier);
},
async read(file) {
// Custom file reading logic
if (file.startsWith('virtual://')) {
return await fetchFromDatabase(file);
}
return await fs.readFile(file, 'utf8');
}
}
});Define custom file resolution and reading logic for advanced bundling scenarios.
/** Custom resolver to use when loading CSS files. */
interface Resolver {
/** Read the given file and return its contents as a string. */
read?: (file: string) => string | Promise<string>;
/**
* Resolve the given CSS import specifier from the provided originating file to a
* path which gets passed to `read()`.
*/
resolve?: (specifier: string, originatingFile: string) => string | Promise<string>;
}Usage Examples:
import { bundleAsync } from "lightningcss";
import path from "path";
import fs from "fs/promises";
// URL-based resolver
const urlResolver: Resolver = {
async resolve(specifier, originatingFile) {
if (specifier.startsWith('http')) {
return specifier; // Keep URLs as-is
}
if (originatingFile.startsWith('http')) {
return new URL(specifier, originatingFile).href;
}
return path.resolve(path.dirname(originatingFile), specifier);
},
async read(file) {
if (file.startsWith('http')) {
const response = await fetch(file);
return await response.text();
}
return await fs.readFile(file, 'utf8');
}
};
const result = await bundleAsync({
filename: "https://cdn.example.com/styles.css",
resolver: urlResolver,
minify: true
});
// Package-based resolver
const packageResolver: Resolver = {
async resolve(specifier, originatingFile) {
if (specifier.startsWith('@')) {
// Resolve scoped packages from node_modules
return require.resolve(specifier + '/style.css');
}
return path.resolve(path.dirname(originatingFile), specifier);
},
async read(file) {
return await fs.readFile(file, 'utf8');
}
};Process the bundling results to extract combined CSS, source maps, and dependency information.
// Bundle results use the same TransformResult interface
interface TransformResult {
/** The bundled and transformed CSS code. */
code: Uint8Array;
/** The generated source map, if enabled. */
map: Uint8Array | void;
/** Combined CSS module exports from all bundled files, if enabled. */
exports: CSSModuleExports | void;
/** CSS module references from all bundled files. */
references: CSSModuleReferences;
/** All dependencies found during bundling, if enabled. */
dependencies: Dependency[] | void;
/** Warnings that occurred during bundling. */
warnings: Warning[];
}Usage Examples:
import { bundle } from "lightningcss";
import fs from "fs";
const result = bundle({
filename: "src/main.css",
sourceMap: true,
cssModules: true,
analyzeDependencies: true,
minify: true
});
// Write bundled CSS
fs.writeFileSync('dist/bundle.css', result.code);
// Write source map if generated
if (result.map) {
fs.writeFileSync('dist/bundle.css.map', result.map);
}
// Process CSS module exports
if (result.exports) {
const moduleMap = Object.fromEntries(
Object.entries(result.exports).map(([key, value]) => [key, value.name])
);
fs.writeFileSync('dist/css-modules.json', JSON.stringify(moduleMap, null, 2));
}
// Log dependency information
if (result.dependencies) {
console.log('Bundle dependencies:');
result.dependencies.forEach(dep => {
console.log(` ${dep.type}: ${dep.url}`);
});
}
// Handle warnings
if (result.warnings.length > 0) {
console.warn('Bundle warnings:');
result.warnings.forEach(warning => {
console.warn(` ${warning.message} at ${warning.loc.filename}:${warning.loc.line}:${warning.loc.column}`);
});
}Enable dependency analysis during bundling to track @import and url() dependencies.
interface DependencyOptions {
/** Whether to preserve `@import` rules rather than removing them. */
preserveImports?: boolean;
}Usage Examples:
const result = bundle({
filename: "src/main.css",
analyzeDependencies: {
preserveImports: false // Default: remove @import rules after inlining
},
minify: true
});
// Dependencies contain all @import and url() references
result.dependencies?.forEach(dep => {
if (dep.type === 'import') {
console.log(`Imported: ${dep.url} with media: ${dep.media}`);
} else if (dep.type === 'url') {
console.log(`Asset: ${dep.url}`);
}
});