chore(release.js): 当前发布程序
This commit is contained in:
178
release.js
178
release.js
@@ -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)) {
|
||||||
cleanDistDir(distDir);
|
if (!keepDist && !onlyProcessDist) {
|
||||||
|
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');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制并压缩文件到dist目录
|
// 根据参数决定执行哪种流程
|
||||||
console.log('Start copying and compressing files...');
|
if (onlyProcessDist) {
|
||||||
copyAndCompressDir(rootDir, distDir);
|
// 只处理dist目录下已有的JS文件
|
||||||
console.log('Files copied and compressed successfully!');
|
console.log('Start processing existing JS files in dist directory...');
|
||||||
|
processExistingJsFiles(distDir);
|
||||||
|
console.log('Processing existing JS files completed!');
|
||||||
|
} else {
|
||||||
|
// 复制并压缩文件到dist目录
|
||||||
|
console.log('Start copying and compressing files...');
|
||||||
|
copyAndCompressDir(rootDir, distDir);
|
||||||
|
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');
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user