UNPKG

zyros

Version:

A developer-friendly static site generator built with Next.js and Tailwind CSS. Transform a simple JSON file into a beautiful, fast static website.

222 lines (194 loc) 7.64 kB
const { execSync } = require('child_process'); const path = require('path'); const fs = require('fs'); const childProcess = require('child_process'); // Helper function to safely remove directory with retry logic function safeRemoveDir(dirPath, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { if (fs.existsSync(dirPath)) { // Try to remove read-only attributes on Windows if (process.platform === 'win32') { try { execSync(`attrib -R "${dirPath}\\*" /S /D`, { stdio: 'ignore' }); } catch (e) { // Ignore attrib errors } } fs.rmSync(dirPath, { recursive: true, force: true }); } return true; } catch (error) { if (i === maxRetries - 1) { console.warn(`⚠️ Could not fully clean ${dirPath}: ${error.message}`); return false; } // Wait a bit before retrying if (process.platform === 'win32') { childProcess.execSync('ping 127.0.0.1 -n 2 > nul', { stdio: 'ignore' }); } else { childProcess.execSync('sleep 1', { stdio: 'ignore' }); } } } return false; } // Generate RSS feed manually since TypeScript compilation is complex async function generateRSS() { try { // Load the site data const siteDataPath = path.join(process.cwd(), 'public', 'site.json'); if (!fs.existsSync(siteDataPath)) { console.log('⚠️ No site.json found, skipping RSS generation'); return; } const siteData = JSON.parse(fs.readFileSync(siteDataPath, 'utf8')); // Generate RSS content manually const baseUrl = process.env.SITE_URL || 'https://your-site.com'; const { site, pages } = siteData; if (!pages || pages.length === 0) { console.log('⚠️ No pages found, skipping RSS generation'); return; } const rssItems = pages .sort((a, b) => { const dateA = new Date(a.publishedAt || '2024-01-01'); const dateB = new Date(b.publishedAt || '2024-01-01'); return dateB.getTime() - dateA.getTime(); }) .map(page => { const pubDate = page.publishedAt ? new Date(page.publishedAt).toUTCString() : new Date().toUTCString(); const description = page.description || (page.content ? page.content.replace(/[#*`]/g, '').substring(0, 200) + '...' : ''); return ` <item> <title><![CDATA[${page.title}]]></title> <description><![CDATA[${description}]]></description> <link>${baseUrl}/${page.slug}</link> <guid isPermaLink="true">${baseUrl}/${page.slug}</guid> <pubDate>${pubDate}</pubDate> ${page.category ? `<category><![CDATA[${page.category}]]></category>` : ''} ${page.tags ? page.tags.map(tag => `<category><![CDATA[${tag}]]></category>`).join('\n ') : ''} </item>`; }).join('\n'); const rssContent = `<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> <title><![CDATA[${site.title}]]></title> <description><![CDATA[${site.description || 'A static site built with zyros'}]]></description> <link>${baseUrl}</link> <atom:link href="${baseUrl}/rss.xml" rel="self" type="application/rss+xml"/> <language>en-us</language> <lastBuildDate>${new Date().toUTCString()}</lastBuildDate> <generator>zyros</generator>${rssItems} </channel> </rss>`; // Write RSS file to dist directory const distDir = path.join(process.cwd(), 'out'); if (!fs.existsSync(distDir)) { fs.mkdirSync(distDir, { recursive: true }); } const rssPath = path.join(distDir, 'rss.xml'); fs.writeFileSync(rssPath, rssContent, 'utf8'); console.log('✓ RSS feed generated successfully'); } catch (error) { console.error('Error generating RSS feed:', error); } } async function main() { try { console.log('🚀 Building zyros...'); // Run Next.js build with error handling for Windows console.log('📦 Building Next.js app...'); try { // Clean output directory first on Windows if (process.platform === 'win32') { const outDir = path.join(process.cwd(), 'out'); safeRemoveDir(outDir); } execSync('next build', { stdio: 'inherit' }); } catch (error) { // Check if it's just a Windows permission issue but build succeeded const outDir = path.join(process.cwd(), 'out'); const buildSucceeded = fs.existsSync(outDir) && fs.readdirSync(outDir).length > 0; if (buildSucceeded && error.status === 1 && ( error.message.includes('EPERM') || error.message.includes('ENOTEMPTY') || error.message.includes('uncaughtException') || (error.stderr && (error.stderr.includes('EPERM') || error.stderr.includes('ENOTEMPTY'))) || (error.stdout && (error.stdout.includes('EPERM') || error.stdout.includes('ENOTEMPTY'))) )) { console.log('⚠️ Build completed successfully (Windows file permission issue ignored)'); } else if (buildSucceeded) { console.log('⚠️ Build completed successfully (ignoring cleanup error)'); } else { throw error; } } // Generate RSS feed console.log('📡 Generating RSS feed...'); await generateRSS(); // Generate sitemap (optional) console.log('🗺️ Generating sitemap...'); await generateSitemap(); console.log('✅ Build completed successfully!'); process.exit(0); } catch (error) { console.error('❌ Build failed:', error); process.exit(1); } } async function generateSitemap() { try { const siteDataPath = path.join(process.cwd(), 'public', 'site.json'); if (!fs.existsSync(siteDataPath)) { console.log('⚠️ No site.json found, skipping sitemap generation'); return; } const siteData = JSON.parse(fs.readFileSync(siteDataPath, 'utf8')); const baseUrl = process.env.SITE_URL || 'https://your-site.com'; const urls = [ { loc: baseUrl, lastmod: new Date().toISOString(), changefreq: 'weekly', priority: '1.0' } ]; if (siteData.pages && siteData.pages.length > 0) { urls.push(...siteData.pages.map(page => ({ loc: `${baseUrl}/${page.slug}`, lastmod: page.publishedAt ? new Date(page.publishedAt).toISOString() : new Date().toISOString(), changefreq: 'monthly', priority: '0.8' }))); } const sitemapContent = `<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> ${urls.map(url => ` <url> <loc>${url.loc}</loc> <lastmod>${url.lastmod}</lastmod> <changefreq>${url.changefreq}</changefreq> <priority>${url.priority}</priority> </url>`).join('\n')} </urlset>`; const distDir = path.join(process.cwd(), 'out'); const sitemapPath = path.join(distDir, 'sitemap.xml'); fs.writeFileSync(sitemapPath, sitemapContent, 'utf8'); console.log('✓ Sitemap generated successfully'); } catch (error) { console.error('Error generating sitemap:', error); } } // Export functions for use in other modules module.exports = { generateSite: main, generateRSS, generateSitemap, safeRemoveDir }; if (require.main === module) { main(); }