build.cjs (3667B)
1 #!/usr/bin/env node 2 3 // require('dotenv').config(); 4 const cpy = require('cpy').default; 5 const fs = require('node:fs'); 6 const { dirname } = require('node:path'); 7 const { fileURLToPath } = require('node:url'); 8 const { exec } = require('node:child_process'); 9 const esbuild = require('esbuild'); 10 // const { nodeModulesPolyfillPlugin } = require('esbuild-plugins-node-modules-polyfill'); 11 12 // const __dirname = dirname(fileURLToPath(import.meta.url)); 13 14 const entryPoints = { 15 'main': __dirname + '/src/main.tsx', 16 }; 17 18 const config = { 19 format: 'iife', // immediately invoked function expression 20 platform: 'browser', 21 target: ['chrome108','firefox107'], 22 mainFields: ['browser','module','main'], 23 bundle: true, 24 outdir: __dirname + '/dist', 25 entryPoints: [ 26 ...Object.values(entryPoints), 27 // __dirname+'/src/service-worker.ts', 28 ], 29 minify: false, 30 // define, 31 32 jsxFactory : 'm', 33 jsxFragment : '"["', 34 35 loader: { 36 '.eot' : 'dataurl', 37 '.html' : 'text', 38 '.wasm' : 'dataurl', 39 '.png' : 'dataurl', 40 '.svg' : 'dataurl', 41 '.ttf' : 'dataurl', 42 '.woff' : 'dataurl', 43 '.woff2': 'dataurl', 44 }, 45 46 // Kept for when a Buffer is needed. 47 // plugins: [ 48 // nodeModulesPolyfillPlugin({ 49 // globals: { 50 // Buffer: true 51 // } 52 // }) 53 // ], 54 55 }; 56 57 const buildList = []; 58 const styles = ['global.css']; 59 60 esbuild 61 .build(config) 62 .then(async () => { 63 try { fs.mkdirSync('./dist/assets'); } catch { /* empty */ } 64 // Already rendered at every size by util/icon.js, so only copied here. 65 await cpy(__dirname + '/src/assets/**/*', __dirname + '/dist/assets'); 66 // try { fs.mkdirSync('./dist/AppModule'); } catch { /* empty */ } 67 fs.copyFileSync(__dirname + `/src/global.css`, config.outdir + `/global.css`); 68 for(const name of Object.keys(entryPoints)) { 69 buildList.push(`${name}.js`); 70 try { 71 fs.statSync(config.outdir + `/${name}.css`); 72 styles.push(`${name}.css`); 73 } catch(e) { 74 // Intentionally empty 75 } 76 } 77 78 fs.writeFileSync(config.outdir + `/index.html`, `<!DOCTYPE html> 79 <html> 80 <head> 81 <meta charset="utf-8"> 82 <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> 83 <title>conductor</title> 84 <link rel="icon" type="image/svg+xml" href="assets/icon.svg"> 85 <link rel="icon" type="image/png" sizes="32x32" href="assets/favicon-32.png"> 86 <link rel="icon" type="image/png" sizes="32x32" href="assets/favicon-32-dark.png" media="(prefers-color-scheme: dark)"> 87 <link rel="apple-touch-icon" href="assets/apple-touch-icon.png"> 88 <link rel="manifest" href="assets/manifest.json"/> 89 <!-- <link rel="stylesheet" href="/assets/fonts/karla/karla.css"/> --> 90 ${styles.map(name => `<link rel="stylesheet" href="${name}"/>`).join('\n ')} 91 </head> 92 <body> 93 ${buildList.map(name => `<script src="${name}" defer></script>`).join('\n ')} 94 </body> 95 </html> 96 `); 97 98 // const files = await new Promise(done => { 99 // exec(`find ${config.outdir} -type f`, (err,stdout, stderr) => { 100 // done(stdout 101 // .split('\n') 102 // .map(file => file.slice(config.outdir.length)) 103 // .filter(file => file) 104 // ); 105 // }); 106 // }); 107 // let sw = fs.readFileSync(`${config.outdir}/service-worker.js`, 'utf-8') 108 // .split('"--FILES--"').join(JSON.stringify(['/',...files])); 109 // fs.writeFileSync(`${config.outdir}/service-worker.js`, sw); 110 }) 111 // Without this a failed build still exits 0, and the image ships empty. 112 .catch(e => { console.error(e); process.exit(1); });