// IMPORTS const fs = require('fs'); const swc = require('@swc/core'); const path = require('path'); const util = require('util'); const postcss = require('postcss'); const utils = require('./assets/utils.js'); const assproc = require('./assets/assproc.js'); // CONFIG const rootDir = __dirname; const srcDir = path.join(rootDir, 'assets'); const srcCurrentInfo = path.join(srcDir, 'current.json'); const pubDir = path.join(rootDir, 'public'); const pubAssetsDir = path.join(pubDir, 'assets'); const isDebugBuild = fs.existsSync(path.join(rootDir, '.debug')); const buildTasks = { js: [ { source: 'misuzu.js', target: '/assets', name: 'misuzu.{hash}.js', }, ], css: [ { source: 'misuzu.css', target: '/assets', name: 'misuzu.{hash}.css', }, ], }; // PREP const postcssPlugins = [ require('autoprefixer')({ remove: false }) ]; if(!isDebugBuild) postcssPlugins.push(require('cssnano')({ preset: [ 'cssnano-preset-default', { minifyGradients: false, reduceIdents: false, zindex: true, } ], })); const swcJscOptions = { target: 'es2021', loose: false, externalHelpers: false, keepClassNames: true, preserveAllComments: false, transform: {}, parser: { syntax: 'ecmascript', jsx: true, dynamicImport: false, privateMethod: false, functionBind: false, exportDefaultFrom: false, exportNamespaceFrom: false, decorators: false, decoratorsBeforeExport: false, topLevelAwait: true, importMeta: false, }, transform: { react: { runtime: 'classic', pragma: '$er', }, }, }; // BUILD (async () => { const files = {}; console.log('Ensuring assets directory exists...'); fs.mkdirSync(pubAssetsDir, { recursive: true }); console.log(); console.log('JS assets'); for(const info of buildTasks.js) { console.log(`=> Building ${info.source}...`); let origTarget = undefined; if('es' in info) { origTarget = swcJscOptions.target; swcJscOptions.target = info.es; } const assprocOpts = { prefix: '#', entry: info.entry || 'main.js', }; const swcOpts = { filename: info.source, sourceMaps: false, isModule: false, minify: !isDebugBuild, jsc: swcJscOptions, }; const pubName = await assproc.process(path.join(srcDir, info.source), assprocOpts) .then(output => swc.transform(output, swcOpts)) .then(output => { const name = utils.strtr(info.name, { hash: utils.shortHash(output.code) }); const pubName = path.join(info.target || '', name); console.log(` Saving to ${pubName}...`); fs.writeFileSync(path.join(pubDir, pubName), output.code); return pubName; }); if(origTarget !== undefined) swcJscOptions.target = origTarget; files[info.source] = pubName; } console.log(); console.log('CSS assets'); for(const info of buildTasks.css) { console.log(`=> Building ${info.source}...`); const sourcePath = path.join(srcDir, info.source); const assprocOpts = { prefix: '@', entry: info.entry || 'main.css', }; const postcssOpts = { from: sourcePath }; files[info.source] = await assproc.process(sourcePath, assprocOpts) .then(output => postcss(postcssPlugins).process(output, postcssOpts) .then(output => { const name = utils.strtr(info.name, { hash: utils.shortHash(output.css) }); const pubName = path.join(info.target || '', name); console.log(` Saving to ${pubName}...`); fs.writeFileSync(path.join(pubDir, pubName), output.css); return pubName; })); } console.log(); console.log('Writing assets info...'); fs.writeFileSync(srcCurrentInfo, JSON.stringify(files)); console.log(); console.log('Cleaning up old builds...'); assproc.housekeep(pubAssetsDir); })();