使用Egret插件壓縮代碼包體積,減小請求數量的實戰教程

在白鷺引擎發佈了5.2.7版本中新增長了命令行,增長自動合圖插件TextureMergerPlugin功能。今天,咱們以一個EUI案例來展現自動合圖插件的具體使用方法和注意事項。javascript

此外,咱們在本文還融入了UglifyPlugin、ResSplitPlugin、ZipPlugin等插件使用方法。開發者利用上述4款插件,將實現代碼包體積更小、更好管理的目標。html


目錄:java

  • 使用UglifyPlugin將代碼混淆壓縮
  • 使用ResSplitPlugin把部分資源分離出去
  • 使用ZipPlugin把文件壓縮成zip格式
  • 使用TextureMergerPlugin將紋理合並,且用ConvertResConfigFilePlugin修改res.json配置文件


項目初始化

1. 把index.html中的`data-scale-mode`改爲`fixedWidth`
2. 打開EgretLauncher,將本項目發佈成微信小遊戲
3. 打開微信開發者工具


使用UglifyPlugin壓縮代碼

在微信開發者工具能夠看到,js文件夾中5個庫文件和一個`main.js`。

如今需求是是要把庫文件壓縮到一個文件`lib.min.js`中。

回到EgretWing,編輯sctipts下的config.wxgame.ts:
 node

//***其餘代碼***
//

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' })
        ]
    }
    }

//
// ***其餘代碼***



保存後在終端執行:linux

egret build


能夠在微信開發者工具看到發佈後的代碼,js文件夾內的庫文件已經被壓縮到lib.min.js。

可是報錯,找不到eui,這是由於自動生成的`manifest.js`裏面對js的引用順序出錯,須要優先引用lib.min.js

打開根目錄下的`manifest.js`, 修改一下引用順序。
 c++

require("js/lib.min.js")
require("js/main.js")
require("js/default.thm.js")


每次編譯的時候`manifest.js`都會被從新生成,因此咱們使用一個自定義腳原本修改他們的順序

打開 scripts下的myPlugin.ts :
 git

/**
 * 示例自定義插件,您能夠查閱 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中已經默認引用,因此只須要調用便可,注意調用順序
 github

new ManifestPlugin({ output: 'manifest.js' }),
// 在manifest.js生成以後調用
new CustomPlugin()


使用ResSplitPlugin分離資源文件

由於微信對代碼包的大小是有限制的,總大小不能超過4M(使用分包功能能夠提高到8M),因此咱們須要經過ResSplitPlugin把某些遊戲資源文件分離出去,將遊戲資源放置在一個外部CDN服務器上,須要的時候動態加載便可。

編輯config.wxgame.ts:
 npm

// ***其餘代碼***
//

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` }
    ]
})

// ***其餘代碼***


保存後在終端執行:json

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`, 能夠用兩種方式生成:

1. 使用[TextureMerger工具](http://developer.egret.com/cn/github/egret-docs/tools/TextureMerger/manual/index.html)
2. 執行腳本生成

這裏使用第二種方法,使用腳本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自帶的插件,已經能夠知足開發者的基本需求,若是有針對項目的特殊需求,能夠選擇[自定義插件](http://developer.egret.com/cn/github/egret-docs/Engine2D/projectConfig/cmdExtensionPlugin/index.html)。

相關文章
相關標籤/搜索