cq

Distributed social media platform
git clone git://git.finwo.net/app/cq
Log | Files | Refs

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   })