使用Egret插件压缩代码包体积,减少请求数量的实战教程
在白鹭引擎发布了5.2.7版本中新增加了命令行,增加自动合图插件TextureMergerPlugin功能。今天,我们以一个EUI案例来展示自动合图插件的具体使用方法和注意事项。
此外,我们在本文还融入了UglifyPlugin、ResSplitPlugin、ZipPlugin等插件使用方法。开发者利用上述4款插件,将实现代码包体积更小、更好管理的目标。
目录:
使用UglifyPlugin将代码混淆压缩
使用ResSplitPlugin把部分资源分离出去
使用ZipPlugin把文件压缩成zip格式
使用TextureMergerPlugin将纹理合并,且用ConvertResConfigFilePlugin修改res.json配置文件
项目初始化
- 把index.html中的data-scale-mode改成fixedWidth
- 打开EgretLauncher,将本项目发布成微信小游戏
- 打开微信开发者工具
使用UglifyPlugin压缩代码
在微信开发者工具可以看到,js文件夹中5个库文件和一个main.js。
现在需求是是要把库文件压缩到一个文件lib.min.js中。
回到EgretWing,编辑sctipts下的config.wxgame.ts:
//***其他代码***
//
if (command == 'build') {
    return {
        outputDir,
        commands: [
            // 清理js,resource文件夹
            new CleanPlugin({ matchers: ["js", "resource"] }),
            new CompilePlugin({ libraryType: "debug", defines: { DEBUG: true, RELEASE: false } }),
            new ExmlPlugin('commonjs'), // 非 EUI 项目关闭此设置
            new WxgamePlugin(),
            //  压缩插件
            new UglifyPlugin([
                {
                    // 需要被压缩的文件
                    sources: [
                        "libs/modules/egret/egret.js",
                        "libs/modules/eui/eui.js",
                        "libs/modules/assetsmanager/assetsmanager.js",
                        "libs/modules/tween/tween.js",
                    ],
                    // 压缩后的文件
                    target: "lib.min.js"
                }
            ]),
            new ManifestPlugin({ output: 'manifest.js' })
        ]
    }
    }
//
// ***其他代码***保存后在终端执行:
egret build可以在微信开发者工具看到发布后的代码,js文件夹内的库文件已经被压缩到lib.min.js。
但是报错,找不到eui,这是因为自动生成的manifest.js里面对js的引用顺序出错,需要优先引用lib.min.js
打开根目录下的manifest.js, 修改一下引用顺序。
require("js/lib.min.js")
require("js/main.js")
require("js/default.thm.js")每次编译的时候manifest.js都会被重新生成,所以我们使用一个自定义脚本来修改他们的顺序
打开 scripts下的myPlugin.ts :
/**
 * 示例自定义插件,您可以查阅 http://developer.egret.com/cn/2d/projectConfig/cmdExtensionPluginin/
 * 了解如何开发一个自定义插件
 */
export class CustomPlugin implements plugins.Command {
    private buffer
    constructor() {
    }
    async onFile(file: plugins.File) {
        // 保存manifest.js文件的内容
        if(file.basename.indexOf('manifest.js') > -1) {
            this.buffer = file.contents
        }
        return file;
    }
    async onFinish(commandContext: plugins.CommandContext) {
        // 把'lib.min.js'移到第一位
        if (this.buffer) {
            let contents: string = this.buffer.toString()
            let arr = contents.split('\n')
            let lib = null
            arr.forEach((item, index) => {
                if (item.indexOf('lib.min.js') > -1) {
                    lib = item
                    arr.splice(index, 1)
                }
            })
            if (lib != null) {
                arr.unshift(lib)
            }
            let newCont = arr.join('\n')
            commandContext.createFile('manifest.js', new Buffer(newCont))
        }
    }
}这个文件就是用来自定义插件的,在config.wxgame.ts中已经默认引用,所以只需要调用即可,注意调用顺序
new ManifestPlugin({ output: 'manifest.js' }),
// 在manifest.js生成之后调用
new CustomPlugin()使用ResSplitPlugin分离资源文件
因为微信对代码包的大小是有限制的,总大小不能超过4M(使用分包功能可以提升到8M),所以我们需要通过ResSplitPlugin把某些游戏资源文件分离出去,将游戏资源放置在一个外部CDN服务器上,需要的时候动态加载即可。
编辑config.wxgame.ts:
// ***其他代码***
//
new ResSplitPlugin({
    verbose: false, matchers:
    [
        // from 使用glob表达式来匹配文件,  projectName就是项目的名字
        { from: "resource/art/about/**.**", to: `${projectName}_wxgame_remote` },
        { from: "resource/art/heros_goods/**.**", to: `${projectName}_wxgame_remote` }
    ]
})
// ***其他代码***保存后在终端执行:
egret build微信开发者工具中resource > art 下的about和heros_goods已经不在了。
被分离出去的在项目根目录中 egret-eui-demo_wxgame_remote 文件夹内。
使用ZipPlugin把文件压缩成zip格式
为了减少加载次数和传输量,我们可以把文件压缩成zip格式,使用的时候可以使用第三方库JSZip来读取使用zip文件。
使用ZipPlugin插件之前,需要安装cross-zip 和 cross-zip-cli , 在终端中输入:
//全局安装
npm install cross-zip -g
npm install cross-zip-cli -g安装完成之后,在config.wxgame.ts添加代码:
new ZipPlugin({
    mergeSelector: p => {
        // 如果文件是assets/路径下的, 压缩到assets.zip
        if (p.indexOf("assets/") >= 0) {
            return "assets.zip"
        }
    }
})项目中其实assets里面的资源都是没有用到的,这里我们用它来演示压缩插件的使用。
保存后在终端执行
egret build执行之后可以在微信开发者工具看到,resource目录下原来的assets文件夹已经被压缩成了assets.zip。
使用TextureMergerPlugin,ConvertResConfigFilePlugin合并纹理集
项目中使用的图片资源都是单独的png文件,在加载的时候每张图片都会单独请求。我们可以通过合并纹理集的方式把这些图片合成一张图,以减少请求数量。
使用插件之前,我们需要有纹理集的配置文件tmpropject, 可以用两种方式生成:
- 使用TextureMerger工具
- 执行脚本生成
这里使用第二种方法,使用脚本autoMerger.js:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var fs = require("fs");
var path = require("path");
var resjsons = ["resource/default.res.json"]; //要扫描的res.json文件
var targetDir = "resource/TextureMerger"; //输出目录
var pathNor = path.relative(targetDir, "resource"); //返回一个相对路径
var tempindex = 0;
//创建输出文件夹
if (resjsons.length > 0) {
    if (!fs.existsSync(targetDir)) {
        // var paths = path.normalize(targetDir).split("\\");   //windows 下使用
        var paths = path.normalize(targetDir).split("\/");   //mac linux 下使用
        var target = ".";
        for (var _i = 0, paths_1 = paths; _i < paths_1.length; _i++) {
            var p = paths_1[_i];
            // target += ("\\" + p);  // windows 下使用
            target += ("\/" + p);  // mac linux 下使用
            if (!fs.existsSync(target))
                // 根据路径创建文件夹
                fs.mkdirSync(target);
        }
    }
}
var _loop_1 = function (resJson) {
    // 判断是否是res.json文件
    if (fs.existsSync(resJson) && resJson.indexOf("res.json") > -1) {
        var defaultJson = fs.readFileSync(resJson, "utf-8");
        // 解析res.json文件内容
        var defaultObject = JSON.parse(defaultJson);
        var groups = defaultObject.groups; //组
        var resources = defaultObject.resources; //资源
        var resourcesHash_1 = {}; // 用来存放resources的资源信息
        // 遍历resources
        for (var _i = 0, resources_1 = resources; _i < resources_1.length; _i++) {
            var resource = resources_1[_i];
            resourcesHash_1[resource.name] = resource.url;
        }
        // 遍历groups
        for (var _a = 0, groups_1 = groups; _a < groups_1.length; _a++) {
            var group = groups_1[_a];
            var tmproject = {}; //用来存放tmproject文件的信息
            // tmproject文件配置
            tmproject["options"] = {
                "layoutMath": "2",
                "sizeMode": "2n",
                "useExtension": 1,
                "layoutGap": 1,
                "extend": 0
            };
            // projectName
            tmproject["projectName"] = group.name + "_" + tempindex;
            // 版本
            tmproject["version"] = 5;
            tempindex++;
            // 获取res.json分组的keys, 并分割成数组
            var oldkeys = group.keys.split(",");
            var oldkeysHash = {};
            // 遍历oldkeys
            for (var _b = 0, oldkeys_1 = oldkeys; _b < oldkeys_1.length; _b++) {
                var key = oldkeys_1[_b];
                // 保存到oldkeysHash对象中
                oldkeysHash[key] = true;
            }
            var newKeys = [];
            // 遍历oldkeys
            for (var _c = 0, oldkeys_2 = oldkeys; _c < oldkeys_2.length; _c++) {
                var key = oldkeys_2[_c];
                if (key.indexOf("json") == -1) {
                    if (!oldkeysHash[key.replace("png", "json")]) { //粒子和龙骨对应的图集不合图
                        if (!oldkeysHash[key.replace("png", "fnt")]) //位图字体
                            newKeys.push(key);
                    }
                    else if (key.indexOf("jpg") > -1) {
                        newKeys.push(key);
                    }
                }
            }
            oldkeysHash = {};
            oldkeys = [];
            // files路径
            var urls = newKeys.map(function (key) {
                return path.join(pathNor, resourcesHash_1[key]);
            });
            tmproject["files"] = urls;
            // 根据tmproject写入文件
            if (urls.length > 0) {
                fs.writeFileSync(path.join(targetDir, tmproject["projectName"] + ".tmproject"), JSON.stringify(tmproject));
            }
            tmproject = {};
        }
    }
};
//根据数组开始扫描
for (var _a = 0, resjsons_1 = resjsons; _a < resjsons_1.length; _a++) {
    var resJson = resjsons_1[_a];
    _loop_1(resJson);
}把这个脚本放在scripts文件夹内,这个脚本是根据项目的default.res.json文件的内容来生成tmpropject文件
在终端中执行:
node scripts/autoMerger.js执行成功之后可以在resource文件夹中看到多出了一个TextureMerger文件夹,里面就是根据default.res.json分组生成的tmpropject文件。
现在只需要执行TextureMergerPlugin插件就可以自动合并,这里需要注意TextureMergerPlugin依赖 TextureMerger 1.7 以上的版本,如果不符合请自行安装,并且在运行时TextureMerger需要处于关闭状态。
new TextureMergerPlugin({textureMergerRoot:[ 'resource']})保存后在终端执行:
egret build执行完成后,在微信开发者工具可以看到,resource > TextureMerger 内新增了三个png文件,就是合并之后的纹理集。游戏运行的时候只需要加载这三个纹理集就可以,无需加载那些单独的png文件但是需要去res.json里面配置,把单独的资源引用都删除,加上纹理集的引用。
这些操作当然不需要手动去完成,现在只需要使用ConvertResConfigFilePlugin插件就可以实现这个功能。
编辑config.wxgame.ts:
new TextureMergerPlugin(),
new ConvertResConfigFilePlugin({
    resourceConfigFiles: [{ filename: "resource/default.res.json", root: "resource/" }],
    nameSelector: (p) => {
         return path.basename(p).split(".").join("_")
    },
    TM_Verbose: true
})保存后在终端执行:
egret build在微信开发者工具中,打开调试器,在network面板可以看到加载的纹理集。
这里有个注意事项,在游戏中点击英雄按钮,切换到英雄场景时,会发现列表里面的图片加载不出来。
在network面板可以看到加载请求是单独的png文件,而不是纹理集。
这是因为列表中的图片地址是直接使用url。
// 原始数组
let dataArr:any[] = [
    {image: 'resource/art/heros_goods/heros01.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},
    {image: 'resource/art/heros_goods/heros02.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},
    {image: 'resource/art/heros_goods/heros03.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: true},
    {image: 'resource/art/heros_goods/heros04.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},
    {image: 'resource/art/heros_goods/heros05.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},
    {image: 'resource/art/heros_goods/heros06.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false},
    {image: 'resource/art/heros_goods/heros07.png', name: '亚特伍德', value: '评价: 很特么厉害, 为所欲为', isSelected: false}
]
// 转成eui数据
let euiArr:eui.ArrayCollection = new eui.ArrayCollection(dataArr)
// 把list_hero数据源设置成euiArr
this.list_hero.dataProvider = euiArr
// 设置list_hero的项呈视器 (这里直接写类名,而不是写实例)
this.list_hero.itemRenderer = heroList_item这种引用方式的图片,需要开发者手动在代码中修改,将图片地址修改成纹理集中的图片。
结语
本文通过使用UglifyPlugin,ResSplitPlugin,ZipPlugin,TextureMergerPlugin,ConvertResConfigFilePlugin插件,使项目发布到微信小程序之后的代码包体积减小,用户发起的请求数变少,且将代码混淆压缩。
使用Egret自带的插件,已经可以满足开发者的基本需求,如果有针对项目的特殊需求,可以选择自定义插件。
使用Egret插件压缩代码包体积,减少请求数量的实战教程的更多相关文章
- 使用混淆ProGuard压缩代码和资源/减少方法数量
		ProGuard介绍 ProGuard是一个Java类文件压缩器,优化器,混淆器和预先文件验证器. 压缩步骤检测和删除未使用的类,字段,方法和属性. 优化步骤分析和优化方法的字节码. 混淆步骤使用短无 ... 
- 小程序代码包压缩 策略&方案
		微信小程序自推出以来,逐渐发展,目前正受到越来越多的青睐.其中很重要的一点得益于小程序的轻量级特性,每个小程序最多不超过2MB,招之即来挥之即去,相比于几十上百兆的APP,用户进入小程序,或者说,小程 ... 
- webpack4下import()模块按需加载,打包按需切割模块,减少包体积,加快首页请求速度
		一:背景 因为项目功能越加越多,打包后的体积越来越大,导致首页展示的时候速度比较慢,因为要等压缩的js的包加载完毕. 首页展示的时候只需要对应的js,并不需要全部的js模块,所以这里就可以用按需加载, ... 
- webpack学习笔记--压缩代码
		浏览器从服务器访问网页时获取的 JavaScript.CSS 资源都是文本形式的,文件越大网页加载时间越长. 为了提升网页加速速度和减少网络传输流量,可以对这些资源进行压缩. 压缩的方法除了可以通过 ... 
- 压缩代码加速ecshop程序页面加载速度
		由于页面有很多图片,页面加载速度有点慢,本来打算减小图片的体积,后来想想这个后期还得测试下,所以暂时不打算使用google的图片优化工具,先把ecshop生成的html代码压缩下吧 压缩前:首页体积为 ... 
- 前端神器-神级代码编辑软件Sublime Text下载、使用教程、插件推荐说明、全套快捷键
		Sublime Text 是一个代码编辑器,也是HTML和散文先进的文本编辑器.Sublime Text是由程序员Jon Skinner于2008年1月份所开发出来,它最初被设计为一个具有丰富扩展功能 ... 
- python学习笔记(23)——python压缩bin包
		说明(2017-12-25 10:43:20): 1. CZ写的压缩bin包代码,记下来以后好抄. # coding:utf-8 ''' Created on 2014年8月14日 @author: ... 
- 关于执行findbugs,checkstyle,jacoco插件检测代码,GitHook的脚本编写
		Git钩子的作用: (pre-commit ) 在用户执行 git commit -m "xxx" 命令之前,先执行pre-commit文件中的脚本命令 在pre-commit文件 ... 
- hudson用SVN插件下载代码,用ant插件打包, 用SSH插件部署
		hudson自动化部署步骤 1.SVN插件->下载代码 2.ant插件->war打包 (hudson服务器上可安装多个版本ant,每个项目可以选择一个ant版本.Build File ... 
随机推荐
- WARN node unsupported "node@v6.11.2" is ......(windows系统更新node版本)
			问题: 使用npm下载文件时报错:WARN node unsupported "node@v6.11.2" is incompatible with electron@^7.1.9 ... 
- 禁用所有控制台console.log()打印
			在前端dev的环境下,经常会用到console.log()进行调试,以方便开发, 而在产品release的版本中,又不合适在浏览器的console中输出那么多的调试信息. 但是会经常因为没有删除这些开 ... 
- 如何在windows下成功的编译和安装python组件hyperscan
			摘要:hyperscan 是英特尔推出的一款高性能正则表达式引擎,一次接口调用可以实现多条规则与多个对象之间的匹配,可以支持多种匹配模式,块模式和流模式,它是以PCRE为原型开发,并以BSD许可证开源 ... 
- C#控制台输入密码星号显示
			在Program类中的Main方法里: 1 public class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.Write ... 
- 测试杂谈——一条SQL引发的思考
			此篇只是个人记录,相信各位大神早已轻车熟路,不喜勿喷:有错之处,欢迎指正. 有一天收到新人的咨询,是关于sql的问题. 问题1:为什么sql查询的数据与界面展示的不准确: 问题2:为什么sql查询时间 ... 
- 如何用 Redis 解决海量重复提交问题
			前言 在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求,我们来解释一下幂等的概念:任意多次执行所产生的影响均与一次执行的影响相同.按照这个含义,最终的含义就是 对数据库的影响只能是一次性的, ... 
- MySQL二进制binlog日志说明以及利用binlog日志恢复数据
			MySQL的binlog日志对于mysql数据库来说是十分重要的.在数据丢失的紧急情况下,我们往往会想到用binlog日志功能进行数据恢复(定时全量备份+binlog日志恢复增量数据部分). 一.关于 ... 
- web服务器-nginx配置文件
			web服务器-nginx配置文件 一 nginx配置文件 #启动子进程程序的默认用户 #user nobody #一个主进程和多个工作进程.工作进程是单进程的,且不需要特殊授权即可运行:这里定义的是工 ... 
- web自动化之定位
			UI自动化必不可少的操作--元素定位 8大基础定位 driver.find_element_by_id() # id定位 driver.find_element_by_name() # name定位 ... 
- 学习SpringMVC必知必会(2)~走近Spring MVC
			一.Spring 基本介绍 1.什么是 Spring MVC? SpringMVC 是 Spring-Frame 框架的子集(Spring-Frame包含了Spring MVC), MVC 框架,(类 ... 
