Node.js-specific utilities and runtime functionality for Tailwind CSS v4, providing compilation tools, module dependency analysis, source map handling, path normalization, and optimization utilities.
Recursive module dependency analysis with support for TypeScript, ESM, and CommonJS import patterns. Provides comprehensive dependency tracking for hot module reloading and build optimization.
Recursively analyzes module dependencies and returns all file paths.
/**
* Recursively traces all dependencies of a module
* Returns an unordered set of absolute file paths
* @param absoluteFilePath - Absolute path to the entry module file
* @returns Promise resolving to array of absolute dependency file paths
*/
function getModuleDependencies(absoluteFilePath: string): Promise<string[]>;Usage Examples:
import { getModuleDependencies } from "@tailwindcss/node";
import path from "path";
// Analyze a TypeScript module
const entryFile = path.resolve(process.cwd(), "src/index.ts");
const dependencies = await getModuleDependencies(entryFile);
console.log("Dependencies:", dependencies);
// Output: [
// "/path/to/project/src/index.ts",
// "/path/to/project/src/utils/helpers.ts",
// "/path/to/project/src/components/Button.tsx",
// "/path/to/project/src/types/index.ts"
// ]
// Analyze a JavaScript module
const jsFile = path.resolve(process.cwd(), "config/webpack.config.js");
const jsDependencies = await getModuleDependencies(jsFile);
console.log("JS Dependencies:", jsDependencies);Use dependency analysis for hot module reloading setup:
import { getModuleDependencies } from "@tailwindcss/node";
import { watch } from "chokidar";
async function setupHMR(entryFile: string) {
// Get all dependencies
const dependencies = await getModuleDependencies(entryFile);
// Watch all dependency files
const watcher = watch(dependencies, {
ignoreInitial: true
});
watcher.on('change', async (changedFile) => {
console.log(`File changed: ${changedFile}`);
// Re-analyze dependencies in case new ones were added
const newDependencies = await getModuleDependencies(entryFile);
// Update watcher with new dependencies
const newFiles = newDependencies.filter(file => !dependencies.includes(file));
if (newFiles.length > 0) {
watcher.add(newFiles);
dependencies.push(...newFiles);
}
// Trigger rebuild
await rebuild();
});
return watcher;
}
// Usage
const watcher = await setupHMR("./src/index.ts");Integration with build tools for dependency tracking:
import { getModuleDependencies } from "@tailwindcss/node";
// Webpack plugin example
class DependencyTrackingPlugin {
apply(compiler: any) {
compiler.hooks.compilation.tap('DependencyTrackingPlugin', (compilation: any) => {
compilation.hooks.buildModule.tapAsync('DependencyTrackingPlugin',
async (module: any, callback: Function) => {
if (module.resource) {
try {
const dependencies = await getModuleDependencies(module.resource);
// Add dependencies to webpack's dependency graph
dependencies.forEach(dep => {
if (dep !== module.resource) {
module.addDependency(createDependency(dep));
}
});
} catch (error) {
console.warn(`Failed to analyze dependencies for ${module.resource}:`, error);
}
}
callback();
}
);
});
}
}Use for bundle analysis and optimization:
import { getModuleDependencies } from "@tailwindcss/node";
import fs from "fs/promises";
async function analyzeBundleSize(entryPoints: string[]) {
const bundleAnalysis = new Map<string, {
size: number;
dependencies: string[];
}>();
for (const entry of entryPoints) {
const dependencies = await getModuleDependencies(entry);
let totalSize = 0;
for (const dep of dependencies) {
try {
const stats = await fs.stat(dep);
totalSize += stats.size;
} catch (error) {
console.warn(`Could not stat file: ${dep}`);
}
}
bundleAnalysis.set(entry, {
size: totalSize,
dependencies
});
}
return bundleAnalysis;
}
// Usage
const analysis = await analyzeBundleSize([
"./src/app.ts",
"./src/worker.ts"
]);
analysis.forEach((info, entry) => {
console.log(`${entry}: ${info.size} bytes, ${info.dependencies.length} files`);
});The dependency analysis recognizes various import and require patterns:
// Named imports
import { foo, bar } from './utils';
import { default as utils } from './utils';
// Default imports
import utils from './utils';
import * as utils from './utils';
// Side-effect imports
import './polyfills';
// Dynamic imports (string literals only)
const module = await import('./dynamic');// Basic require
const utils = require('./utils');
const { foo, bar } = require('./utils');
// Conditional requires (string literals)
if (condition) {
const optional = require('./optional');
}// Re-exports
export { foo } from './foo';
export * from './bar';
export { default } from './baz';
// Named exports with re-export
export { foo as publicFoo } from './internal';The module resolution follows Node.js conventions with TypeScript support:
For JavaScript files (.js, .cjs, .mjs):
.js.cjs.mjs.ts.cts.mts.jsx.tsxFor TypeScript files (.ts, .cts, .mts, .tsx):
.ts.cts.mts.tsx.js.cjs.mjs.jsx// For import './components'
// Tries in order:
// 1. ./components.ts (or appropriate extension)
// 2. ./components/index.ts
// 3. ./components/index.js
// etc.// The function handles circular dependencies gracefully
// Example: A.ts imports B.ts, B.ts imports A.ts
const dependencies = await getModuleDependencies("A.ts");
// Returns: ["A.ts", "B.ts"] (both files, no infinite loop)import { getModuleDependencies } from "@tailwindcss/node";
// For performance, implement your own caching layer
const dependencyCache = new Map<string, string[]>();
async function getCachedDependencies(filePath: string): Promise<string[]> {
if (dependencyCache.has(filePath)) {
return dependencyCache.get(filePath)!;
}
const dependencies = await getModuleDependencies(filePath);
dependencyCache.set(filePath, dependencies);
return dependencies;
}
// Invalidate cache when files change
function invalidateCache(filePath: string) {
dependencyCache.delete(filePath);
}import { getModuleDependencies } from "@tailwindcss/node";
// Analyze multiple entry points in parallel
async function analyzeMultipleEntries(entryPoints: string[]) {
const results = await Promise.all(
entryPoints.map(async (entry) => ({
entry,
dependencies: await getModuleDependencies(entry)
}))
);
return results;
}
const analysis = await analyzeMultipleEntries([
"./src/client.ts",
"./src/server.ts",
"./src/worker.ts"
]);The function handles various error conditions gracefully:
import { getModuleDependencies } from "@tailwindcss/node";
try {
const dependencies = await getModuleDependencies("./nonexistent.ts");
} catch (error) {
console.error("Analysis failed:", error.message);
// File may not exist or may have unresolvable dependencies
}
// Missing dependencies are silently skipped
const dependencies = await getModuleDependencies("./file-with-missing-deps.ts");
// Returns dependencies that could be resolved, skips missing ones./ or ../)require.context) are not supportedtessl i tessl/npm-tailwindcss--node@4.1.0docs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10