H5原生项目的压缩、混淆(html-minifier 、javascript-obfuscator)

为了防止项目被别人轻松抄袭,所以对代码的压缩、混淆还是很有必要的


一、常见插件介绍

  1. js压缩:terser、uglifyjs
  2. js混淆:javascript-obfuscator
  3. css压缩:postcss、clean-css
  4. html、css、js压缩:html-minifier

这里我们使用 html-minifier(压缩html、css)javascript-obfuscator(js混淆)

二、开始吧

  1. 运行环境:node(v14.17.6)
  2. 安装依赖:npm i html-minifier javascript-obfuscator
  3. 运行:
    1. 根据自己的项目修改根目录修改不进行处理的文件(夹)、修改原样输出的文件(如图片、字体文件、min文件)
    2. node main.js
  4. main.js 代码如下:
const fs = require('fs');
const path = require('path');
const minify = require('html-minifier').minify;
const JO = require("javascript-obfuscator");

// 项目根目录
let sRootPath = 'ui'

fnTravel(sRootPath, fnCompressHtmlCss)
console.log("文件处理结束")

/**
 * 遍历文件
 * @params {*} dir 文件夹
 * @params {*} callback 回调函数
 */
function fnTravel(dir, callback) {
    // 同步读取指定目录的内容
    let aFiles = fs.readdirSync(dir, 'utf8'), aFilterPath = ['.git', '.idea', 'html', 'README'];
    aFiles.forEach((file) => {
        // 获得完整路径
        let pathname = path.join(dir, file)
        // 判断是否处理
        let bIsHandle = aFilterPath.some(item => pathname.includes(item));
        if(!bIsHandle) {
            // 同步获取详细信息
            let stats = fs.statSync(pathname);
            if (stats.isDirectory()) {
                // 文件夹
                fnTravel(pathname, callback)
            } else {
                // 文件
                try {
                    if (pathname.endsWith('js')) {
                        // js 文件
                        fnObfuscatorJs(pathname)
                    } else {
                        // 其他文件
                        callback(pathname)
                    }
                } catch (e) {
                    console.error("压缩失败:" + pathname);
                    console.error(e);
                }
            }
        }
    })
}

/**
 * 压缩 html、css 文件方法
 * @params {*} path 文件路径
 */
function fnCompressHtmlCss(path) {
    let sTargetPath = path.replace('ui', 'dist'),
        sCompressData = null, data = null;
    if (!path.includes('img') && !path.includes('fonts')) {
        // 获取文件内容
        data = fs.readFileSync(path, 'utf8')
        if(!path.endsWith('.min.css')) {
            // 压缩后的文件内容
            sCompressData = minify(data, {
                collapseWhitespace: true, // 删除html里的空格 达到html的压缩
                removeAttributeQuotes: true, // 尽可能删除html标签里的双引号 达到html的压缩
                removeComments: true, //删除html中的注释
                removeCommentsFromCDATA: true, //从脚本和样式删除的注释
                minifyCSS: true, // 压缩css
            })
        }
    }
    let result = sCompressData ? sCompressData : data;
    // 将数据同步写入文件
    fnWriteFileRecursive(path, sTargetPath, result, (err) => {
        if (err) console.error(err);
        console.log('compress--[' + path + ']--success');
    })
}

/**
 * 压缩、混淆js方法
 * @params {*} path 文件路径
 */
function fnObfuscatorJs(path) {
    let sTargetPath = path.replace('ui', 'dist'),
        sObfuscateCode = null;
    // 获取文件内容
    let data = fs.readFileSync(path, 'utf8')
    if (!sTargetPath.endsWith('.min.js')) {
        // 进行混淆
        sObfuscateCode = JO.obfuscate(data, {
            compact: true, // 压缩
            controlFlowFlattening: true,
            controlFlowFlatteningThreshold: 1,
            numbersToExpressions: true,
            simplify: true,
            shuffleStringArray: true,
            splitStrings: true,
            stringArrayThreshold: 1,
        });
    }
    // getObfuscatedCode() 返回混淆后的代码字符串,调用 toString 方法也会返回混淆代码
    let sResultCode = sObfuscateCode ? sObfuscateCode.getObfuscatedCode() : data;
    fnWriteFileRecursive(path, sTargetPath, sResultCode, (err) => {
        if (err) console.error(err);
        console.log('compress--[' + path + ']--success');
    })
}

/**
 * 创建目录并写入文件
 * @params {*} sFromPath 来源路径
 * @params {*} sTargetPath 目标路径
 * @params {*} buffer 文件内容
 * @params {*} callback 回调函数
 * */
function fnWriteFileRecursive(sFromPath, sTargetPath, buffer, callback) {
    let lastPath = sTargetPath.substring(0, sTargetPath.lastIndexOf("\\"));
    // 创建目录
    fs.mkdir(lastPath, {
        recursive: true
    }, (err) => {
        if (err) return callback(err);
        if (sTargetPath.includes('img') || sTargetPath.includes('fonts')) {
            // 处理图片、字体文件
            let readStream = fs.createReadStream(sFromPath); // 逐块读取文件
            let writeStream = fs.createWriteStream(sTargetPath); // 对指定文件创建一个“可写数据流”
            readStream.pipe(writeStream); // 将文件数据流导向 writeStream 对象
        } else {
            // 处理html、css、js文件
            fs.writeFileSync(sTargetPath, buffer, function (err) {
                if (err) return callback(err);
            });
        }
    });
}

知识点扩展

  1. 在写入文件之前,首先使用 mkdir(第一个参数是目录路径,第二个是权限,第三个是回调函数)方法新建目录,防止因为路径不存在而报错
  2. node.js 内置的 fs模块是文件系统模块,负责读写文件,fs模块还提供了异步和同步的方法
    1. 使用异步方法执行IO(输入/输出)操作时,JS代码不需要等待,在传入回调函数后,会继续执行后续代码
    2. 使用同步方法执行IO时,则需要等待函数返回
  3. node.js 中readFile和createReadStream函数的区别:
    1. readFile函数异步读取文件内容,并存储在内存中,然后才能使用;优点是符合直觉,流程自然。缺点是如果遇到大文件,要花费很长时间,才能进入数据处理的步骤
    2. createReadStream使用一个可读的流,逐块读取文件,而不是全部存储在内存中,同时每当系统读入一小块数据时,就会触发一个事件,只要监听这个事件(data)就能掌握执行进度,做出相应的数据处理,这样一来 createReadStream 使用更少的内存和更快的速度来优化文件的读取操作。

参考文章

https://segmentfault.com/a/1190000040502426
https://blog.csdn.net/qq_37667074/article/details/108356269
https://blog.csdn.net/foupwang/article/details/103306332
https://blog.csdn.net/Liheishuai/article/details/124625069

压缩HTML: 可以使用多种工具来压缩HTML,例如HTMLMinifier或UglifyJS等。这些工具可以删除不必要的空格、注释和其他字符,从而减小文件大小。以下是使用HTMLMinifier进行HTML压缩的示例代码: ```javascript const html = '<html><head><title>Hello World</title></head><body><p>Hello, world!</p></body></html>'; const minifiedHtml = htmlMinifier.minify(html, { collapseWhitespace: true, removeComments: true, minifyCSS: true, minifyJS: true }); ``` 图片上传: 可以使用HTML5的File API来实现图片上传。以下是一个基本的示例: ```html <input type="file" id="upload-input"> <script> const input = document.getElementById('upload-input'); input.addEventListener('change', (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (event) => { const imageData = event.target.result; // 图片数据 // 将图片数据上传到服务器 }; reader.readAsDataURL(file); }); </script> ``` JS Canvas 修改图片尺寸和压缩大小: 可以使用canvas的API来修改图片的尺寸和压缩图片大小。以下是一个基本的示例: ```html <input type="file" id="upload-input"> <canvas id="canvas"></canvas> <script> const input = document.getElementById('upload-input'); const canvas = document.getElementById('canvas'); const context = canvas.getContext('2d'); input.addEventListener('change', (e) => { const file = e.target.files[0]; const reader = new FileReader(); reader.onload = (event) => { const img = new Image(); img.onload = () => { // 计算缩小后的尺寸 const maxWidth = 300; const maxHeight = 300; let width = img.width; let height = img.height; if (width > height) { if (width > maxWidth) { height *= maxWidth / width; width = maxWidth; } } else { if (height > maxHeight) { width *= maxHeight / height; height = maxHeight; } } canvas.width = width; canvas.height = height; // 绘制缩小后的图片 context.drawImage(img, 0, 0, width, height); // 压缩图片 const quality = 0.7; const imageData = canvas.toDataURL('image/jpeg', quality); // 将图片数据上传到服务器 }; img.src = event.target.result; }; reader.readAsDataURL(file); }); </script> ``` 以上是一个基本的实现,具体的实现方式可以根据需求进行修改。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忍冬 ⁡⁡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值