const fs = require('fs'); const path = require('path'); const obfuscator = require('javascript-obfuscator'); const distDir = path.resolve(__dirname, 'unpackage/dist/build/web'); const jsDir = path.join(distDir, 'static/js'); const htmlPath = path.join(distDir, 'index.html'); if (!fs.existsSync(jsDir)) { console.error('❌ 找不到 static/js 目录,打包还没生成?'); process.exit(1); } // 读取所有 js 文件 const files = fs.readdirSync(jsDir).filter(f => f.endsWith('.js')); // 辅助:提取 webpackChunkName function extractChunkName(content) { // webpackChunkName 通常写成 /* webpackChunkName: "xxx" */ const match = content.match(/webpackChunkName:\s*["']([^"']+)["']/); if (match) return match[1]; // 如果没有注释,尝试提取其他线索,或者返回空 return null; } // 生成映射:逻辑 chunk 名 → 纯 hash 文件名 const map = {}; files.forEach(file => { const filePath = path.join(jsDir, file); const content = fs.readFileSync(filePath, 'utf-8'); const chunkName = extractChunkName(content); if (chunkName) { map[`${chunkName}.js`] = file; } else { // 入口文件(比如index.js)可能没 webpackChunkName 注释,尝试用文件名(hash.js)临时映射 // 或你可以手动补充 } }); // 入口文件手动添加,比如 index.js 映射到某个文件 // 你可以根据实际情况手动确认替换 // 例如找 index 文件内容包含特定关键词,或者人工指定: if (!map['index.js']) { // 尝试找内容包含 "new Vue" 的文件作为入口 for (const file of files) { const content = fs.readFileSync(path.join(jsDir, file), 'utf-8'); if (content.includes('new Vue') || content.includes('createApp')) { map['index.js'] = file; break; } } } if (!map['index.js']) { console.warn('⚠️ 找不到入口 index.js 对应的纯 hash 文件,请确认入口文件'); } // 写入映射文件 const mapPath = path.join(distDir, 'pure-chunk-map.json'); fs.writeFileSync(mapPath, JSON.stringify(map, null, 2), 'utf-8'); console.log('✅ 生成纯 hash 映射:pure-chunk-map.json'); // 生成映射加载脚本,注入页面使用 const mapScript = ` window.__PURE_CHUNK_MAP__ = ${JSON.stringify(map, null, 2)}; (function() { const originalChunkFilename = __webpack_chunk_load__; // 覆写 webpack chunk 加载函数 __webpack_chunk_load__ = function(chunkId) { const pureName = window.__PURE_CHUNK_MAP__[chunkId + '.js']; if (!pureName) { console.warn('[pure-chunk-map] 未找到映射', chunkId); return originalChunkFilename(chunkId); } const url = 'static/js/' + pureName; return originalChunkFilename(url); }; })(); `; // 写入映射脚本文件 const mapScriptPath = path.join(distDir, 'pure-chunk-map.js'); fs.writeFileSync(mapScriptPath, mapScript, 'utf-8'); console.log('✅ 生成映射加载脚本:pure-chunk-map.js'); // 替换 index.html 中入口 chunk,注入映射脚本 if (!fs.existsSync(htmlPath)) { console.warn('⚠️ 找不到 index.html,可能打包失败或路径不对'); process.exit(1); } let html = fs.readFileSync(htmlPath, 'utf-8'); // 替换入口 chunk 文件名,比如 index.js 替换为纯 hash 文件名 Object.keys(map).forEach(logicName => { const pureName = map[logicName]; const regex = new RegExp(logicName.replace('.', '\\.'), 'g'); html = html.replace(regex, pureName); }); // 注入映射加载脚本到 html 底部(紧靠 前) html = html.replace('', ``); fs.writeFileSync(htmlPath, html, 'utf-8'); console.log('🎉 替换 index.html 入口 chunk 并注入映射加载脚本'); // 混淆所有 .js files.forEach(file => { const filePath = path.join(jsDir, file); const code = fs.readFileSync(filePath, 'utf-8'); const obfuscated = obfuscator.obfuscate(code, { compact: true, controlFlowFlattening: true, deadCodeInjection: true, selfDefending: true, }).getObfuscatedCode(); fs.writeFileSync(filePath, obfuscated, 'utf-8'); console.log(`🔒 已混淆 ${file}`); }); console.log('🚀 全部完成!');