本身動手打造代碼壓縮合並工具

時下grunt很是的火啊,用着雖然很爽,可是它的配置確實很煩。若是以前沒有用過,想要一會兒熟練駕馭它,有必定的學習成本,並且還要裝node這個你們夥,項目之初咱們選擇了compiler.jar這個輕量的工具進行打包。我一直在尋思着,如何編寫一鍵打包工具。以前呢是手工的拼接好有的js文件,作成符合compiler.jar打包文件所要求的批處理文件,而後運行這個批處理,生成咱們須要的js和css文件。隨着js文件數量的增加,純手工拼接這些文件的地址就變得很是考驗人的耐心了,並且還容易漏掉或重複某些文件,因而「一鍵打包工具」的編寫就變得刻不容緩了。下面是一個真實的index.html文件的一部分:javascript

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="target-densitydpi=device-dpi, initial-scale=1, user-scalable=0, maximum-scale=1">
     <!--隱藏瀏覽器的工具欄和菜單欄,對iso系統起用-->
    <!--用於PC上調式,不參與合併壓縮-->
    <script src="lib/data/database.js" name="noBuild"></script>
    <!--Iframe加載處理-->
    <script src="lib/LoadMode.js"></script>

    <script src="lib/core/jQuery.js"></script>
    <script src="lib/core/underscore.js"></script>
    <script src="lib/animate/SVGIcons/snap.min.js"></script>
    <script src="lib/animate/pixi.js"></script>

    <script src="lib/core/Xut.js"></script>
    <script src="lib/core/isMobile.js"></script>
    <script src="lib/core/aaronRequire.js"></script>
    <script src="lib/core/nextTick.js"></script>
    <script src="lib/Config.js"></script>

    <script src="lib/core/lang/Object.js"></script>
    <script src="lib/core/lang/Function.js"></script>
    <script src="lib/core/lang/Array.js"></script>
    <script src="lib/core/video.js"></script>

    <!-- 自定義事件,合集處理,iframe通信 -->
    <script src="lib/core/event/asEvented.js"></script>
    <script src="lib/core/message/pms.js"></script>

    <!--插件-->
    <script src="lib/plugin/cordova.js"></script>
    <script src="lib/plugin/readAssetsFilePlugin.js"></script>
    <script src="lib/plugin/initDatabase.js"></script>
    <script src="lib/plugin/web.js"></script>
    <script src="lib/plugin/video.js"></script>
    <script src="lib/plugin/openAppPlugin.js"></script>
    <script src="lib/plugin/tabletPlugin.js"></script>
    <script src="lib/plugin/statusbar.js"></script>
    <script src="lib/plugin/iap.js"></script>
    <script src="lib/plugin/AppStoreLink.js"></script>
    <script src="lib/plugin/downloadPlugin.js"></script>
    <script src="lib/plugin/xxteManager.js"></script>
    <script src="lib/plugin/unzipPlugin.js"></script>
    <script src="lib/plugin/readPlugin.js"></script>
    <script src="lib/plugin/deletePlugin.js"></script>
    <!-- 動畫庫 -->
    <script src="lib/animate/TweenMax.min.js"></script>
    <script src="lib/animate/plugins/ThrowPropsPlugin.min.js"></script>
    <script src="lib/animate/PptAnimation.js"></script>
    <script src="lib/animate/CanvasAnimation.js"></script>
    <script src="lib/animate/dragdrop/Draggable.min.js"></script>
    <script src="lib/animate/dragdrop/dragdrop.js"></script>
    <script src="lib/animate/iscroll.js"></script>
    <script src="lib/animate/hammer.js"></script>
    <script src="lib/animate/SVGIcons/svgicons-config.js"></script>
    <script src="lib/animate/SVGIcons/svgicons.js"></script>
    <script src="lib/animate/SpriteA.js"></script>

    <script src="lib/util/Utils.js"></script>
    <script src="lib/util/LocalStorage.js"></script>
    <script src="lib/util/ScriptLoad.js"></script>
    <script src="lib/util/ExecuteSql.js"></script>
    <script src="lib/util/PromptNotice.js"></script>
    <script src="lib/util/edge.js"></script>

    <!-- 配置文件,數據文件,結構文件 -->
    <script src="lib/data/Store.js"></script>
    <script src="lib/data/StoreManager.js"></script>

    <!-- 數據初始化 -->
    <script src="lib/Main.js"></script>
    <script src="lib/Initialize.js"></script>
    <script src="lib/scenario/SceneLayout.js"></script>
    <script src="lib/scenario/SceneFactory.js"></script>
    <script src="lib/scenario/SceneController.js"></script>
    <script src="lib/LoadScene.js"></script>
    <script src="lib/Dispatcher.js"></script>

    <!-- 工具欄 -->
    <script src="lib/toolbar/Navbar.js"></script>
    <script src="lib/toolbar/sToolbar.js"></script>
    <script src="lib/toolbar/fToolbar.js"></script>
    <script src="lib/toolbar/searchBar.js"></script>
    <script src="lib/toolbar/bookMark.js"></script>

    <!-- 多線程任務片 -->
    <script src="lib/threadTask/Buffer.js"></script>
    <script src="lib/threadTask/TaskContents.js"></script>
    <script src="lib/threadTask/TaskComponents.js"></script>
    <script src="lib/threadTask/TaskBackground.js"></script>
    <script src="lib/threadTask/TaskContainer.js"></script>

    <script src="lib/pageBase/Parser.js"></script>
    <script src="lib/pageBase/Collection.js"></script>
    <script src="lib/pageBase/MultiEvent.js"></script>
    <script src="lib/pageBase/PageBase.js"></script>
    <script src="lib/pageBase/Page.js"></script>
    <script src="lib/pageBase/Master.js"></script>


    <!-- 頁面管理模塊 -->
    <script src="lib/controller/transform/Translation.js"></script>
    <script src="lib/controller/OverrideApi.js"></script>
    <script src="lib/controller/Abstract.js"></script>
    <script src="lib/controller/Emitter.js"></script>
    <script src="lib/controller/PageMgr.js"></script>
    <script src="lib/controller/MasterMgr.js"></script>
    <script src="lib/controller/Compiler.js"></script>
    <script src="lib/controller/ViewModel.js"></script>
    <script src="lib/controller/SwitchPage.js"></script>
    <script src="lib/controller/EventDrive.js"></script>

    <!--熱點管理-->
    <script src="lib/scheduler/AssignAutoRun.js"></script>
    <script src="lib/scheduler/AssignTrigger.js"></script>
    <script src="lib/scheduler/AssignSuspend.js"></script>
    <script src="lib/scheduler/AssignOriginal.js"></script>
    <script src="lib/scheduler/AssignRecovery.js"></script>
    <script src="lib/scheduler/ProcessControl.js"></script>
    <script src="lib/scheduler/Binding.js"></script>

    <!-- 適配器,用於處理熱點 -->
    <script src="lib/directives/dir-Content.js"></script>
    <script src="lib/directives/dir-Widget.js"></script>
    <script src="lib/directives/dir-Media.js"></script>
    <script src="lib/directives/dir-Action.js"></script>
    <script src="lib/directives/dir-ShowNote.js"></script>

     <!--多媒體對象 -->
    <script src="lib/component/media/Audio.js"></script>
    <script src="lib/component/media/Video.js"></script>
    <script src="lib/component/media/AudioManager.js"></script>
    <script src="lib/component/media/VideoManager.js"></script>

    <!--文本熱點-->
    <script src="lib/component/content/conFilter.js"></script>
    <script src="lib/component/content/conAlgorithm.js"></script>

後面還有很長,bug,活人不能被尿憋死,辦法總比問題多。我是會一點php的,php在處理文件方面是很拿手的,是時候讓它發揮點做用了。因而我想到了用php去自動提出index裏邊的js和css,而後按指定的格式生成批處理文件,在後臺用靜默方式運行這個批處理,最後把結果返回給顯示器。這樣我就能夠不勞而獲了。想一想都有點小激動喲,因而簡單的寫了一個界面.php

 

接下來就是實現功能了,先不着急編寫代碼,分析下需求:css

1. 遍歷index.html文件,提取js文件或css文件.html

2. 對這文件進行過慮,由於有些是註釋掉的,有些是調式用的。前端

3. 生成對應的批處理文件java

4. 執行批處理文件node

5. 顯示處理結果web

即然有兩種狀況,我就用一個工廠模式來適配,方便之後擴展其它類型,目光要放長遠一點。即然工廠都有了,那索性再來一個接口,約定都必須要實現「接收請求」和「輸出結果」這兩個接口。再想一想處理js和css均可能會有相同的功能,讓它們繼承一個父類能夠使代碼複用,因而繼承也先用上。目前的設計應當能夠知足個人要求了,因而開始編寫php代碼.ajax

<?php
header("Content-type: text/html; charset=utf-8");

/**
 * 根據index.html文件中引用的js,生成compressJs.bat
 * @author frog <278500368@qq.com>
 * @date 2014-11-17
 */

interface ICompress {
    /**
     * 處理用戶請求
     * @return [type] [description]
     */
    public function request();

    /**
     * 處理輸出結果
     * @return [type] [description]
     */
    public function render();
}

class BaseCompress {
    public $content;
    public $outPath;
    public $isAuto;

    public function __construct($isAuto=false){
        $outPath = '_file';
        if(!is_dir($outPath)){
            mkdir($outPath);
        }
        $this->outPath = $outPath;
        $this->isAuto = $isAuto;
    }


    /**
     * 運行批處理
     * @return [type] [description]
     */
    public function runBat($name){

    }
}

/**
 * 壓縮javascript文件
 * 合併javascript文件
 */
class CompressJS extends BaseCompress implements ICompress {

    /**
     * 處理用戶請求
     * @return [type] [description]
     */
    public function request(){

    }

    /**
     * 處理輸出結果
     * @return [type] [description]
     */
        public function render(){}

}

/**
 * 壓縮樣式文件
 */
class CompressCSS extends BaseCompress implements ICompress {

    public function request(){
 
    }

    /**
     * 處理輸出結果
     * @return [type] [description]
     */
         public function render(){}
     
}

/**
 * 工廠類
 */
class Factory {

    public static function create($type,$isAuto){
        $ob = null;
        switch ($type) {
            case 'js':
                $ob = new CompressJS($isAuto);
                break;
            case 'css':
                $ob = new CompressCSS($isAuto);
                break;
            default:
                # code...
                break;
        }
        return $ob;
    }
}

而後是調用處理:chrome

//處理ajax請求
if(isset($_POST['submit'])){
    //是否自動執行批處理
    $isAuto = $_POST['zip'] === 'true' ? true : false;
    //處理類型
    $type = $_POST['type'];

    $c = Factory::create($type,$isAuto);
//接口方法
$c->request(); $c->render(); }else{ echo '請使用靜態頁訪問本程序:<a href="index.html">點此進入</a>'; }

大體的骨架就出來了。具體的填碼過程就比較簡單了。稍微有點難度的就是執行批處理這個一方法.

是網上提供的方法,之後可能用的上,這裏特地貼一下:

public function runBat($name){
        if(!file_exists($name) || !$this->isAuto){
            return;
        }
        //轉入後臺處理
        @exec(pclose(popen("start /B ". escapeshellcmd($name), "r")));
    }

在前面的index.html中,有一個name="noBuild"這個是我人爲添加的,這是由於我要過濾這種標識的js文件,這樣之後要過濾別的文件,也只要添加這個標識就能夠了,不用改php代碼。因爲是內部使用,沒有作表單項來指定工程的路徑,默認就是index.html所處的上級目錄即爲工程目錄。這樣設計簡化了操做,提升了效率。

關於遍歷特定的文件,我推薦glob函數,很簡潔的方案:

$files = glob($path.'/*.css',GLOB_NOSORT);

下面是工程目錄結構圖:

再來一張運行效果圖:

  

最後是處理結果圖:

終於不用寫grunt的配置和安裝node這個傢伙了,不再擔憂更新的時候,從svn上拉下來一堆node的東西,是時候和它們說再見了:

好像忘了展現前端代碼了:

/**
 * 選項卡類
 * @param {string} id 選項卡的ID
 */
function Tabs(id){
    var node = document.querySelector('#'+id);
    var selected = node.querySelector('.selected');
    this.selected = selected;
    this.node = node;
    this.bindEvent();
}

/**
 * 切換選項卡
 * @param  {object} event 事件
 * @return {[type]}   [description]
 */
Tabs.prototype.change = function(event){
    var element = event.target;
    if(element.tagName.toLowerCase()=='li'){
        if(element.className=='selected'){
            return;
        }
    }else{
        while(element != this.node){
            element = element.parentNode;
            if(element.tagName.toLowerCase()=='li'){
                break;
            }
        }
        if(element == this.node) return;
    }
    this.selected.removeAttribute('class');
    element.className = 'selected';
    this.selected = element;
    this.content();
}

Tabs.prototype.content = function(){
  var form = document.form1;

    switch(this.getTabType()){
      case 'js':
        form.style.display = 'block';
        form.children[0].innerHTML = '自動壓縮JS';
        break;
      case 'css':
        form.style.display = 'block';
        form.children[0].innerHTML = '自動壓縮CSS';
        break;
      default:
    }
}

 

會前端和後端,就是這麼任性。輕輕一點,告別煩惱!造本身的工具,讓別人去苦逼吧,So easy!

相關文章
相關標籤/搜索