Files
mp-weixin-2811-xcx.aigc-qui…/release.js

400 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const { minify } = require('terser');
// 定义项目根目录
const rootDir = __dirname;
// 定义输出目录
const distDir = path.join(rootDir, 'dist');
// 定义要排除的目录和文件
const excludeDirs = ['node_modules', '.git', 'dist', '.vscode', 'scripts'];
const excludeFiles = ['.gitignore', 'package-lock.json', 'yarn.lock', 'release.js', 'README.md'];
// 统计信息变量
let totalJsOriginalSize = 0;
let totalJsCompressedSize = 0;
let jsFileCount = 0;
const jsSizeDetails = [];
// 存储包含console语句的JS文件
const filesWithConsole = [];
// 存储压缩错误的JS文件
const filesWithCompressionError = [];
// 存储压缩后仍含console语句的JS文件
const filesWithConsoleAfterCompression = [];
// 获取当前日期用于生成zip文件名格式YYYY-MM-DD
function getCurrentDate() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// 定义wxml压缩函数
function compressWxml(content) {
// 移除HTML注释
content = content.replace(/<!--[\s\S]*?-->/g, '');
// 移除多余的空白字符(空格、换行、制表符)
// 保留标签内的必要空格
content = content.replace(/\s+/g, ' ');
// 移除标签前后的空格
content = content.replace(/\s*</g, '<');
content = content.replace(/>\s*/g, '>');
return content;
}
// 定义js压缩函数 - 使用Terser去除console语句
function compressJs(content, filePath) {
return content;
try {
// 使用Terser进行压缩
const result = minify(content, {
compress: {
drop_console: true, // 去除所有console语句
drop_debugger: true, // 去除debugger语句
dead_code: true,
passes: 3 // 增加压缩次数
},
mangle: false, // 不混淆变量名,保持代码可读性
output: {
ascii_only: true, // 确保输出ASCII字符
comments: false // 去除所有注释
}
});
if (result.error) {
console.warn('Terser compression failed for', filePath, ':', result.error.message);
if (filePath && !filesWithCompressionError.includes(filePath)) {
filesWithCompressionError.push(filePath);
}
return content; // 出错时返回原始内容
}
return result.code || content;
} catch (error) {
console.warn('Error in compressJs for', filePath, ':', error.message);
if (filePath && !filesWithCompressionError.includes(filePath)) {
filesWithCompressionError.push(filePath);
}
return content; // 捕获异常时返回原始内容
}
}
// 定义css压缩函数
function compressCss(content) {
// 移除单行注释
content = content.replace(/\/\/.*$/gm, '');
// 移除多行注释
content = content.replace(/\/\*[\s\S]*?\*\//g, '');
// 移除多余的空白字符
content = content.replace(/\s+/g, ' ');
// 移除CSS属性前后的空格
content = content.replace(/\s*([{:;}])\s*/g, '$1');
// 移除行首和行尾的空格
content = content.replace(/^\s+|\s+$/gm, '');
return content;
}
// 定义json压缩函数
function compressJson(content) {
try {
// 使用JSON.parse和JSON.stringify进行压缩
// 确保中文等非ASCII字符不会被转义
const jsonObj = JSON.parse(content);
return JSON.stringify(jsonObj, null, 0);
} catch (error) {
// 如果JSON解析失败返回原始内容
console.warn('Failed to compress JSON, using original content:', error.message);
return content;
}
}
// 输出JS文件压缩统计结果
function outputJsCompressionStats() {
if (jsFileCount === 0) {
console.log('\nNo JS files were processed.');
return;
}
console.log('\n=== JS File Compression Statistics ===');
// 输出每个文件的详细信息
console.log('\nIndividual File Statistics:');
jsSizeDetails.forEach(file => {
console.log(`${file.path}`);
console.log(` Original: ${file.originalSize} bytes`);
console.log(` Compressed: ${file.compressedSize} bytes`);
console.log(` Saved: ${file.sizeDiff} bytes (-${file.compressionRatio}%)`);
console.log('');
});
// 计算整体统计信息
const totalSaved = totalJsOriginalSize - totalJsCompressedSize;
const overallRatio = totalJsOriginalSize > 0 ? (totalSaved / totalJsOriginalSize * 100).toFixed(2) : '0.00';
// 输出整体统计结果
console.log('=== Overall JS Compression Results ===');
console.log(`Total JS files processed: ${jsFileCount}`);
console.log(`Total original size: ${totalJsOriginalSize} bytes`);
console.log(`Total compressed size: ${totalJsCompressedSize} bytes`);
console.log(`Total saved: ${totalSaved} bytes (-${overallRatio}%)`);
console.log('=====================================');
}
// 递归复制目录并压缩文件wxml, js, css, json
function copyAndCompressDir(sourceDir, targetDir) {
// 创建目标目录
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
const files = fs.readdirSync(sourceDir);
files.forEach(file => {
const sourcePath = path.join(sourceDir, file);
const targetPath = path.join(targetDir, file);
const stats = fs.statSync(sourcePath);
// 跳过排除的目录和文件
if (excludeDirs.includes(file) || excludeFiles.includes(file)) {
return;
}
if (stats.isDirectory()) {
// 递归处理子目录
copyAndCompressDir(sourcePath, targetPath);
} else {
const extname = path.extname(file);
let compressedContent;
let content;
try {
// 根据文件类型选择不同的处理方式
if (extname === '.wxml') {
// 压缩wxml文件
content = fs.readFileSync(sourcePath, { encoding: 'utf8' });
compressedContent = compressWxml(content);
fs.writeFileSync(targetPath, compressedContent, { encoding: 'utf8' });
console.log(`Compressed and copied: ${sourcePath}`);
} else if (extname === '.js') {
// 压缩js文件
content = fs.readFileSync(sourcePath, { encoding: 'utf8' });
// 检测是否包含console语句
const hasConsole = /console\.(log|warn|error|info|debug|trace|table|dir|time|timeEnd)/i.test(content);
if (hasConsole) {
filesWithConsole.push(sourcePath);
}
compressedContent = compressJs(content, sourcePath);
// 检测压缩后是否仍包含console语句
const hasConsoleAfterCompression = /console\.(log|warn|error|info|debug|trace|table|dir|time|timeEnd)/i.test(compressedContent);
if (hasConsoleAfterCompression) {
filesWithConsoleAfterCompression.push({ sourcePath, targetPath });
}
fs.writeFileSync(targetPath, compressedContent, { encoding: 'utf8' });
// 统计JS文件大小变化
const originalSize = Buffer.from(content).length;
const compressedSize = Buffer.from(compressedContent).length;
const sizeDiff = originalSize - compressedSize;
const compressionRatio = originalSize > 0 ? (sizeDiff / originalSize * 100).toFixed(2) : '0.00';
totalJsOriginalSize += originalSize;
totalJsCompressedSize += compressedSize;
jsFileCount++;
jsSizeDetails.push({
path: sourcePath,
originalSize,
compressedSize,
sizeDiff,
compressionRatio
});
console.log(`Compressed and copied: ${sourcePath} - ${originalSize}${compressedSize} bytes (-${compressionRatio}%)`);
} else if (extname === '.css') {
// 压缩css文件
content = fs.readFileSync(sourcePath, { encoding: 'utf8' });
compressedContent = compressCss(content);
fs.writeFileSync(targetPath, compressedContent, { encoding: 'utf8' });
console.log(`Compressed and copied: ${sourcePath}`);
} else if (extname === '.json') {
// 压缩json文件
content = fs.readFileSync(sourcePath, { encoding: 'utf8' });
compressedContent = compressJson(content);
fs.writeFileSync(targetPath, compressedContent, { encoding: 'utf8' });
console.log(`Compressed and copied: ${sourcePath}`);
} else {
// 直接复制其他文件
fs.copyFileSync(sourcePath, targetPath);
console.log(`Copied: ${sourcePath}`);
}
} catch (error) {
console.error(`Error processing file ${sourcePath}:`, error.message);
// 发生错误时,直接复制原始文件
fs.copyFileSync(sourcePath, targetPath);
console.log(`Fallback: Copied original file ${sourcePath}`);
}
}
});
}
// 使用系统命令创建zip压缩包
function createZipArchive(sourceDir, outputPath) {
try {
// 根据操作系统选择命令
if (process.platform === 'win32') {
// Windows系统使用PowerShell命令排除文件名后缀为 -mp-weixin.zip 的文件
// 使用PowerShell的管道功能和Where-Object来排除特定文件
const command = `PowerShell.exe -Command "Get-ChildItem -Path \"${sourceDir}\" | Where-Object { $_.Name -notlike '*\-mp\-weixin\.zip' } | Compress-Archive -DestinationPath \"${outputPath}\" -Force"`;
execSync(command, { shell: 'cmd.exe' });
} else {
// Linux/Mac系统使用zip命令排除文件名后缀为 -mp-weixin.zip 的文件
const command = `zip -r \"${outputPath}\" * -x \"*-mp-weixin.zip\"`;
execSync(command, { cwd: sourceDir });
}
console.log(`Zip archive created: ${outputPath}`);
} catch (error) {
console.error('Error creating zip archive:', error.message);
throw error;
}
}
function cleanDistDir(distDir) {
if (fs.existsSync(distDir)) {
// 清理dist目录下除**-mp-weixin.zip文件外的所有内容
const files = fs.readdirSync(distDir);
files.forEach(file => {
const filePath = path.join(distDir, file);
const stats = fs.statSync(filePath);
// 只保留符合特定命名模式的zip文件**-mp-weixin.zip
if (stats.isFile() && path.extname(file) === '.zip' && file.endsWith('-mp-weixin.zip')) {
console.log(`Keeping zip file: ${file}`);
} else {
if (stats.isDirectory()) {
fs.rmSync(filePath, { recursive: true, force: true });
console.log(`Removed directory: ${file}`);
} else {
fs.unlinkSync(filePath);
console.log(`Removed file: ${file}`);
}
}
});
console.log('Cleaned dist directory (excluding -mp-weixin.zip files)');
}
}
// 主函数
function main() {
try {
// 解析命令行参数
const args = process.argv.slice(2);
const keepDist = args.includes('--keep-dist') || args.includes('-k');
const noZip = args.includes('--no-zip') || args.includes('-n');
// 清理dist目录如果存在且不保留
if (fs.existsSync(distDir)) {
cleanDistDir(distDir);
} else {
// 创建dist目录
fs.mkdirSync(distDir, { recursive: true });
console.log('Created dist directory');
}
// 复制并压缩文件到dist目录
console.log('Start copying and compressing files...');
copyAndCompressDir(rootDir, distDir);
console.log('Files copied and compressed successfully!');
// 输出JS文件压缩统计结果
outputJsCompressionStats();
// 生成zip文件名格式POCT检测分析平台-定制化-YYYY-MM-DD-mp-weixin.zip
const currentDate = getCurrentDate();
const zipFileName = `POCT检测分析平台-定制化-${currentDate}-mp-weixin.zip`;
const zipPath = path.join(distDir, zipFileName);
// 创建zip压缩包如果未指定--no-zip参数
if (!noZip) {
console.log('Creating zip archive...');
createZipArchive(distDir, zipPath);
} else {
console.log('Skipping zip archive creation (--no-zip specified)');
}
// 清理dist目录如果不保留
if (!keepDist) {
cleanDistDir(distDir);
}
console.log('\nAll tasks completed successfully!');
console.log(`Dist directory: ${distDir}`);
console.log(`Zip file: ${zipPath}`);
// 输出包含console语句的JS文件列表
if (filesWithConsole.length > 0) {
console.log('\n=== JS Files with Console Statements ===');
console.log(`Found ${filesWithConsole.length} file(s) containing console statements:`);
filesWithConsole.forEach(file => {
console.log(`- ${file}`);
});
console.log('======================================');
} else {
console.log('\nNo JS files contain console statements.');
}
// 输出压缩错误的JS文件列表
if (filesWithCompressionError.length > 0) {
console.log('\n=== JS Files with Compression Errors ===');
console.log(`Found ${filesWithCompressionError.length} file(s) with compression errors:`);
filesWithCompressionError.forEach(file => {
console.log(`- ${file}`);
});
console.log('======================================');
} else {
console.log('\nNo JS files had compression errors.');
}
// 输出压缩后仍含有console语句的JS文件列表
if (filesWithConsoleAfterCompression.length > 0) {
console.log('\n=== JS Files with Console Statements After Compression ===');
console.log(`Found ${filesWithConsoleAfterCompression.length} file(s) still containing console statements after compression:`);
filesWithConsoleAfterCompression.forEach((file, index) => {
console.log(`${index + 1}. ${file.targetPath}`);
});
console.log('\n=================================================');
} else {
console.log('\nNo JS files contain console statements after compression.');
}
} catch (error) {
console.error('Error occurred:', error);
process.exit(1);
}
}
// 执行主函数
main();
// 输出帮助信息
if (process.argv.includes('--help') || process.argv.includes('-h')) {
console.log('Usage: node release.js [options]');
console.log('Options:');
console.log(' --keep-dist, -k Keep existing dist directory contents');
console.log(' --no-zip, -n Skip zip archive creation');
console.log(' --help, -h Show this help message');
}