chore(release.js): 当前发布程序

This commit is contained in:
2025-12-29 18:19:46 +08:00
parent 5edaf8fd08
commit 30ee81521b

View File

@@ -49,24 +49,79 @@ function compressWxml(content) {
return content; return content;
} }
// 定义js压缩函数 - 使用Terser去除console语句 // 检测代码是否已被压缩
function isCodeCompressed(content) {
// 如果代码没有换行符或换行符很少,很可能是已压缩的
const lineBreaks = (content.match(/\n/g) || []).length;
const hasManyLineBreaks = lineBreaks > content.length / 50; // 平均每50个字符至少有一个换行
// 如果代码有很多连续的分号或逗号,很可能是已压缩的
const hasManyConsecutiveSemicolons = /;{2,}/.test(content);
const hasManyConsecutiveCommas = /,{2,}/.test(content);
// 如果代码没有注释,很可能是已压缩的
const hasComments = /\/\/|\/\*/.test(content);
return !hasManyLineBreaks || hasManyConsecutiveSemicolons || hasManyConsecutiveCommas || !hasComments;
}
// 定义js压缩函数 - 使用Terser去除console语句、未使用变量和注释
function compressJs(content, filePath) { function compressJs(content, filePath) {
return content; return content;
try { try {
// 使用Terser进行压缩 // 检测代码是否已被压缩
const result = minify(content, { const isCompressed = isCodeCompressed(content);
// 先尝试使用正则表达式直接去除console语句
let processedContent = content;
// 匹配完整的console函数调用支持嵌套括号
const consoleRegex = /console\.(log|warn|error|info|debug|trace|table|dir|time|timeEnd|assert|clear|count|countReset|group|groupCollapsed|groupEnd|memory|profile|profileEnd|timeStamp)\s*\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)\s*;/gi;
processedContent = processedContent.replace(consoleRegex, '');
// 配置基础压缩选项
const baseOptions = {
compress: { compress: {
drop_console: true, // 去除所有console语句 drop_console: true, // 去除所有console语句
drop_debugger: true, // 去除debugger语句 drop_debugger: true, // 去除debugger语句
dead_code: true, dead_code: true, // 移除死代码
passes: 3 // 增加压缩次数 unused: true, // 移除未使用的变量
toplevel: true, // 清理顶层作用域未使用的变量
passes: isCompressed ? 15 : 10, // 大幅增加压缩次数
reduce_funcs: true, // 合并或移除未使用的函数
collapse_vars: true, // 折叠定义后不再修改的变量
sequences: true, // 合并连续的变量声明
evaluate: true, // 提前计算常量表达式
unsafe: true, // 已压缩代码启用更激进的压缩策略
unsafe_comps: true, // 优化比较操作
reduce_vars: true, // 合并或移除变量
join_vars: true, // 合并变量声明
side_effects: false, // 假设函数调用没有副作用
pure_funcs: ['console.log', 'console.warn', 'console.error', 'console.info', 'console.debug'], // 标记这些函数为纯函数,可以安全移除
pure_getters: true, // 假设getter函数没有副作用
unsafe_math: true, // 允许不安全的数学优化
unsafe_proto: true, // 允许不安全的原型优化
unsafe_regexp: true, // 允许不安全的正则表达式优化
conditionals: true, // 优化条件表达式
comparisons: true, // 优化比较操作
booleans: true, // 优化布尔表达式
typeofs: true // 优化typeof操作
}, },
mangle: false, // 不混淆变量名,保持代码可读性 mangle: false, // 不混淆变量名,保持代码可读性
output: { format: {
ascii_only: true, // 确保输出ASCII字符 ascii_only: true, // 确保输出ASCII字符
comments: false // 去除所有注释 comments: false, // 去除所有注释
beautify: false // 不美化输出
},
// 为已压缩代码启用更严格的处理
parse: {
bare_returns: true, // 允许顶级return语句
expression: false // 禁用表达式模式
} }
}); };
// 使用Terser进行压缩
const result = minify(processedContent, baseOptions);
if (result.error) { if (result.error) {
console.warn('Terser compression failed for', filePath, ':', result.error.message); console.warn('Terser compression failed for', filePath, ':', result.error.message);
@@ -153,6 +208,87 @@ function outputJsCompressionStats() {
console.log('====================================='); console.log('=====================================');
} }
// 递归处理dist目录下已有的JS文件再次压缩以去除console语句、未使用变量和注释
function processExistingJsFiles(distDir) {
console.log(`Processing directory: ${distDir}`);
const files = fs.readdirSync(distDir);
console.log(`Found files: ${files.join(', ')}`);
files.forEach(file => {
const filePath = path.join(distDir, file);
const stats = fs.statSync(filePath);
if (stats.isDirectory()) {
// 递归处理子目录
processExistingJsFiles(filePath);
} else if (path.extname(file) === '.js') {
// 处理JS文件
console.log(`Found JS file: ${filePath}`);
try {
let content = fs.readFileSync(filePath, { encoding: 'utf8' });
// 检测是否包含console语句
const hasConsole = /console\.(log|warn|error|info|debug|trace|table|dir|time|timeEnd)/i.test(content);
if (hasConsole) {
filesWithConsole.push(filePath);
}
// 直接使用正则表达式去除console语句优化版本减少复杂度
let processedContent = content;
// 匹配完整的console函数调用支持嵌套括号
const consoleRegex = /console\.(log|warn|error|info|debug|trace|table|dir|time|timeEnd|assert|clear|count|countReset|group|groupCollapsed|groupEnd|memory|profile|profileEnd|timeStamp)\s*\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)\s*;/gi;
processedContent = processedContent.replace(consoleRegex, '');
// 去除单行注释
processedContent = processedContent.replace(/\/\/.*$/gm, '');
// 去除多行注释(优化版本,避免过度匹配)
processedContent = processedContent.replace(/\/\*[\s\S]*?\*\//g, '');
// 然后再使用terser进行压缩
const compressedContent = compressJs(processedContent, filePath);
// 检测压缩后是否仍包含console语句
const hasConsoleAfterCompression = /console\.(log|warn|error|info|debug|trace|table|dir|time|timeEnd)/i.test(compressedContent);
if (hasConsoleAfterCompression) {
filesWithConsoleAfterCompression.push({ sourcePath: filePath, targetPath: filePath });
}
// 确保即使内容变化很小也要写入文件
const finalContent = compressedContent;
// 写入文件(无论是否有变化)
fs.writeFileSync(filePath, finalContent, { encoding: 'utf8' });
console.log(`Processed: ${filePath}`);
// 更新统计信息
const originalSize = Buffer.from(content).length;
const compressedSize = Buffer.from(finalContent).length;
const sizeDiff = originalSize - compressedSize;
const compressionRatio = originalSize > 0 ? (sizeDiff / originalSize * 100).toFixed(2) : '0.00';
totalJsOriginalSize += originalSize;
totalJsCompressedSize += compressedSize;
jsFileCount++;
jsSizeDetails.push({
path: filePath,
originalSize,
compressedSize,
sizeDiff,
compressionRatio
});
console.log(` Original: ${originalSize} bytes`);
console.log(` Compressed: ${compressedSize} bytes`);
console.log(` Saved: ${sizeDiff} bytes (-${compressionRatio}%)`);
} catch (error) {
console.error(`Error processing file ${filePath}:`, error.message);
}
}
});
}
// 递归复制目录并压缩文件wxml, js, css, json // 递归复制目录并压缩文件wxml, js, css, json
function copyAndCompressDir(sourceDir, targetDir) { function copyAndCompressDir(sourceDir, targetDir) {
// 创建目标目录 // 创建目标目录
@@ -306,20 +442,31 @@ function main() {
const args = process.argv.slice(2); const args = process.argv.slice(2);
const keepDist = args.includes('--keep-dist') || args.includes('-k'); const keepDist = args.includes('--keep-dist') || args.includes('-k');
const noZip = args.includes('--no-zip') || args.includes('-n'); const noZip = args.includes('--no-zip') || args.includes('-n');
const onlyProcessDist = args.includes('--only-process-dist') || args.includes('-p'); // 只处理dist目录下已有的JS文件
// 清理dist目录如果存在且不保留 // 清理dist目录如果存在且不保留
if (fs.existsSync(distDir)) { if (fs.existsSync(distDir)) {
if (!keepDist && !onlyProcessDist) {
cleanDistDir(distDir); cleanDistDir(distDir);
}
} else { } else {
// 创建dist目录 // 创建dist目录
fs.mkdirSync(distDir, { recursive: true }); fs.mkdirSync(distDir, { recursive: true });
console.log('Created dist directory'); console.log('Created dist directory');
} }
// 根据参数决定执行哪种流程
if (onlyProcessDist) {
// 只处理dist目录下已有的JS文件
console.log('Start processing existing JS files in dist directory...');
processExistingJsFiles(distDir);
console.log('Processing existing JS files completed!');
} else {
// 复制并压缩文件到dist目录 // 复制并压缩文件到dist目录
console.log('Start copying and compressing files...'); console.log('Start copying and compressing files...');
copyAndCompressDir(rootDir, distDir); copyAndCompressDir(rootDir, distDir);
console.log('Files copied and compressed successfully!'); console.log('Files copied and compressed successfully!');
}
// 输出JS文件压缩统计结果 // 输出JS文件压缩统计结果
outputJsCompressionStats(); outputJsCompressionStats();
@@ -337,8 +484,8 @@ function main() {
console.log('Skipping zip archive creation (--no-zip specified)'); console.log('Skipping zip archive creation (--no-zip specified)');
} }
// 清理dist目录如果不保留 // 清理dist目录如果不保留且不是只处理dist目录
if (!keepDist) { if (!keepDist && !onlyProcessDist) {
cleanDistDir(distDir); cleanDistDir(distDir);
} }
@@ -396,5 +543,6 @@ if (process.argv.includes('--help') || process.argv.includes('-h')) {
console.log('Options:'); console.log('Options:');
console.log(' --keep-dist, -k Keep existing dist directory contents'); console.log(' --keep-dist, -k Keep existing dist directory contents');
console.log(' --no-zip, -n Skip zip archive creation'); console.log(' --no-zip, -n Skip zip archive creation');
console.log(' --only-process-dist, -p Only process existing JS files in dist directory');
console.log(' --help, -h Show this help message'); console.log(' --help, -h Show this help message');
} }