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 底部(紧靠 </body> 前)
|
html = html.replace('</body>', `<script src="./pure-chunk-map.js"></script></body>`);
|
|
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('🚀 全部完成!');
|