Files
jiapu/scripts/build-minified.mjs

87 lines
3.1 KiB
JavaScript

import { copyFile, mkdir, readdir, readFile, rm, stat, writeFile } from 'node:fs/promises';
import { dirname, extname, join, resolve } from 'node:path';
import { transform } from 'esbuild';
const sourceRoot = resolve(import.meta.dirname, '..');
const outputRoot = resolve(sourceRoot, 'dist');
const sourceDirectories = ['public', 'utils'];
const sourceFiles = ['config.js', 'tokens.css'];
const totals = {
css: { files: 0, sourceBytes: 0, outputBytes: 0 },
js: { files: 0, sourceBytes: 0, outputBytes: 0 }
};
function shouldMinify(filePath) {
const extension = extname(filePath).toLowerCase();
return (extension === '.css' || extension === '.js') && !filePath.toLowerCase().endsWith(`.min${extension}`);
}
async function writeBuildFile(sourcePath, destinationPath) {
await mkdir(dirname(destinationPath), { recursive: true });
if (!shouldMinify(sourcePath)) {
await copyFile(sourcePath, destinationPath);
return;
}
const extension = extname(sourcePath).slice(1).toLowerCase();
const source = await readFile(sourcePath, 'utf8');
const result = await transform(source, {
loader: extension,
minify: true,
target: 'es2018',
charset: 'utf8',
legalComments: 'inline'
});
const output = result.code.trimEnd() + '\n';
await writeFile(destinationPath, output, 'utf8');
totals[extension].files += 1;
totals[extension].sourceBytes += Buffer.byteLength(source);
totals[extension].outputBytes += Buffer.byteLength(output);
}
async function copyDirectory(sourceDirectory, destinationDirectory) {
await mkdir(destinationDirectory, { recursive: true });
for (const entry of await readdir(sourceDirectory, { withFileTypes: true })) {
const sourcePath = join(sourceDirectory, entry.name);
const destinationPath = join(destinationDirectory, entry.name);
if (entry.isDirectory()) await copyDirectory(sourcePath, destinationPath);
else if (entry.isFile()) await writeBuildFile(sourcePath, destinationPath);
}
}
function formatSavings(type) {
const total = totals[type];
const percent = total.sourceBytes
? Math.round((1 - total.outputBytes / total.sourceBytes) * 100)
: 0;
return `${type.toUpperCase()}: ${total.files} 个文件,${total.sourceBytes}${total.outputBytes} 字节,减少 ${percent}%`;
}
if (outputRoot !== resolve(sourceRoot, 'dist')) {
throw new Error('拒绝清理预期目录之外的构建输出');
}
await rm(outputRoot, { recursive: true, force: true });
await mkdir(outputRoot, { recursive: true });
for (const entry of await readdir(sourceRoot, { withFileTypes: true })) {
if (entry.isFile() && entry.name.endsWith('.html')) {
await copyFile(join(sourceRoot, entry.name), join(outputRoot, entry.name));
}
}
for (const file of sourceFiles) {
await writeBuildFile(join(sourceRoot, file), join(outputRoot, file));
}
for (const directory of sourceDirectories) {
const sourceDirectory = join(sourceRoot, directory);
if ((await stat(sourceDirectory)).isDirectory()) {
await copyDirectory(sourceDirectory, join(outputRoot, directory));
}
}
console.log(`压缩构建已生成:${outputRoot}`);
console.log(formatSavings('css'));
console.log(formatSavings('js'));