298 lines
8.5 KiB
JavaScript
298 lines
8.5 KiB
JavaScript
/* eslint-disable no-console */
|
|
import {execSync} from "child_process";
|
|
import path from "path";
|
|
import {fileURLToPath} from "url";
|
|
import zlib from "zlib";
|
|
|
|
import fs from "fs-extra";
|
|
|
|
import {generateTypes} from "./generate-types.mjs";
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const rootDir = path.resolve(__dirname, "..");
|
|
const distDir = path.join(rootDir, "dist");
|
|
|
|
async function clean() {
|
|
console.log("🧹 Cleaning dist directory...");
|
|
await fs.remove(distDir);
|
|
}
|
|
|
|
async function build() {
|
|
console.log("📦 Building with Rollup...");
|
|
execSync("rollup -c rollup.config.mjs", {cwd: rootDir, stdio: "inherit"});
|
|
}
|
|
|
|
async function buildStyles() {
|
|
console.log("🎨 Creating styles export...");
|
|
|
|
// Simply copy the styles.css file to dist
|
|
const stylesPath = path.join(rootDir, "src/styles.css");
|
|
const outputPath = path.join(distDir, "styles.css");
|
|
|
|
await fs.copy(stylesPath, outputPath);
|
|
|
|
console.log("✅ Styles export created successfully");
|
|
}
|
|
|
|
async function logComponentCount() {
|
|
console.log("📊 Counting components...");
|
|
|
|
const componentsDir = path.join(rootDir, "src/components");
|
|
let componentCount = 0;
|
|
|
|
if (await fs.pathExists(componentsDir)) {
|
|
const items = await fs.readdir(componentsDir);
|
|
|
|
for (const item of items) {
|
|
const itemPath = path.join(componentsDir, item);
|
|
const stat = await fs.stat(itemPath);
|
|
|
|
// Check if it's a directory with an index.ts file
|
|
if (stat.isDirectory() && (await fs.pathExists(path.join(itemPath, "index.ts")))) {
|
|
// Skip special directories
|
|
if (item === "icons" || item === "utils" || item === "hooks") {
|
|
continue;
|
|
}
|
|
componentCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(`✅ Found ${componentCount} components`);
|
|
console.log(` Note: Component exports will be generated during 'pnpm pack' via clean-package`);
|
|
}
|
|
|
|
async function addUseClientDirective() {
|
|
console.log("🔧 Adding directives to files...");
|
|
|
|
// Find all JS files in the components and hooks directories
|
|
const jsFiles = [];
|
|
const componentsDir = path.join(distDir, "components");
|
|
const hooksDir = path.join(distDir, "hooks");
|
|
const srcDir = path.join(rootDir, "src");
|
|
|
|
async function findJsFiles(dir) {
|
|
const items = await fs.readdir(dir);
|
|
|
|
for (const item of items) {
|
|
const fullPath = path.join(dir, item);
|
|
const stat = await fs.stat(fullPath);
|
|
|
|
if (stat.isDirectory()) {
|
|
await findJsFiles(fullPath);
|
|
} else if (item.endsWith(".js")) {
|
|
jsFiles.push(fullPath);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (await fs.pathExists(componentsDir)) {
|
|
await findJsFiles(componentsDir);
|
|
}
|
|
|
|
if (await fs.pathExists(hooksDir)) {
|
|
await findJsFiles(hooksDir);
|
|
}
|
|
|
|
let useClientCount = 0;
|
|
let useStrictCount = 0;
|
|
|
|
// Add "use client" or "use strict" based on source file type
|
|
for (const jsFile of jsFiles) {
|
|
// Map the dist file back to its source file
|
|
const relativePath = path.relative(distDir, jsFile);
|
|
const sourcePathTs = path.join(srcDir, relativePath.replace(/\.js$/, ".ts"));
|
|
const sourcePathTsx = path.join(srcDir, relativePath.replace(/\.js$/, ".tsx"));
|
|
|
|
const content = await fs.readFile(jsFile, "utf-8");
|
|
|
|
// Skip if already has a directive
|
|
if (
|
|
content.startsWith('"use client"') ||
|
|
content.startsWith("'use client'") ||
|
|
content.startsWith('"use strict"') ||
|
|
content.startsWith("'use strict'")
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
// Check which source file exists
|
|
const isTsx = await fs.pathExists(sourcePathTsx);
|
|
const isTs = await fs.pathExists(sourcePathTs);
|
|
|
|
if (isTsx) {
|
|
// .tsx files get "use client"
|
|
await fs.writeFile(jsFile, `"use client";\n${content}`);
|
|
useClientCount++;
|
|
} else if (isTs) {
|
|
// .ts files get "use strict"
|
|
await fs.writeFile(jsFile, `"use strict";\n${content}`);
|
|
useStrictCount++;
|
|
}
|
|
}
|
|
|
|
console.log(`✅ Added "use client" to ${useClientCount} files (from .tsx)`);
|
|
console.log(`✅ Added "use strict" to ${useStrictCount} files (from .ts)`);
|
|
}
|
|
|
|
async function measureBundleSizes() {
|
|
console.log("📊 Measuring bundle sizes...");
|
|
|
|
const sizes = {
|
|
components: {},
|
|
css: {},
|
|
main: {},
|
|
plugin: {},
|
|
total: {gzip: 0, min: 0},
|
|
};
|
|
|
|
// Helper function to measure file size
|
|
async function measureFile(filePath) {
|
|
if (!(await fs.pathExists(filePath))) {
|
|
return null;
|
|
}
|
|
|
|
const content = await fs.readFile(filePath);
|
|
const minSize = Buffer.byteLength(content) / 1000;
|
|
const gzipSize = zlib.gzipSync(content, {level: 9}).length / 1000;
|
|
|
|
return {
|
|
gzip: gzipSize.toFixed(2),
|
|
min: minSize.toFixed(2),
|
|
};
|
|
}
|
|
|
|
// Measure main bundle
|
|
const mainPath = path.join(distDir, "index.js");
|
|
const mainSize = await measureFile(mainPath);
|
|
|
|
if (mainSize) {
|
|
sizes.main = mainSize;
|
|
sizes.total.min += parseFloat(mainSize.min);
|
|
sizes.total.gzip += parseFloat(mainSize.gzip);
|
|
}
|
|
|
|
// Measure plugin bundle
|
|
const pluginPath = path.join(distDir, "plugin.js");
|
|
const pluginSize = await measureFile(pluginPath);
|
|
|
|
if (pluginSize) {
|
|
sizes.plugin = pluginSize;
|
|
sizes.total.min += parseFloat(pluginSize.min);
|
|
sizes.total.gzip += parseFloat(pluginSize.gzip);
|
|
}
|
|
|
|
// Measure individual components
|
|
const componentsDir = path.join(distDir, "components");
|
|
|
|
if (await fs.pathExists(componentsDir)) {
|
|
const componentDirs = await fs.readdir(componentsDir);
|
|
|
|
for (const componentDir of componentDirs) {
|
|
const componentPath = path.join(componentsDir, componentDir, "index.js");
|
|
const componentSize = await measureFile(componentPath);
|
|
|
|
if (componentSize) {
|
|
sizes.components[componentDir] = componentSize;
|
|
sizes.total.min += parseFloat(componentSize.min);
|
|
sizes.total.gzip += parseFloat(componentSize.gzip);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Measure CSS files
|
|
const cssPath = path.join(distDir, "index.css");
|
|
const cssSize = await measureFile(cssPath);
|
|
|
|
if (cssSize) {
|
|
sizes.css.main = cssSize;
|
|
sizes.total.min += parseFloat(cssSize.min);
|
|
sizes.total.gzip += parseFloat(cssSize.gzip);
|
|
}
|
|
|
|
// Measure styles.css
|
|
const stylesCssPath = path.join(distDir, "styles.css");
|
|
const stylesCssSize = await measureFile(stylesCssPath);
|
|
|
|
if (stylesCssSize) {
|
|
sizes.css.styles = stylesCssSize;
|
|
sizes.total.min += parseFloat(stylesCssSize.min);
|
|
sizes.total.gzip += parseFloat(stylesCssSize.gzip);
|
|
}
|
|
|
|
// Round totals
|
|
sizes.total.min = sizes.total.min.toFixed(2);
|
|
sizes.total.gzip = sizes.total.gzip.toFixed(2);
|
|
|
|
// Save sizes to JSON file
|
|
const sizesPath = path.join(rootDir, "bundle-sizes.json");
|
|
|
|
await fs.writeJson(sizesPath, sizes, {spaces: 2});
|
|
|
|
// Print size report
|
|
console.log("\n📦 Bundle Size Report");
|
|
console.log("═".repeat(50));
|
|
console.log(`Total: ${sizes.total.min}kb (${sizes.total.gzip}kb gzipped)`);
|
|
console.log("─".repeat(50));
|
|
|
|
console.log("\n📄 Main Bundles:");
|
|
console.log(` index.js: ${sizes.main.min}kb (${sizes.main.gzip}kb gzipped)`);
|
|
if (sizes.plugin.min) {
|
|
console.log(` plugin.js: ${sizes.plugin.min}kb (${sizes.plugin.gzip}kb gzipped)`);
|
|
}
|
|
|
|
if (sizes.css.main || sizes.css.styles) {
|
|
console.log("\n🎨 CSS:");
|
|
if (sizes.css.main) {
|
|
console.log(` index.css: ${sizes.css.main.min}kb (${sizes.css.main.gzip}kb gzipped)`);
|
|
}
|
|
if (sizes.css.styles) {
|
|
console.log(` styles.css: ${sizes.css.styles.min}kb (${sizes.css.styles.gzip}kb gzipped)`);
|
|
}
|
|
}
|
|
|
|
console.log("\n🧩 Components:");
|
|
const sortedComponents = Object.entries(sizes.components).sort(
|
|
(a, b) => parseFloat(b[1].gzip) - parseFloat(a[1].gzip),
|
|
);
|
|
|
|
for (const [component, size] of sortedComponents) {
|
|
console.log(` ${component}: ${size.min}kb (${size.gzip}kb gzipped)`);
|
|
}
|
|
|
|
console.log("═".repeat(50));
|
|
console.log(`\n💾 Size report saved to: ${sizesPath}`);
|
|
|
|
return sizes;
|
|
}
|
|
|
|
async function main() {
|
|
try {
|
|
// Check if --tsc flag is passed
|
|
const shouldGenerateTypes = process.argv.includes("--tsc");
|
|
|
|
await clean();
|
|
// await generateThemes(); // Generate themes before build
|
|
await build();
|
|
await buildStyles();
|
|
await addUseClientDirective();
|
|
|
|
if (shouldGenerateTypes) {
|
|
await generateTypes();
|
|
console.log("✅ TypeScript declarations generated");
|
|
} else {
|
|
console.log("⚡ Skipping TypeScript generation (use --tsc to include)");
|
|
}
|
|
|
|
await logComponentCount();
|
|
await measureBundleSizes();
|
|
|
|
console.log("✨ Build completed successfully!");
|
|
} catch (error) {
|
|
console.error("❌ Build failed:", error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|