ATlast — you'll never need to find your favorites on another platform again. Find your favs in the ATmosphere.
atproto
at master 5.3 kB view raw
1import * as esbuild from 'esbuild'; 2import * as fs from 'fs'; 3import * as path from 'path'; 4import { fileURLToPath } from 'url'; 5import postcss from 'postcss'; 6import tailwindcss from 'tailwindcss'; 7import autoprefixer from 'autoprefixer'; 8 9const __dirname = path.dirname(fileURLToPath(import.meta.url)); 10 11const watch = process.argv.includes('--watch'); 12const isProd = process.argv.includes('--prod') || process.env.NODE_ENV === 'production'; 13const mode = isProd ? 'production' : 'development'; 14 15// Environment-specific configuration 16const ATLAST_API_URL = mode === 'production' 17 ? 'https://atlast.byarielm.fyi' 18 : 'http://127.0.0.1:8888'; 19 20console.log(`🌍 Building for ${mode} mode`); 21console.log(`🔗 API URL: ${ATLAST_API_URL}`); 22 23// Clean dist directory 24const distBaseDir = path.join(__dirname, 'dist'); 25if (fs.existsSync(distBaseDir)) { 26 fs.rmSync(distBaseDir, { recursive: true }); 27} 28fs.mkdirSync(distBaseDir, { recursive: true }); 29 30// Build configuration base 31const buildConfigBase = { 32 bundle: true, 33 minify: !watch, 34 sourcemap: watch ? 'inline' : false, 35 target: 'es2020', 36 format: 'esm', 37 define: { 38 '__ATLAST_API_URL__': JSON.stringify(ATLAST_API_URL), 39 '__BUILD_MODE__': JSON.stringify(mode), 40 }, 41 // Include webextension-polyfill in the bundle 42 external: [], 43}; 44 45// Build scripts for a specific browser 46function getScripts(browser) { 47 const distDir = path.join(distBaseDir, browser); 48 return [ 49 { 50 ...buildConfigBase, 51 entryPoints: ['src/content/index.ts'], 52 outfile: path.join(distDir, 'content', 'index.js'), 53 }, 54 { 55 ...buildConfigBase, 56 entryPoints: ['src/background/service-worker.ts'], 57 outfile: path.join(distDir, 'background', 'service-worker.js'), 58 }, 59 { 60 ...buildConfigBase, 61 entryPoints: ['src/popup/popup.ts'], 62 outfile: path.join(distDir, 'popup', 'popup.js'), 63 }, 64 ]; 65} 66 67// Build function 68async function build() { 69 try { 70 console.log('🔨 Building extension for Chrome and Firefox...'); 71 72 const browsers = ['chrome', 'firefox']; 73 74 for (const browser of browsers) { 75 console.log(`\n📦 Building ${browser} version...`); 76 const scripts = getScripts(browser); 77 78 // Build all scripts 79 for (const config of scripts) { 80 if (watch) { 81 const ctx = await esbuild.context(config); 82 await ctx.watch(); 83 console.log(`👀 Watching ${browser}/${path.basename(config.entryPoints[0])}...`); 84 } else { 85 await esbuild.build(config); 86 console.log(`✅ Built ${browser}/${path.basename(config.entryPoints[0])}`); 87 } 88 } 89 90 // Copy static files 91 copyStaticFiles(browser); 92 93 // Process CSS with Tailwind 94 await processCSS(browser); 95 } 96 97 if (!watch) { 98 console.log('\n✨ Build complete for both browsers!'); 99 } 100 } catch (error) { 101 console.error('❌ Build failed:', error); 102 process.exit(1); 103 } 104} 105 106// Process CSS with PostCSS (Tailwind + Autoprefixer) 107async function processCSS(browser) { 108 const cssPath = path.join(__dirname, 'src/popup/popup.css'); 109 const distDir = path.join(distBaseDir, browser); 110 const outputPath = path.join(distDir, 'popup/popup.css'); 111 112 const css = fs.readFileSync(cssPath, 'utf8'); 113 114 // Import cssnano dynamically for production minification 115 const plugins = [tailwindcss, autoprefixer]; 116 if (isProd) { 117 const cssnano = (await import('cssnano')).default; 118 plugins.push(cssnano); 119 } 120 121 const result = await postcss(plugins).process(css, { 122 from: cssPath, 123 to: outputPath, 124 }); 125 126 // Create directory if it doesn't exist 127 const destDir = path.dirname(outputPath); 128 if (!fs.existsSync(destDir)) { 129 fs.mkdirSync(destDir, { recursive: true }); 130 } 131 132 fs.writeFileSync(outputPath, result.css); 133 console.log('🎨 Processed CSS with Tailwind'); 134} 135 136// Copy static files 137function copyStaticFiles(browser) { 138 const distDir = path.join(distBaseDir, browser); 139 140 const filesToCopy = [ 141 { from: `manifest.${browser}.json`, to: 'manifest.json', fallback: 'manifest.json' }, 142 { from: 'src/popup/popup.html', to: 'popup/popup.html' }, 143 ]; 144 145 for (const file of filesToCopy) { 146 // Try to use browser-specific file first, fall back to default 147 let srcPath = path.join(__dirname, file.from); 148 if (file.fallback && !fs.existsSync(srcPath)) { 149 srcPath = path.join(__dirname, file.fallback); 150 } 151 const destPath = path.join(distDir, file.to); 152 153 // Create directory if it doesn't exist 154 const destDir = path.dirname(destPath); 155 if (!fs.existsSync(destDir)) { 156 fs.mkdirSync(destDir, { recursive: true }); 157 } 158 159 fs.copyFileSync(srcPath, destPath); 160 } 161 162 // Create placeholder icons (TODO: replace with actual icons) 163 const assetsDir = path.join(distDir, 'assets'); 164 if (!fs.existsSync(assetsDir)) { 165 fs.mkdirSync(assetsDir, { recursive: true }); 166 } 167 168 // Create simple text files as placeholder icons 169 const sizes = [16, 48, 128]; 170 for (const size of sizes) { 171 const iconPath = path.join(assetsDir, `icon-${size}.png`); 172 if (!fs.existsSync(iconPath)) { 173 // TODO: Generate actual PNG icons 174 fs.writeFileSync(iconPath, `Placeholder ${size}x${size} icon`); 175 } 176 } 177 178 console.log('📋 Copied static files'); 179} 180 181// Run build 182build();