在白鹭引擎发布了5.2.7版本中新增加了命令行,增加自动合图插件TextureMergerPlugin功能。今天,我们以一个EUI案例来展示自动合图插件的具体使用方法和注意事项。
此外,我们在本文还融入了UglifyPlugin、ResSplitPlugin、ZipPlugin等插件使用方法。开发者利用上述4款插件,将实现代码包体积更小、更好管理的目标。
项目初始化
把index.html中的data-scale-mode改成fixedWidth 打开EgretLauncher,将本项目发布成微信小游戏 打开微信开发者工具
使用UglifyPlugin压缩代码 在微信开发者工具可以看到,js文件夹中5个库文件和一个main.js。
现在需求是是要把库文件压缩到一个文件lib.min.js中。
回到EgretWing,编辑sctipts下的config.wxgame.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 if (command == 'build' ) { return { outputDir, commands : [ new CleanPlugin ({ matchers : ["js" , "resource" ] }), new CompilePlugin ({ libraryType : "debug" , defines : { DEBUG : true , RELEASE : false } }), new ExmlPlugin ('commonjs' ), 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, 修改一下引用顺序。
1 2 3 require("js/lib.min.js" ) require("js/main.js" ) require("js/default.thm.js" )
每次编译的时候manifest.js都会被重新生成,所以我们使用一个自定义脚本来修改他们的顺序
打开 scripts下的myPlugin.ts :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 export class CustomPlugin implements plugins.Command { private buffer constructor ( ) { } async onFile (file: plugins.File ) { if (file.basename .indexOf ('manifest.js' ) > -1 ) { this .buffer = file.contents } return file; } async onFinish (commandContext: plugins.CommandContext ) { 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中已经默认引用,所以只需要调用即可,注意调用顺序
1 2 3 new ManifestPlugin ({ output : 'manifest.js' }),new CustomPlugin ()
使用ResSplitPlugin分离资源文件 因为微信对代码包的大小是有限制的,总大小不能超过4M(使用分包功能可以提升到8M),所以我们需要通过ResSplitPlugin把某些游戏资源文件分离出去,将游戏资源放置在一个外部CDN服务器上,需要的时候动态加载即可。
编辑config.wxgame.ts:
1 2 3 4 5 6 7 8 9 10 new ResSplitPlugin ({ verbose : false , matchers : [ { 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 , 在终端中输入:
1 2 3 npm install cross-zip -g npm install cross-zip-cli -g
安装完成之后,在config.wxgame.ts添加代码:
1 2 3 4 5 6 7 8 new ZipPlugin ({ mergeSelector : p => { if (p.indexOf ("assets/" ) >= 0 ) { return "assets.zip" } } })
项目中其实assets里面的资源都是没有用到的,这里我们用它来演示压缩插件的使用。
保存后在终端执行:egret build
执行之后可以在微信开发者工具看到,resource目录下原来的assets文件夹已经被压缩成了assets.zip。
使用TextureMergerPlugin,ConvertResConfigFilePlugin合并纹理集 项目中使用的图片资源都是单独的png文件,在加载的时候每张图片都会单独请求。我们可以通过合并纹理集的方式把这些图片合成一张图,以减少请求数量。 使用插件之前,我们需要有纹理集的配置文件tmpropject, 可以用两种方式生成:
使用 TextureMerger工具 执行脚本生成 这里使用第二种方法,使用脚本autoMerger.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 "use strict" ;Object .defineProperty (exports , "__esModule" , { value : true });var fs = require ("fs" );var path = require ("path" );var resjsons = ["resource/default.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 ("\/" ); var target = "." ; for (var _i = 0 , paths_1 = paths; _i < paths_1.length ; _i++) { var p = paths_1[_i]; target += ("\/" + p); if (!fs.existsSync (target)) fs.mkdirSync (target); } } } var _loop_1 = function (resJson ) { if (fs.existsSync (resJson) && resJson.indexOf ("res.json" ) > -1 ) { var defaultJson = fs.readFileSync (resJson, "utf-8" ); var defaultObject = JSON .parse (defaultJson); var groups = defaultObject.groups ; var resources = defaultObject.resources ; var resourcesHash_1 = {}; for (var _i = 0 , resources_1 = resources; _i < resources_1.length ; _i++) { var resource = resources_1[_i]; resourcesHash_1[resource.name ] = resource.url ; } for (var _a = 0 , groups_1 = groups; _a < groups_1.length ; _a++) { var group = groups_1[_a]; var tmproject = {}; tmproject["options" ] = { "layoutMath" : "2" , "sizeMode" : "2n" , "useExtension" : 1 , "layoutGap" : 1 , "extend" : 0 }; tmproject["projectName" ] = group.name + "_" + tempindex; tmproject["version" ] = 5 ; tempindex++; var oldkeys = group.keys .split ("," ); var oldkeysHash = {}; for (var _b = 0 , oldkeys_1 = oldkeys; _b < oldkeys_1.length ; _b++) { var key = oldkeys_1[_b]; oldkeysHash[key] = true ; } var newKeys = []; 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 = []; var urls = newKeys.map (function (key ) { return path.join (pathNor, resourcesHash_1[key]); }); tmproject["files" ] = urls; 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:
1 2 3 4 5 6 7 8 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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 原始数组 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插件压缩代码包体积,减少请求数量的实战教程