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

395 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');
// 直接引用本地安装的 mini-optimizer 模块
const Optimizer = require('mini-optimizer').default;
// 导入 mini-optimizer 配置文件
const optimizerConfig = require('./mini-optimizer.config.js');
// 定义项目根目录
const rootDir = __dirname;
// 定义输出目录
const distDir = path.join(rootDir, 'dist');
// 定义要排除的目录和文件
const excludeDirs = ['node_modules', '.git', 'dist', '.vscode'];
const excludeFiles = ['.gitignore', 'package.json', 'package-lock.json', 'yarn.lock', 'release.js', 'mini-optimizer.config.js', 'babel.config.js', 'README.md'];
// 获取当前日期用于生成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压缩函数 - 采用更安全的压缩策略,接近微信小程序开发工具的压缩方式
function compressJs(content) {
// 移除单行注释
content = content.replace(/\/\/.*$/gm, '');
// 移除多行注释
content = content.replace(/\/\*[\s\S]*?\*\//g, '');
// 移除行尾多余的空白字符
content = content.replace(/\s+$/gm, '');
// 移除多余的空行,只保留必要的换行
content = content.replace(/\n{2,}/g, '\n');
// 保存所有require语句避免压缩时破坏模块路径
const requireStatements = [];
let requireIndex = 0;
content = content.replace(/require\s*\([^)]+\)/g, (match) => {
const placeholder = `__REQUIRE_PLACEHOLDER_${requireIndex}__`;
requireStatements.push({ placeholder, content: match });
requireIndex++;
return placeholder;
});
// 在适当的位置添加分号,避免语法错误
// 只在特定情况下添加分号
// 1. 处理return、break、continue、throw等语句
content = content.replace(/(return|break|continue|throw)\s*(.*?)\n/g, '$1 $2;\n');
// 2. 处理变量声明和赋值(简单情况)
content = content.replace(/([a-zA-Z_$][a-zA-Z0-9_$]*\s*=\s*[^;\n]+)\n/g, '$1;\n');
// 3. 处理函数调用
content = content.replace(/([a-zA-Z_$][a-zA-Z0-9_$]*\s*\([^;\n]+\))\n/g, '$1;\n');
// 移除语句之间多余的空白字符,但保留必要的空格
content = content.replace(/\s*\{\s*/g, '{');
content = content.replace(/\s*\}\s*/g, '}');
content = content.replace(/\s*;\s*/g, ';');
content = content.replace(/\s*,\s*/g, ',');
content = content.replace(/\s*=\s*/g, '=');
content = content.replace(/\s*\+\s*/g, '+');
content = content.replace(/\s*-\s*/g, '-');
content = content.replace(/\s*\*\s*/g, '*');
content = content.replace(/\s*\/\s*/g, '/');
content = content.replace(/\s*\[\s*/g, '[');
content = content.replace(/\s*\]\s*/g, ']');
// 移除多余的分号
content = content.replace(/;;+/g, ';');
// 移除多余的空白字符(连续的空格只保留一个)
content = content.replace(/\s+/g, ' ');
// 恢复之前保存的require语句
requireStatements.forEach(({ placeholder, content: requireContent }) => {
content = content.replace(placeholder, requireContent + ';');
});
// 移除文件开头和结尾的分号
content = content.replace(/^;|;$/g, '');
// 移除所有多余的空格
content = content.replace(/\s+/g, '');
// 确保最后一个require语句也有分号
content = content.replace(/require\([^)]+\)$/, '$&;');
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;
}
}
// 递归复制目录(只复制文件,不进行压缩)
function copyDir(sourceDir, targetDir) {
// 创建目标目录
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir, { recursive: true });
}
const files = fs.readdirSync(sourceDir);
for (const file of files) {
const sourcePath = path.join(sourceDir, file);
const targetPath = path.join(targetDir, file);
const stats = fs.statSync(sourcePath);
// 跳过排除的目录和文件
if (excludeDirs.includes(file) || excludeFiles.includes(file)) {
continue;
}
if (stats.isDirectory()) {
// 递归处理子目录
copyDir(sourcePath, targetPath);
} else {
// 直接复制文件
fs.copyFileSync(sourcePath, targetPath);
console.log(`Copied: ${sourcePath}`);
}
}
}
// 使用 mini-optimizer API 对 dist 目录进行统一压缩
async function compressDistDir(targetDir) {
console.log('Start compressing files in dist directory using mini-optimizer API...');
// 创建优化器实例,使用配置文件中的极限压缩选项
const optimizer = new Optimizer(targetDir, 'wx', optimizerConfig);
// 是否启用兼容模式 - 开启后,会使用自定义压缩函数处理压缩失败的文件
const enableCompatMode = false;
// 记录哪些成功被压缩的文件
const compressedFiles = [];
const unCompressedFiles = [];
// 递归遍历 dist 目录,压缩所有需要的文件类型
async function compressDir(dir) {
const files = fs.readdirSync(dir);
for (const file of files) {
const filePath = path.join(dir, file);
const stats = fs.statSync(filePath);
if (stats.isDirectory()) {
// 递归处理子目录
await compressDir(filePath);
} else {
const extname = path.extname(file);
try {
// 读取文件内容
const content = fs.readFileSync(filePath, { encoding: 'utf8' });
let compressedContent;
// 使用 mini-optimizer 压缩不同类型的文件
if (extname === '.wxml' || extname === '.xml') {
// 压缩xml和wxml文件 - 禁用属性值压缩以避免Babel解析错误
try {
compressedContent = optimizer.optimize_xml(content, { minifyAttributes: false });
compressedFiles.push(filePath);
} catch (error) {
if (!enableCompatMode) {
throw error;
}
compressedContent = compressWxml(content);
compressedFiles.push(filePath);
}
} else if (extname === '.js') {
// 压缩js文件
try {
compressedContent = optimizer.optimize_js(content);
compressedFiles.push(filePath);
} catch (error) {
if (!enableCompatMode) {
throw error;
}
compressedContent = compressJs(content);
compressedFiles.push(filePath);
}
} else if (extname === '.css' || extname === '.wxss') {
// 压缩css和wxss文件
try {
compressedContent = await optimizer.optimize_css(content);
compressedFiles.push(filePath);
} catch (error) {
if (!enableCompatMode) {
throw error;
}
compressedContent = compressCss(content);
compressedFiles.push(filePath);
}
} else if (extname === '.json') {
// 压缩json文件
try {
compressedContent = optimizer.optimize_json(content);
compressedFiles.push(filePath);
} catch (error) {
if (!enableCompatMode) {
throw error;
}
compressedContent = compressJson(content);
compressedFiles.push(filePath);
}
} else if (extname === '.xs') {
// 压缩xs文件
compressedContent = optimizer.optimize_xs(content);
compressedFiles.push(filePath);
} else {
// 跳过不需要压缩的文件
continue;
}
// 写入压缩后的内容
fs.writeFileSync(filePath, compressedContent, { encoding: 'utf8' });
console.log(`Compressed: ${filePath}`);
} catch (error) {
console.error(`Error compressing file ${filePath}:`, error.message);
unCompressedFiles.push(filePath);
// 发生错误时,保留原始文件
console.log(`Kept original file: ${filePath}`);
}
}
}
}
// 开始压缩整个dist目录
await compressDir(targetDir);
// 打印压缩成功的文件列表
console.log('Compressed files:', compressedFiles);
// 打印未压缩的文件列表
console.log('Uncompressed files:', unCompressedFiles);
console.log('Files compressed successfully using mini-optimizer API!');
}
// 使用系统命令创建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)');
}
}
// 主函数
async function main() {
try {
// 解析命令行参数
const args = process.argv.slice(2);
const keepDist = args.includes('--keep-dist') || args.includes('-k');
// 清理dist目录如果存在且不保留
if (fs.existsSync(distDir)) {
cleanDistDir(distDir);
} else {
// 创建dist目录
fs.mkdirSync(distDir, { recursive: true });
console.log('Created dist directory');
}
// 第一步复制所有文件到dist目录不压缩
console.log('Start copying files...');
copyDir(rootDir, distDir);
console.log('Files copied successfully!');
// 第二步使用mini-optimizer对dist目录进行统一压缩
console.log('Start compressing files in dist directory...');
await compressDistDir(distDir);
console.log('Files compressed successfully!');
// 生成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压缩包
console.log('Creating zip archive...');
createZipArchive(distDir, zipPath);
// 清理dist目录如果不保留
if (!keepDist) {
cleanDistDir(distDir);
}
console.log('\nAll tasks completed successfully!');
console.log(`Dist directory: ${distDir}`);
console.log(`Zip file: ${zipPath}`);
} 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(' --help, -h Show this help message');
}