@wp-forge/vite-plugin
Version:
Vite plugin for WordPress theme development with WP-Forge
1,076 lines (1,025 loc) • 32.1 kB
JavaScript
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
// src/plugins/blocks.ts
import fg from "fast-glob";
import { readFile, writeFile } from "fs/promises";
import { join, dirname, relative } from "path";
import pc from "picocolors";
function wpForgeBlocks(options = {}) {
const {
dir = "src/blocks",
autoRegister = true,
namespace = "wp-forge",
pattern = "**/block.json"
} = options;
let blocks = [];
let rootDir;
return {
name: "wp-forge:blocks",
async configResolved(config) {
rootDir = config.root;
},
async buildStart() {
const blockJsonFiles = await fg(join(dir, pattern), {
cwd: rootDir,
absolute: true
});
blocks = [];
for (const blockJsonPath of blockJsonFiles) {
try {
const content = await readFile(blockJsonPath, "utf-8");
const blockMeta = JSON.parse(content);
blocks.push({
...blockMeta,
_path: relative(rootDir, blockJsonPath),
_dir: relative(rootDir, dirname(blockJsonPath))
});
this.addWatchFile(blockJsonPath);
} catch (error) {
this.warn(`Failed to parse block.json at ${blockJsonPath}`);
}
}
if (blocks.length > 0) {
console.log(pc.cyan(`
\u2692\uFE0F Found ${blocks.length} block(s):`));
blocks.forEach((block) => {
console.log(pc.dim(` \u2022 ${block.name}`));
});
console.log();
}
},
async generateBundle() {
if (!autoRegister || blocks.length === 0) return;
const phpCode = generateBlockRegistration(blocks, namespace);
const outputPath = join(rootDir, "inc/blocks-generated.php");
await writeFile(outputPath, phpCode, "utf-8");
console.log(pc.green(` \u2713 Generated block registration: inc/blocks-generated.php`));
},
// Hot reload blocks during development
configureServer(server) {
server.watcher.add(join(rootDir, dir, "**/*.json"));
server.watcher.on("change", async (file) => {
if (file.includes("block.json")) {
console.log(pc.cyan(" \u2692\uFE0F Block configuration changed, reloading..."));
server.ws.send({ type: "full-reload" });
}
});
}
};
}
function generateBlockRegistration(blocks, _namespace) {
const blockDirs = blocks.map((block) => {
const blockData = block;
return blockData._dir;
});
return `
/**
* Auto-generated block registration
*
* Generated by WP-Forge Vite Plugin
* Do not edit this file manually
*
* @package wp-forge
*/
namespace WPForge\\Blocks;
/**
* Register all blocks
*/
function register_blocks() {
${blockDirs.map((dir) => `register_block_type( get_template_directory() . '/${dir}' );`).join("\n ")}
}
add_action( 'init', __NAMESPACE__ . '\\register_blocks' );
`;
}
// src/plugins/manifest.ts
import { writeFile as writeFile2 } from "fs/promises";
import { join as join2, dirname as dirname2 } from "path";
import { mkdir } from "fs/promises";
function wpForgeManifest(options = {}) {
const {
enabled = true,
output = "dist/.vite/manifest.json",
wordpress = true
} = options;
let rootDir;
return {
name: "wp-forge:manifest",
configResolved(config) {
rootDir = config.root;
},
async generateBundle(_, bundle) {
if (!enabled) return;
const manifest = {};
for (const [fileName, chunk] of Object.entries(bundle)) {
if (chunk.type === "chunk") {
const entry = {
file: fileName,
src: chunk.facadeModuleId || fileName,
isEntry: chunk.isEntry
};
if (chunk.viteMetadata?.importedCss?.size) {
entry.css = Array.from(chunk.viteMetadata.importedCss);
}
if (wordpress) {
const wpDeps = extractWordPressDependencies(chunk.code);
if (wpDeps.length > 0) {
entry.dependencies = wpDeps;
}
entry.version = chunk.fileName.match(/\.([a-f0-9]{8})\./)?.[1] || "1.0.0";
}
manifest[chunk.name || fileName] = entry;
}
if (chunk.type === "asset") {
manifest[fileName] = {
file: fileName
};
}
}
const outputPath = join2(rootDir, output);
await mkdir(dirname2(outputPath), { recursive: true });
await writeFile2(outputPath, JSON.stringify(manifest, null, 2), "utf-8");
console.log(` \u2713 Generated WordPress manifest: ${output}`);
}
};
}
function extractWordPressDependencies(code) {
const deps = /* @__PURE__ */ new Set();
const wpPackagePattern = /@wordpress\/([\w-]+)/g;
let match;
while ((match = wpPackagePattern.exec(code)) !== null) {
deps.add(`wp-${match[1]}`);
}
if (code.includes("wp.")) {
if (code.includes("wp.element")) deps.add("wp-element");
if (code.includes("wp.blocks")) deps.add("wp-blocks");
if (code.includes("wp.blockEditor")) deps.add("wp-block-editor");
if (code.includes("wp.components")) deps.add("wp-components");
if (code.includes("wp.data")) deps.add("wp-data");
if (code.includes("wp.i18n")) deps.add("wp-i18n");
}
return Array.from(deps);
}
// src/plugins/php-hmr.ts
import { watch } from "chokidar";
import pc2 from "picocolors";
function wpForgePhpHmr(options = {}) {
const {
enabled = true,
watch: patterns = ["**/*.php", "theme.json"],
debounce = 100
} = options;
let server;
let watcher = null;
let timeout = null;
return {
name: "wp-forge:php-hmr",
configureServer(devServer) {
if (!enabled) return;
server = devServer;
watcher = watch(patterns, {
ignored: ["**/node_modules/**", "**/vendor/**", "**/dist/**"],
persistent: true,
ignoreInitial: true
});
watcher.on("change", (path5) => {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
console.log(pc2.cyan(`
\u2692\uFE0F PHP file changed: ${pc2.dim(path5)}`));
console.log(pc2.cyan(" Reloading page...\n"));
server.ws.send({
type: "full-reload",
path: "*"
});
}, debounce);
});
watcher.on("add", (path5) => {
console.log(pc2.green(`
\u2692\uFE0F New PHP file: ${pc2.dim(path5)}
`));
});
watcher.on("unlink", (path5) => {
console.log(pc2.yellow(`
\u2692\uFE0F PHP file removed: ${pc2.dim(path5)}
`));
});
server.httpServer?.once("listening", () => {
setTimeout(() => {
console.log(pc2.dim(" \u{1F4DD} Watching PHP files for changes..."));
}, 150);
});
},
async closeBundle() {
if (watcher) {
await watcher.close();
watcher = null;
}
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
}
};
}
// src/plugins/assets.ts
function wpForgeAssets(options = {}) {
const {
publicDir = "dist",
baseUrl
} = options;
return {
name: "wp-forge:assets",
config() {
return {
publicDir,
base: baseUrl || "./",
build: {
// Output to WordPress theme structure
outDir: publicDir,
emptyOutDir: false,
// Don't delete PHP files
// Asset handling
assetsDir: "",
assetsInlineLimit: 0,
// Don't inline assets
// Sourcemaps for debugging
sourcemap: true
}
};
}
};
}
// src/plugins/design-system.ts
import path from "path";
import fs from "fs";
function wpForgeDesignSystem(options = {}) {
const {
enabled = false,
framework = "none",
wordpressPresets = true
} = options;
if (!enabled || framework === "none") {
return {
name: "wp-forge:design-system",
apply: () => false
};
}
let config;
return {
name: "wp-forge:design-system",
configResolved(resolvedConfig) {
config = resolvedConfig;
},
async config() {
const root = process.cwd();
const tailwindConfig = path.join(root, "tailwind.config.js");
const tailwindConfigTs = path.join(root, "tailwind.config.ts");
const unoConfig = path.join(root, "uno.config.ts");
const hasTailwindConfig = fs.existsSync(tailwindConfig) || fs.existsSync(tailwindConfigTs);
const hasUnoConfig = fs.existsSync(unoConfig);
if (framework === "tailwind" && !hasTailwindConfig) {
console.warn(
"\u26A0\uFE0F Tailwind CSS enabled but no config file found. Run: wp-forge design-system:setup tailwind"
);
}
if (framework === "unocss" && !hasUnoConfig) {
console.warn(
"\u26A0\uFE0F UnoCSS enabled but no config file found. Run: wp-forge design-system:setup unocss"
);
}
if (framework === "tailwind") {
try {
const tailwindcss = __require("tailwindcss");
const autoprefixer = __require("autoprefixer");
return {
css: {
postcss: {
plugins: [tailwindcss, autoprefixer]
}
}
};
} catch {
console.warn("\u26A0\uFE0F Tailwind CSS dependencies not found");
}
}
return {};
},
configureServer(server) {
const { logger } = config;
server.httpServer?.once("listening", () => {
setTimeout(() => {
if (framework === "tailwind") {
logger.info(" \u{1F3A8} Tailwind CSS integration active");
if (wordpressPresets) {
logger.info(" \u{1F4DD} WordPress preset mappings enabled");
}
} else if (framework === "unocss") {
logger.info(" \u{1F3A8} UnoCSS integration active");
if (wordpressPresets) {
logger.info(" \u{1F4DD} WordPress preset mappings enabled");
}
}
}, 150);
});
},
async transform(code, id) {
if (wordpressPresets && id.endsWith(".css") && (framework === "tailwind" || framework === "unocss")) {
const themeJsonPath = path.join(process.cwd(), "theme.json");
if (fs.existsSync(themeJsonPath)) {
try {
const themeJson = JSON.parse(fs.readFileSync(themeJsonPath, "utf-8"));
if (themeJson.settings?.color?.palette) {
let injectedVars = "\n/* WordPress Color Variables */\n:root {\n";
themeJson.settings.color.palette.forEach((color) => {
injectedVars += ` --wp--preset--color--${color.slug}: ${color.color};
`;
});
injectedVars += "}\n";
code = injectedVars + code;
}
} catch {
}
}
}
return code;
}
};
}
// src/plugins/critical-css.ts
import path2 from "path";
import fs2 from "fs";
function wpForgeCriticalCSS(options = {}) {
const {
enabled = true,
templates = ["index", "single", "page", "archive"],
dimensions = { width: 1300, height: 900 },
inline = true,
output = "dist/critical",
minSize = 0
} = options;
if (!enabled) {
return {
name: "wp-forge:critical-css",
apply: () => false
};
}
return {
name: "wp-forge:critical-css",
apply: "build",
async closeBundle() {
const root = process.cwd();
const distDir = path2.join(root, "dist");
const templatesDir = path2.join(root, "templates");
const outputDir = path2.join(root, output);
let critical;
try {
critical = __require("critical");
} catch {
console.warn(
'\u26A0\uFE0F Critical CSS extraction requires the "critical" package. Install it with: npm install --save-dev critical'
);
return;
}
if (!fs2.existsSync(outputDir)) {
fs2.mkdirSync(outputDir, { recursive: true });
}
console.log("\u{1F4E6} Extracting critical CSS...");
const cssFiles = fs2.readdirSync(path2.join(distDir, "css")).filter((f) => f.endsWith(".css")).map((f) => path2.join(distDir, "css", f));
if (cssFiles.length === 0) {
console.warn(" No CSS files found to extract critical CSS from");
return;
}
const mainCss = cssFiles[0];
const criticalResults = {};
for (const template of templates) {
const templatePath = path2.join(templatesDir, `${template}.html`);
if (!fs2.existsSync(templatePath)) {
console.warn(` Template ${template}.html not found, skipping`);
continue;
}
try {
const result = await critical.generate({
inline: false,
src: templatePath,
css: [mainCss],
dimensions: [dimensions],
penthouse: {
timeout: 3e4
}
});
if (result.css && result.css.length > minSize) {
criticalResults[template] = result.css;
const criticalPath = path2.join(outputDir, `${template}-critical.css`);
fs2.writeFileSync(criticalPath, result.css);
console.log(` \u2713 ${template}: ${(result.css.length / 1024).toFixed(2)}KB`);
}
} catch (error) {
console.warn(` \u2717 ${template}: Failed to extract critical CSS`);
}
}
await generatePHPLoader(root, criticalResults, inline);
}
};
}
async function generatePHPLoader(root, criticalResults, inline) {
const incDir = path2.join(root, "inc");
if (!fs2.existsSync(incDir)) {
fs2.mkdirSync(incDir, { recursive: true });
}
let phpContent = `
/**
* Critical CSS Loader
*
* Auto-generated by WP-Forge
* DO NOT EDIT MANUALLY
*/
namespace WPForge;
/**
* Load critical CSS for template
*/
function load_critical_css(): void {
$template = get_page_template_slug();
// Normalize template name
$template_name = basename($template, '.html');
if (empty($template_name)) {
$template_name = is_singular() ? 'single' : 'index';
}
$critical_css_map = array(
`;
Object.keys(criticalResults).forEach((template) => {
phpContent += ` '${template}' => '${template}-critical.css',
`;
});
phpContent += ` );
if (isset($critical_css_map[$template_name])) {
$critical_file = get_template_directory() . '/dist/critical/' . $critical_css_map[$template_name];
if (file_exists($critical_file)) {
`;
if (inline) {
phpContent += ` // Inline critical CSS
echo '<style id="critical-css">';
echo file_get_contents($critical_file);
echo '</style>';
`;
} else {
phpContent += ` // Link to critical CSS
$critical_url = get_template_directory_uri() . '/dist/critical/' . $critical_css_map[$template_name];
printf(
'<link rel="stylesheet" href="%s" id="critical-css">',
esc_url($critical_url)
);
`;
}
phpContent += ` }
}
}
// Hook into wp_head with high priority
add_action('wp_head', __NAMESPACE__ . '\\load_critical_css', 1);
`;
fs2.writeFileSync(path2.join(incDir, "critical-css-generated.php"), phpContent);
console.log(" \u2713 Generated inc/critical-css-generated.php");
}
// src/plugins/lazy-loading.ts
import path3 from "path";
import fs3 from "fs";
function wpForgeLazyLoading(options = {}) {
const {
enabled = true,
images = "native",
css = true,
chunks = true
} = options;
if (!enabled) {
return {
name: "wp-forge:lazy-loading",
apply: () => false
};
}
return {
name: "wp-forge:lazy-loading",
apply: "build",
config() {
if (chunks) {
return {
build: {
rollupOptions: {
output: {
manualChunks: (id) => {
if (id.includes("node_modules")) {
return "vendor";
}
if (id.includes("@wordpress/")) {
return "wordpress";
}
}
}
}
}
};
}
return {};
},
async closeBundle() {
const root = process.cwd();
await generatePHPUtilities(root, images, css);
}
};
}
async function generatePHPUtilities(root, images, css) {
const incDir = path3.join(root, "inc");
if (!fs3.existsSync(incDir)) {
fs3.mkdirSync(incDir, { recursive: true });
}
let phpContent = `
/**
* Lazy Loading Utilities
*
* Auto-generated by WP-Forge
* DO NOT EDIT MANUALLY
*/
namespace WPForge;
`;
if (images !== "none") {
phpContent += `/**
* Add loading="lazy" to images
*/
function add_lazy_loading_to_images( $content ) {
if ( is_admin() || is_feed() ) {
return $content;
}
// Add loading="lazy" to img tags that don't have it
$content = preg_replace(
'/<img(?![^>]*loading=)([^>]*)>/i',
'<img loading="lazy"$1>',
$content
);
return $content;
}
add_filter( 'the_content', __NAMESPACE__ . '\\add_lazy_loading_to_images', 20 );
add_filter( 'post_thumbnail_html', __NAMESPACE__ . '\\add_lazy_loading_to_images', 20 );
`;
}
if (css) {
phpContent += `/**
* Lazy load non-critical CSS
*/
function lazy_load_css( $html, $handle, $href, $media ) {
// Skip critical CSS
if ( strpos( $handle, 'critical' ) !== false ) {
return $html;
}
// Change media to "print" and add onload to switch to "all"
$html = str_replace(
"media='{$media}'",
"media='print' onload=\\"this.media='all'; this.onload=null;\\"",
$html
);
// Add noscript fallback
$noscript = sprintf(
'<noscript><link rel="stylesheet" href="%s" media="%s"></noscript>',
esc_url( $href ),
esc_attr( $media )
);
return $html . $noscript;
}
// Uncomment to enable CSS lazy loading
// add_filter( 'style_loader_tag', __NAMESPACE__ . '\\lazy_load_css', 10, 4 );
`;
}
phpContent += `/**
* Preconnect to external domains
*/
function add_resource_hints( $urls, $relation_type ) {
if ( 'preconnect' === $relation_type ) {
$urls[] = array(
'href' => 'https://fonts.googleapis.com',
'crossorigin',
);
$urls[] = array(
'href' => 'https://fonts.gstatic.com',
'crossorigin',
);
}
return $urls;
}
add_filter( 'wp_resource_hints', __NAMESPACE__ . '\\add_resource_hints', 10, 2 );
`;
fs3.writeFileSync(path3.join(incDir, "lazy-loading-generated.php"), phpContent);
console.log(" \u2713 Generated inc/lazy-loading-generated.php");
}
// src/plugins/preload.ts
import path4 from "path";
import fs4 from "fs";
function wpForgePreload(options = {}) {
const {
enabled = true,
assets = ["fonts", "critical-css"],
strategy = "link-tag"
} = options;
if (!enabled) {
return {
name: "wp-forge:preload",
apply: () => false
};
}
return {
name: "wp-forge:preload",
apply: "build",
async closeBundle() {
const root = process.cwd();
await generatePHPPreloader(root, assets, strategy);
}
};
}
async function generatePHPPreloader(root, assets, strategy) {
const incDir = path4.join(root, "inc");
if (!fs4.existsSync(incDir)) {
fs4.mkdirSync(incDir, { recursive: true });
}
let phpContent = `
/**
* Asset Preloader
*
* Auto-generated by WP-Forge
* DO NOT EDIT MANUALLY
*/
namespace WPForge;
/**
* Preload critical assets
*/
function preload_assets(): void {
$preloads = array();
`;
if (assets.includes("fonts")) {
phpContent += ` // Preload fonts
$font_dir = get_template_directory() . '/dist/fonts';
$font_url = get_template_directory_uri() . '/dist/fonts';
if ( is_dir( $font_dir ) ) {
$fonts = glob( $font_dir . '/*.{woff2,woff}', GLOB_BRACE );
foreach ( $fonts as $font ) {
$font_name = basename( $font );
$preloads[] = sprintf(
'<link rel="preload" href="%s/%s" as="font" type="font/%s" crossorigin>',
esc_url( $font_url ),
esc_attr( $font_name ),
esc_attr( pathinfo( $font, PATHINFO_EXTENSION ) )
);
}
}
`;
}
if (assets.includes("critical-css")) {
phpContent += ` // Preload critical CSS
$critical_dir = get_template_directory() . '/dist/critical';
$critical_url = get_template_directory_uri() . '/dist/critical';
if ( is_dir( $critical_dir ) ) {
$template_name = is_singular() ? 'single' : 'index';
$critical_file = $critical_dir . '/' . $template_name . '-critical.css';
if ( file_exists( $critical_file ) ) {
$preloads[] = sprintf(
'<link rel="preload" href="%s/%s-critical.css" as="style">',
esc_url( $critical_url ),
esc_attr( $template_name )
);
}
}
`;
}
if (assets.includes("critical-js")) {
phpContent += ` // Preload critical JavaScript
$manifest_file = get_template_directory() . '/dist/.vite/manifest.json';
if ( file_exists( $manifest_file ) ) {
$manifest = json_decode( file_get_contents( $manifest_file ), true );
foreach ( $manifest as $entry ) {
if ( isset( $entry['isEntry'] ) && $entry['isEntry'] ) {
$preloads[] = sprintf(
'<link rel="modulepreload" href="%s/%s">',
esc_url( get_template_directory_uri() . '/dist' ),
esc_attr( $entry['file'] )
);
break; // Only preload main entry
}
}
}
`;
}
phpContent += ` // Output preload tags
foreach ( $preloads as $preload ) {
echo $preload . "
";
}
}
add_action( 'wp_head', __NAMESPACE__ . '\\preload_assets', 2 );
/**
* DNS prefetch for external resources
*/
function dns_prefetch(): void {
$domains = array(
'//fonts.googleapis.com',
'//fonts.gstatic.com',
);
foreach ( $domains as $domain ) {
printf(
'<link rel="dns-prefetch" href="%s">' . "
",
esc_url( $domain )
);
}
}
add_action( 'wp_head', __NAMESPACE__ . '\\dns_prefetch', 1 );
`;
fs4.writeFileSync(path4.join(incDir, "preload-generated.php"), phpContent);
console.log(" \u2713 Generated inc/preload-generated.php");
}
// src/plugins/performance.ts
function wpForgePerformance(options = {}) {
const plugins = [];
if (options.criticalCSS !== false) {
const criticalOptions = typeof options.criticalCSS === "object" ? options.criticalCSS : { enabled: true };
plugins.push(wpForgeCriticalCSS(criticalOptions));
}
if (options.lazyLoading !== false) {
const lazyOptions = typeof options.lazyLoading === "object" ? options.lazyLoading : { enabled: true };
plugins.push(wpForgeLazyLoading(lazyOptions));
}
if (options.preload !== false) {
const preloadOptions = typeof options.preload === "object" ? options.preload : { enabled: true };
plugins.push(wpForgePreload(preloadOptions));
}
return plugins;
}
// src/integrations/tailwind-preset.ts
var wpForgeTailwindPreset = {
theme: {
extend: {
colors: {
// WordPress color palette mappings
"wp-primary": "var(--wp--preset--color--primary)",
"wp-secondary": "var(--wp--preset--color--secondary)",
"wp-accent": "var(--wp--preset--color--accent)",
"wp-text": "var(--wp--preset--color--text)",
"wp-text-muted": "var(--wp--preset--color--text-muted)",
"wp-background": "var(--wp--preset--color--background)",
"wp-background-secondary": "var(--wp--preset--color--background-secondary)",
"wp-border": "var(--wp--preset--color--border)",
"wp-success": "var(--wp--preset--color--success)",
"wp-warning": "var(--wp--preset--color--warning)",
"wp-error": "var(--wp--preset--color--error)"
},
spacing: {
// WordPress spacing scale mappings
"wp-xs": "var(--wp--preset--spacing--xs)",
"wp-sm": "var(--wp--preset--spacing--sm)",
"wp-md": "var(--wp--preset--spacing--md)",
"wp-lg": "var(--wp--preset--spacing--lg)",
"wp-xl": "var(--wp--preset--spacing--xl)",
"wp-2xl": "var(--wp--preset--spacing--2xl)"
},
fontFamily: {
// WordPress font family mappings
"wp-sans": "var(--wp--preset--font-family--sans)",
"wp-serif": "var(--wp--preset--font-family--serif)",
"wp-mono": "var(--wp--preset--font-family--mono)"
},
fontSize: {
// WordPress font size mappings
"wp-xs": "var(--wp--preset--font-size--xs)",
"wp-sm": "var(--wp--preset--font-size--sm)",
"wp-base": "var(--wp--preset--font-size--base)",
"wp-lg": "var(--wp--preset--font-size--lg)",
"wp-xl": "var(--wp--preset--font-size--xl)",
"wp-2xl": "var(--wp--preset--font-size--2xl)",
"wp-3xl": "var(--wp--preset--font-size--3xl)",
"wp-4xl": "var(--wp--preset--font-size--4xl)"
},
borderRadius: {
// WordPress border radius mappings
"wp-sm": "var(--wp--preset--border-radius--sm)",
"wp-md": "var(--wp--preset--border-radius--md)",
"wp-lg": "var(--wp--preset--border-radius--lg)"
},
maxWidth: {
// WordPress content width
"wp-container": "var(--wp--style--global--content-size)",
"wp-wide": "var(--wp--style--global--wide-size)"
}
}
},
content: [
"./src/**/*.{js,jsx,ts,tsx}",
"./inc/**/*.php",
"./templates/**/*.html",
"./parts/**/*.{php,html}",
"./blocks/**/*.{js,jsx,ts,tsx,php}"
],
safelist: [
// Safelist common WordPress block classes
{ pattern: /^wp-block-.+/ },
{ pattern: /^has-.+-color$/ },
{ pattern: /^has-.+-background-color$/ },
{ pattern: /^has-.+-border-color$/ },
{ pattern: /^has-.+-font-size$/ },
{ pattern: /^has-.+-font-family$/ }
]
};
// src/integrations/unocss-preset.ts
var wpForgeUnoPreset = {
name: "@wp-forge/uno-preset",
theme: {
colors: {
// WordPress color palette mappings
"wp-primary": "var(--wp--preset--color--primary)",
"wp-secondary": "var(--wp--preset--color--secondary)",
"wp-accent": "var(--wp--preset--color--accent)",
"wp-text": "var(--wp--preset--color--text)",
"wp-text-muted": "var(--wp--preset--color--text-muted)",
"wp-background": "var(--wp--preset--color--background)",
"wp-background-secondary": "var(--wp--preset--color--background-secondary)",
"wp-border": "var(--wp--preset--color--border)",
"wp-success": "var(--wp--preset--color--success)",
"wp-warning": "var(--wp--preset--color--warning)",
"wp-error": "var(--wp--preset--color--error)"
},
spacing: {
// WordPress spacing scale mappings
"wp-xs": "var(--wp--preset--spacing--xs)",
"wp-sm": "var(--wp--preset--spacing--sm)",
"wp-md": "var(--wp--preset--spacing--md)",
"wp-lg": "var(--wp--preset--spacing--lg)",
"wp-xl": "var(--wp--preset--spacing--xl)",
"wp-2xl": "var(--wp--preset--spacing--2xl)"
},
fontFamily: {
// WordPress font family mappings
"wp-sans": "var(--wp--preset--font-family--sans)",
"wp-serif": "var(--wp--preset--font-family--serif)",
"wp-mono": "var(--wp--preset--font-family--mono)"
},
fontSize: {
// WordPress font size mappings
"wp-xs": "var(--wp--preset--font-size--xs)",
"wp-sm": "var(--wp--preset--font-size--sm)",
"wp-base": "var(--wp--preset--font-size--base)",
"wp-lg": "var(--wp--preset--font-size--lg)",
"wp-xl": "var(--wp--preset--font-size--xl)",
"wp-2xl": "var(--wp--preset--font-size--2xl)",
"wp-3xl": "var(--wp--preset--font-size--3xl)",
"wp-4xl": "var(--wp--preset--font-size--4xl)"
},
borderRadius: {
// WordPress border radius mappings
"wp-sm": "var(--wp--preset--border-radius--sm)",
"wp-md": "var(--wp--preset--border-radius--md)",
"wp-lg": "var(--wp--preset--border-radius--lg)"
},
maxWidth: {
// WordPress content width
"wp-container": "var(--wp--style--global--content-size)",
"wp-wide": "var(--wp--style--global--wide-size)"
}
},
rules: [
// Custom WordPress utility rules
[
"wp-container",
{
"max-width": "var(--wp--style--global--content-size)",
"margin-left": "auto",
"margin-right": "auto",
"padding-left": "1rem",
"padding-right": "1rem"
}
],
[
"wp-wide",
{
"max-width": "var(--wp--style--global--wide-size)",
"margin-left": "auto",
"margin-right": "auto"
}
]
],
safelist: [
// Safelist common WordPress block classes
/^wp-block-.+/,
/^has-.+-color$/,
/^has-.+-background-color$/,
/^has-.+-border-color$/,
/^has-.+-font-size$/,
/^has-.+-font-family$/
]
};
// src/index.ts
function wpForge(options = {}) {
const {
blocks = {
dir: "src/blocks",
autoRegister: true
},
manifest = {
enabled: true,
output: "dist/.vite/manifest.json"
},
phpHmr = {
enabled: true,
watch: ["**/*.php", "theme.json"]
},
assets = {
publicDir: "dist"
},
designSystem = {
enabled: false,
framework: "none"
},
performance = {
criticalCSS: true,
lazyLoading: true,
preload: true
}
} = options;
const plugins = [
wpForgeCore(options),
wpForgeBlocks(blocks),
wpForgeManifest(manifest),
wpForgePhpHmr(phpHmr),
wpForgeAssets(assets)
];
if (designSystem.enabled) {
plugins.push(wpForgeDesignSystem(designSystem));
}
plugins.push(...wpForgePerformance(performance));
return plugins;
}
function wpForgeCore(_options) {
let config;
return {
name: "wp-forge",
config() {
return {
// WordPress-friendly build config
build: {
manifest: true,
rollupOptions: {
output: {
entryFileNames: "js/[name].[hash].js",
chunkFileNames: "js/[name].[hash].js",
assetFileNames: (assetInfo) => {
const name = assetInfo.name || "";
if (/\.(css)$/.test(name)) {
return "css/[name].[hash][extname]";
}
if (/\.(png|jpe?g|svg|gif|webp|avif)$/.test(name)) {
return "images/[name].[hash][extname]";
}
if (/\.(woff2?|eot|ttf|otf)$/.test(name)) {
return "fonts/[name].[hash][extname]";
}
return "assets/[name].[hash][extname]";
}
}
}
},
// Optimize deps for WordPress
optimizeDeps: {
include: [
"@wordpress/blocks",
"@wordpress/block-editor",
"@wordpress/components",
"@wordpress/data",
"@wordpress/element",
"@wordpress/i18n"
]
}
};
},
configResolved(resolvedConfig) {
config = resolvedConfig;
},
configureServer(server) {
server.httpServer?.once("listening", () => {
setTimeout(() => {
const { logger } = config;
logger.info("\n \u2692\uFE0F WP-Forge Dev Server Ready!\n");
logger.info(" WordPress integration active");
logger.info(" Block auto-discovery enabled");
logger.info(" PHP HMR watching for changes\n");
}, 100);
});
}
};
}
export {
wpForge,
wpForgeAssets,
wpForgeBlocks,
wpForgeDesignSystem,
wpForgeManifest,
wpForgePerformance,
wpForgePhpHmr,
wpForgeTailwindPreset,
wpForgeUnoPreset
};