234 lines
6.4 KiB
JavaScript
234 lines
6.4 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
const glob = require('glob');
|
|
const terser = require('terser');
|
|
const csso = require('csso');
|
|
const htmlmin = require('html-minifier');
|
|
|
|
// Configuration
|
|
const config = {
|
|
rootJs: {
|
|
src: './*.js',
|
|
exclude: './*.min.js',
|
|
outputExt: '.min.js'
|
|
},
|
|
js: {
|
|
src: 'src/**/*.js',
|
|
exclude: 'src/**/*.min.js',
|
|
outputExt: '.min.js'
|
|
},
|
|
css: {
|
|
src: 'src/**/*.css',
|
|
exclude: 'src/**/*.min.css',
|
|
outputExt: '.min.css'
|
|
},
|
|
json: {
|
|
src: 'src/**/*.json'
|
|
},
|
|
html: {
|
|
src: 'src/**/*.html'
|
|
},
|
|
images: {
|
|
src: 'src/**/*.+(png|jpg|jpeg|gif|svg|ico)'
|
|
}
|
|
};
|
|
|
|
// Ensure directory exists
|
|
function ensureDirectoryExistence(filePath) {
|
|
const dirname = path.dirname(filePath);
|
|
if (fs.existsSync(dirname)) return;
|
|
ensureDirectoryExistence(dirname);
|
|
fs.mkdirSync(dirname);
|
|
}
|
|
|
|
// Clean public directory
|
|
function cleanPublicDir() {
|
|
console.log('Cleaning public directory...');
|
|
if (fs.existsSync('public')) {
|
|
fs.rmSync('public', { recursive: true, force: true });
|
|
}
|
|
fs.mkdirSync('public');
|
|
console.log('✓ Public directory cleaned');
|
|
}
|
|
|
|
// Create output path preserving directory structure
|
|
function createOutputPath(file, baseDir, outputExt = null) {
|
|
// Get relative path from the source root
|
|
const relativePath = path.relative(baseDir, file);
|
|
|
|
// Create public path with the same relative structure
|
|
let outputPath = path.join('public', relativePath);
|
|
|
|
// Apply output extension if provided
|
|
if (outputExt) {
|
|
outputPath = outputPath.replace(path.extname(outputPath), outputExt);
|
|
}
|
|
|
|
return outputPath;
|
|
}
|
|
|
|
// Minify JavaScript files
|
|
async function minifyJS() {
|
|
console.log('Minifying JavaScript files...');
|
|
|
|
// Minify root-level JS files (like app.js)
|
|
const rootFiles = glob.sync(config.rootJs.src, { ignore: config.rootJs.exclude });
|
|
|
|
for (const file of rootFiles) {
|
|
// Skip already minified files and module files
|
|
if (file.endsWith('.min.js') || file === 'build.js') continue;
|
|
|
|
const content = fs.readFileSync(file, 'utf8');
|
|
const result = await terser.minify(content, {
|
|
compress: true,
|
|
mangle: true
|
|
});
|
|
|
|
const outputPath = createOutputPath(file, '.', config.rootJs.outputExt);
|
|
ensureDirectoryExistence(outputPath);
|
|
fs.writeFileSync(outputPath, result.code);
|
|
console.log(`✓ Minified: ${file} -> ${outputPath}`);
|
|
}
|
|
|
|
// Minify JavaScript files in src directory
|
|
const srcFiles = glob.sync(config.js.src, { ignore: config.js.exclude });
|
|
|
|
for (const file of srcFiles) {
|
|
// Skip already minified files, type definition, and map files
|
|
if (file.endsWith('.min.js') || file.endsWith('.d.ts') || file.endsWith('.map')) continue;
|
|
|
|
const content = fs.readFileSync(file, 'utf8');
|
|
const result = await terser.minify(content, {
|
|
compress: true,
|
|
mangle: true
|
|
});
|
|
|
|
const outputPath = createOutputPath(file, '.', config.js.outputExt);
|
|
ensureDirectoryExistence(outputPath);
|
|
fs.writeFileSync(outputPath, result.code);
|
|
console.log(`✓ Minified: ${file} -> ${outputPath}`);
|
|
}
|
|
}
|
|
|
|
// Minify CSS files
|
|
function minifyCSS() {
|
|
console.log('Minifying CSS files...');
|
|
const files = glob.sync(config.css.src, { ignore: config.css.exclude });
|
|
|
|
for (const file of files) {
|
|
if (file.endsWith('.min.css')) continue;
|
|
|
|
const content = fs.readFileSync(file, 'utf8');
|
|
const result = csso.minify(content);
|
|
|
|
const outputPath = createOutputPath(file, '.', config.css.outputExt);
|
|
ensureDirectoryExistence(outputPath);
|
|
fs.writeFileSync(outputPath, result.css);
|
|
console.log(`✓ Minified: ${file} -> ${outputPath}`);
|
|
}
|
|
}
|
|
|
|
// Minify JSON files
|
|
function minifyJSON() {
|
|
console.log('Minifying JSON files...');
|
|
const files = glob.sync(config.json.src);
|
|
|
|
for (const file of files) {
|
|
const content = fs.readFileSync(file, 'utf8');
|
|
const jsonData = JSON.parse(content);
|
|
const minified = JSON.stringify(jsonData);
|
|
|
|
const outputPath = createOutputPath(file, '.');
|
|
ensureDirectoryExistence(outputPath);
|
|
fs.writeFileSync(outputPath, minified);
|
|
console.log(`✓ Minified: ${file} -> ${outputPath}`);
|
|
}
|
|
}
|
|
|
|
// Minify HTML files and update references
|
|
function minifyHTML() {
|
|
console.log('Minifying HTML files...');
|
|
const files = glob.sync(config.html.src);
|
|
|
|
for (const file of files) {
|
|
let content = fs.readFileSync(file, 'utf8');
|
|
|
|
// Update JS references to minified versions, preserving directory structure
|
|
content = content.replace(/src=["'](.+?)\.js["']/g, (match, p1) => {
|
|
return `src="${p1}.min.js"`;
|
|
});
|
|
|
|
// Update CSS references to minified versions, preserving directory structure
|
|
content = content.replace(/href=["'](.+?)\.css["']/g, (match, p1) => {
|
|
return `href="${p1}.min.css"`;
|
|
});
|
|
|
|
// Minify HTML
|
|
const minified = htmlmin.minify(content, {
|
|
collapseWhitespace: true,
|
|
removeComments: true,
|
|
minifyJS: true,
|
|
minifyCSS: true,
|
|
removeRedundantAttributes: true,
|
|
removeEmptyAttributes: true,
|
|
removeOptionalTags: true
|
|
});
|
|
|
|
const outputPath = createOutputPath(file, '.');
|
|
ensureDirectoryExistence(outputPath);
|
|
fs.writeFileSync(outputPath, minified);
|
|
console.log(`✓ Minified: ${file} -> ${outputPath}`);
|
|
}
|
|
}
|
|
|
|
// Copy images
|
|
function copyImages() {
|
|
console.log('Copying images...');
|
|
const files = glob.sync(config.images.src);
|
|
|
|
for (const file of files) {
|
|
const outputPath = createOutputPath(file, '.');
|
|
ensureDirectoryExistence(outputPath);
|
|
fs.copyFileSync(file, outputPath);
|
|
console.log(`✓ Copied: ${file} -> ${outputPath}`);
|
|
}
|
|
}
|
|
|
|
// Copy other files like README.md
|
|
function copyMiscFiles() {
|
|
console.log('Copying miscellaneous files...');
|
|
const filesToCopy = [
|
|
'README.md',
|
|
'package.json',
|
|
'package-lock.json'
|
|
];
|
|
|
|
for (const file of filesToCopy) {
|
|
if (fs.existsSync(file)) {
|
|
const outputPath = path.join('public', file);
|
|
fs.copyFileSync(file, outputPath);
|
|
console.log(`✓ Copied: ${file} -> ${outputPath}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Main function
|
|
async function build() {
|
|
console.log('Starting build process...');
|
|
|
|
cleanPublicDir();
|
|
await minifyJS();
|
|
minifyCSS();
|
|
minifyJSON();
|
|
minifyHTML();
|
|
copyImages();
|
|
copyMiscFiles();
|
|
|
|
console.log('Build completed successfully!');
|
|
}
|
|
|
|
// Run the build
|
|
build().catch(err => {
|
|
console.error('Build failed:', err);
|
|
process.exit(1);
|
|
}); |