2023-10-13 18:08:45 +00:00
|
|
|
const fs = require('fs');
|
|
|
|
const swc = require('@swc/core');
|
|
|
|
const path = require('path');
|
|
|
|
const util = require('util');
|
2023-10-14 23:05:49 +00:00
|
|
|
const exec = util.promisify(require('child_process').exec);
|
2023-10-13 18:08:45 +00:00
|
|
|
const postcss = require('postcss');
|
2023-10-14 23:05:49 +00:00
|
|
|
const htmlminify = require('html-minifier-terser').minify;
|
2023-10-13 18:08:45 +00:00
|
|
|
const utils = require('./assets/utils.js');
|
|
|
|
const assproc = require('./assets/assproc.js');
|
|
|
|
|
|
|
|
const rootDir = __dirname;
|
|
|
|
|
|
|
|
const assetsDir = path.join(rootDir, 'assets');
|
|
|
|
const assetsInfo = path.join(assetsDir, 'current.json');
|
|
|
|
|
|
|
|
const pubDir = path.join(rootDir, 'public');
|
|
|
|
const pubAssets = '/assets';
|
|
|
|
const pubAssetsFull = path.join(pubDir, pubAssets);
|
|
|
|
const pubAssetCSSFormat = '%s-%s.css';
|
|
|
|
const pubAssetJSFormat = '%s-%s.js';
|
|
|
|
|
|
|
|
const isDebugBuild = fs.existsSync(path.join(rootDir, '.debug'));
|
|
|
|
|
2023-10-14 23:05:49 +00:00
|
|
|
const renderTemplates = [
|
|
|
|
{ in: 'errors/401', out: '/error-401.html' },
|
|
|
|
{ in: 'errors/403', out: '/error-403.html' },
|
|
|
|
{ in: 'errors/404', out: '/error-404.html' },
|
|
|
|
{ in: 'errors/500', out: '/error-500.html' },
|
|
|
|
{ in: 'errors/503', out: '/error-503.html' },
|
|
|
|
];
|
|
|
|
|
2023-10-13 18:08:45 +00:00
|
|
|
const swcJscOptions = {
|
|
|
|
target: 'es2016',
|
|
|
|
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',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-10-14 23:05:49 +00:00
|
|
|
const htmlMinifyOptions = {
|
|
|
|
collapseBooleanAttributes: true,
|
|
|
|
collapseWhitespace: true,
|
|
|
|
conservativeCollapse: false,
|
|
|
|
decodeEntities: false,
|
|
|
|
quoteCharacter: '"',
|
|
|
|
removeAttributeQuotes: true,
|
|
|
|
removeComments: true,
|
|
|
|
removeEmptyAttributes: true,
|
|
|
|
removeOptionalTags: true,
|
|
|
|
removeScriptTypeAttributes: true,
|
|
|
|
removeStyleLinkTypeAttributes: true,
|
|
|
|
sortAttributes: true,
|
|
|
|
sortClassName: true,
|
|
|
|
};
|
|
|
|
|
2023-10-13 18:08:45 +00:00
|
|
|
const postcssPlugins = [];
|
|
|
|
if(!isDebugBuild) postcssPlugins.push(require('cssnano'));
|
|
|
|
postcssPlugins.push(require('autoprefixer')({
|
|
|
|
remove: false,
|
|
|
|
}));
|
|
|
|
|
|
|
|
fs.mkdirSync(pubAssetsFull, { recursive: true });
|
|
|
|
|
|
|
|
(async () => {
|
2023-10-13 19:33:34 +00:00
|
|
|
console.log('Building assets...');
|
|
|
|
|
|
|
|
const dirs = fs.readdirSync(assetsDir);
|
|
|
|
const assets = {};
|
|
|
|
|
|
|
|
const _postcss = postcss(postcssPlugins);
|
|
|
|
|
|
|
|
for(const dir of dirs) {
|
|
|
|
const dirPath = path.join(assetsDir, dir);
|
|
|
|
if(!fs.statSync(dirPath).isDirectory())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
const parts = dir.split('.', 2);
|
|
|
|
if(parts.length < 2)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
console.log();
|
|
|
|
console.log(dir);
|
|
|
|
|
|
|
|
let filePath = '';
|
|
|
|
let fileBody = '';
|
|
|
|
|
|
|
|
if(parts[1] === 'js') {
|
|
|
|
fileBody = await assproc.process(dirPath, { 'prefix': '#', 'entry': 'main.js' });
|
|
|
|
fileBody = (await swc.transform(fileBody, {
|
|
|
|
filename: dir,
|
|
|
|
sourceMaps: false,
|
|
|
|
isModule: false,
|
|
|
|
minify: !isDebugBuild,
|
|
|
|
jsc: swcJscOptions,
|
|
|
|
})).code;
|
|
|
|
filePath = path.join(pubAssets, util.format(pubAssetJSFormat, parts[0], utils.shortHash(fileBody)));
|
|
|
|
} else if(parts[1] === 'css') {
|
|
|
|
fileBody = await assproc.process(dirPath, { 'prefix': '@', 'entry': 'main.css' });
|
|
|
|
fileBody = (await _postcss.process(fileBody, { from: dir })).css;
|
|
|
|
filePath = path.join(pubAssets, util.format(pubAssetCSSFormat, parts[0], utils.shortHash(fileBody)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(filePath !== '') {
|
|
|
|
assets[dir] = filePath;
|
|
|
|
fs.writeFileSync(path.join(pubDir, filePath), fileBody);
|
|
|
|
} else console.error(`Unknown type: ${parts[1]}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log('Writing assets info...');
|
|
|
|
fs.writeFileSync(assetsInfo, JSON.stringify(assets));
|
2023-10-13 18:08:45 +00:00
|
|
|
|
2023-10-14 23:05:49 +00:00
|
|
|
console.log('Housekeeping...');
|
2023-10-13 18:08:45 +00:00
|
|
|
assproc.housekeep(pubAssetsFull);
|
2023-10-14 23:05:49 +00:00
|
|
|
|
|
|
|
console.log('Prerendering templates...');
|
|
|
|
|
|
|
|
const renderCommand = path.join(rootDir, 'tools/render-tpl');
|
|
|
|
console.log(renderCommand);
|
|
|
|
|
|
|
|
for(const info of renderTemplates) {
|
|
|
|
console.log();
|
|
|
|
console.log(info.in);
|
|
|
|
|
|
|
|
const { stdout, stderr } = await exec(`${renderCommand} ${info.in}`);
|
|
|
|
|
|
|
|
if(stdout.trim() === '') {
|
|
|
|
console.error(stderr);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let body = await htmlminify(stdout, htmlMinifyOptions);
|
|
|
|
|
|
|
|
fs.writeFileSync(path.join(pubDir, info.out), body);
|
|
|
|
}
|
2023-10-13 18:08:45 +00:00
|
|
|
})();
|