build.js (4210B)
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.ts', 16 }; 17 18 const define = { 19 'process.env.BASEURL_APP': process.env.BASEURL_APP || '"http://localhost:4000/#!"', 20 }; 21 22 const config = { 23 format: 'esm', 24 platform: 'browser', 25 target: ['chrome108','firefox107'], 26 mainFields: ['browser','module','main'], 27 bundle: true, 28 outdir: __dirname + '/dist', 29 entryPoints: [ 30 ...Object.values(entryPoints), 31 __dirname+'/src/service-worker.ts', 32 ], 33 minify: false, 34 define, 35 36 jsxFactory : 'm', 37 jsxFragment : '"["', 38 39 loader: { 40 '.eot' : 'dataurl', 41 '.html' : 'text', 42 '.wasm' : 'dataurl', 43 '.png' : 'dataurl', 44 '.svg' : 'dataurl', 45 '.ttf' : 'dataurl', 46 '.woff' : 'dataurl', 47 '.woff2': 'dataurl', 48 }, 49 50 plugins: [ 51 nodeModulesPolyfillPlugin({ 52 globals: { 53 Buffer: true 54 } 55 }) 56 ], 57 58 }; 59 60 const buildList = []; 61 const styles = ['global.css']; 62 63 esbuild 64 .build(config) 65 .then(async () => { 66 try { fs.mkdirSync('./dist/assets'); } catch { /* empty */ } 67 await cpy(__dirname + '/src/assets/*', __dirname + '/dist/assets'); 68 await cpy(__dirname + '/src/assets/**/*', __dirname + '/dist/assets'); 69 // try { fs.mkdirSync('./dist/AppModule'); } catch { /* empty */ } 70 fs.copyFileSync(`./src/global.css`, `./dist/global.css`); 71 for(const name of Object.keys(entryPoints)) { 72 buildList.push(`${name}.js`); 73 try { 74 fs.statSync(config.outdir + `/${name}.css`); 75 styles.push(`${name}.css`); 76 } catch(e) { 77 // Intentionally empty 78 } 79 } 80 81 fs.writeFileSync(config.outdir + `/index.html`, `<!DOCTYPE html> 82 <html> 83 <head> 84 <meta charset="utf-8"> 85 <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> 86 <link rel="icon" href="/assets/favicon.ico"> 87 <link rel="apple-touch-icon" href="/assets/apple-touch-icon.png"> 88 <link rel="icon" type="image/png" sizes="192x192" href="/assets/icon-192x192.png"> 89 <link rel="icon" type="image/png" sizes="512x512" href="/assets/icon-512x512.png"> 90 <link rel="manifest" href="/assets/manifest.json"/> 91 <link rel="stylesheet" href="/assets/fonts/karla/karla.css"/> 92 ${styles.map(name => `<link rel="preload" as="style" href="${name}" onload="this.onload=null;this.rel='stylesheet'"/>`).join('\n ')} 93 </head> 94 <body> 95 ${buildList.map(name => `<script type="module" src="${name}" defer></script>`).join('\n ')} 96 </body> 97 </html> 98 `); 99 100 // Build favicons 101 await new Promise(done => { 102 exec(`ffmpeg -n -i ${config.outdir}/assets/icon.png -vf scale=32:32 -sws_flags area ${config.outdir}/assets/favicon.ico`, done); 103 }); 104 await new Promise(done => { 105 exec(`ffmpeg -n -i ${config.outdir}/assets/icon.png -vf scale=180:180 -sws_flags area ${config.outdir}/assets/apple-touch-icon.png`, done); 106 }); 107 108 // Build app icons 109 const manifest = require(__dirname+'/dist/assets/manifest.json'); 110 for(const format of manifest.icons) { 111 const scale = format.sizes.split('x').join(':'); 112 await new Promise(done => { 113 exec(`ffmpeg -n -i ${config.outdir}/assets/icon.png -vf scale=${scale} -sws_flags area ${config.outdir}${format.src}`, done); 114 }); 115 } 116 117 const files = await new Promise(done => { 118 exec(`find ${config.outdir} -type f`, (err,stdout, stderr) => { 119 done(stdout 120 .split('\n') 121 .map(file => file.slice(config.outdir.length)) 122 .filter(file => file) 123 ); 124 }); 125 }); 126 let sw = fs.readFileSync(`${config.outdir}/service-worker.js`, 'utf-8') 127 .split('"--FILES--"').join(JSON.stringify(['/',...files])); 128 fs.writeFileSync(`${config.outdir}/service-worker.js`, sw); 129 })