@richaadgigi/stylexui
Version:
Build responsive, beautiful interfaces faster than ever with utility-first classes and smart defaults. No bloat. No fuss. Just results.
114 lines (99 loc) • 4.62 kB
JavaScript
/**
* @richaadgigi/stylexui — withStylexui Next.js Plugin
*
* Wraps your next.config.js/ts to automatically:
* 1. Scan source files for dynamic xui utility classes (e.g. xui-pt-[24px])
* 2. Generate a static CSS file: public/xui-generated.css
* 3. Re-extract on every dev reload and production build
*
* Works with both Webpack and Turbopack.
*
* Usage in next.config.ts:
* const withStylexui = require('@richaadgigi/stylexui/withStylexui');
* module.exports = withStylexui({ ...yourNextConfig });
*
* Then add to your root layout's <head>:
* <link rel="stylesheet" href="/xui-generated.css" />
*
* The runtime xuiDynamicCSS() still handles classes added dynamically at runtime.
*/
;
const path = require('path');
const fs = require('fs');
const { extractDynamicCSS } = require('./scripts/extract-dynamic-css');
// ─── Sync Extraction (Turbopack + Webpack) ────────────────────────────────────
// Runs when next.config is evaluated — before any bundler kicks in.
// This ensures public/xui-generated.css always exists before the first request.
function runExtractionSync(outputPath, srcPatterns, cwd) {
// Run async extraction in a fire-and-forget manner from the sync context.
// Node's event loop will process this before webpack/turbopack starts compiling.
setImmediate(async () => {
try {
await extractDynamicCSS({ outputPath, srcPatterns, cwd });
} catch (e) {
console.warn('[stylexui] Initial CSS extraction warning:', e.message);
}
});
}
// ─── Webpack Plugin ───────────────────────────────────────────────────────────
// Re-runs extraction before every webpack compilation (handles dev HMR refreshes).
class StylexuiWebpackPlugin {
constructor(options) {
this.options = options;
}
apply(compiler) {
const { outputPath, srcPatterns, cwd } = this.options;
compiler.hooks.beforeCompile.tapAsync('StylexuiPlugin', async (params, callback) => {
try {
await extractDynamicCSS({ outputPath, srcPatterns, cwd });
} catch (e) {
console.warn('[stylexui] CSS extraction warning:', e.message);
}
callback();
});
}
}
// ─── withStylexui ─────────────────────────────────────────────────────────────
/**
* Wrap your Next.js config with the StylexUI build plugin.
*
* @param {object} nextConfig - Your existing Next.js config object
* @param {object} [xuiOptions]
* @param {string[]} [xuiOptions.srcPatterns] - Custom glob patterns to scan
* @param {string} [xuiOptions.outputFile] - Output filename inside public/ (default: 'xui-generated.css')
* @returns {object} Modified Next.js config
*/
function withStylexui(nextConfig = {}, xuiOptions = {}) {
const projectRoot = process.cwd();
const outputFileName = xuiOptions.outputFile || 'xui-generated.css';
const publicDir = path.join(projectRoot, 'public');
const outputPath = path.join(publicDir, outputFileName);
const srcPatterns = xuiOptions.srcPatterns || [
'src/**/*.{ts,tsx,js,jsx,html,mdx}',
'app/**/*.{ts,tsx,js,jsx,html,mdx}',
'pages/**/*.{ts,tsx,js,jsx,html,mdx}',
'components/**/*.{ts,tsx,js,jsx,html,mdx}',
];
// Run immediately when next.config is loaded (works with Turbopack + Webpack)
runExtractionSync(outputPath, srcPatterns, projectRoot);
return {
...nextConfig,
// Silence Next.js 15+ warning/error when webpack is modified but turbopack isn't
// Dynamic CSS extraction runs synchronously for both, so Turbopack is supported.
turbopack: nextConfig.turbopack || {},
webpack(config, context) {
// Also hook into webpack for live dev reloads in webpack mode
config.plugins.push(
new StylexuiWebpackPlugin({ outputPath, srcPatterns, cwd: projectRoot })
);
// Chain existing webpack config if provided
if (typeof nextConfig.webpack === 'function') {
return nextConfig.webpack(config, context);
}
return config;
},
};
}
module.exports = withStylexui;
module.exports.default = withStylexui;
module.exports.withStylexui = withStylexui;