【grunt第一彈】30分鐘學會使用grunt打包前端代碼

前言

以如今前端js激增的態勢,一個項目下來幾十個js文件輕輕鬆鬆
對於複雜一點的單頁應用來講,文件上百簡直是屢見不鮮,那麼這個時候咱們的js文件應該怎麼處理呢?
另外,對於css文件,又該如何處理呢??
這些都是咱們實際工做中要遇到的問題,好比咱們如今框架使用zepto、backbone、underscore
咱們要如何將他們合成一個libs文件,這都是使人頭疼的問題css

可是grunt的出現卻讓這些事情變得優雅起來!
簡單一鍵,打包結束,尼瑪不是不可能啊!html

grunt

是一套前端自動化工具,一個基於nodeJs的命令行工具,通常用於:
① 壓縮文件
② 合併文件
③ 簡單語法檢查前端

對於其餘用法,我還不太清楚,咱們這裏簡單介紹下grunt的壓縮、合併文件node

初學,有誤請包涵web

準備階段

一、nodeJs環境

由於grunt是基於nodeJs的,因此首先各位須要安裝nodeJS環境,這塊咱們便無論了
http://www.cnblogs.com/yexiaochai/p/3527418.htmlexpress

二、安裝grunt

有了nodeJs環境後,咱們即可以開始搞grunt了,由於咱們可能在任何目錄下運行打包程序,因此咱們須要安裝CLI
官方推薦在全局安裝CLI(grunt的命令行接口)npm

npm install -g grunt-cli

這條命令將會把grunt命令植入系統路徑,這樣就能在任意目錄運行他,緣由是json

每次運行grunt時,它都會使用node的require查找本地是否安裝grunt,若是找到CLI便加載這個本地grunt庫
而後應用咱們項目中的GruntFile配置,並執行任務
PS:這段先不要管,安裝完了往下看安全

實例學習:打包zepto

一些東西說多了都是淚,直接先上實例吧,實例結束後再說其它的
首先在D盤新建一個項目(文件夾就好)
在裏面新增兩個文件(不要問爲何,搞進去先)app

① package.json

{
  "name": "demo",
  "file": "zepto",
  "version": "0.1.0",
  "description": "demo",
  "license": "MIT",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-jshint": "~0.6.3",
    "grunt-contrib-uglify": "~0.2.1",
    "grunt-contrib-requirejs": "~0.4.1",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-contrib-clean": "~0.5.0",
    "grunt-strip": "~0.2.1"
  },
  "dependencies": {
    "express": "3.x"
  }
}

② Gruntfile.js

完了咱們須要在grunt目錄下執行 npm install將相關的文件下載下來:

$ cd d:
$ cd grunt

而後咱們的目錄就會多一點東西:

多了不少東西,先別管事幹什麼的,咱們後面都會用到,這個時候在目錄下新建src文件夾,而且搞一個zepto進去

而後在Gruntfile中新增如下代碼(先別管,增長再說)

module.exports = function (grunt) {
  // 項目配置
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      options: {
        banner: '/*! <%= pkg.file %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/<%=pkg.file %>.js',
        dest: 'dest/<%= pkg.file %>.min.js'
      }
    }
  });
  // 加載提供"uglify"任務的插件
  grunt.loadNpmTasks('grunt-contrib-uglify');
  // 默認任務
  grunt.registerTask('default', ['uglify']);
}

而後運行 grunt命令後

grunt

嗯嗯,多了一個文件,而且是壓縮的,不差!!!第一步結束

認識Gruntdile與package.json

不出意外,每個gurnt都會須要這兩個文件,而且極可能就只有這兩個文件(複雜的狀況有所不一樣)

package.json

這個文件用來存儲npm模塊的依賴項(好比咱們的打包如果依賴requireJS的插件,這裏就須要配置)
而後,咱們會在裏面配置一些不同的信息,好比咱們上面的file,這些數據都會放到package中
對於package的靈活配置,咱們會在後面提到

Gruntfile

這個文件尤爲關鍵,他通常幹兩件事情:
① 讀取package信息
② 插件加載、註冊任務,運行任務(grunt對外的接口所有寫在這裏面)

Gruntfile通常由四個部分組成
① 包裝函數
這個包裝函數沒什麼東西,意思就是咱們全部的代碼必須放到這個函數裏面

module.exports = function (grunt) {
//你的代碼
}

這個不用知道爲何,直接將代碼放入便可

② 項目/任務配置
咱們在Gruntfile通常第一個用到的就是initConfig方法配置依賴信息

pkg: grunt.file.readJSON('package.json')

這裏的 grunt.file.readJSON就會將咱們的配置文件讀出,而且轉換爲json對象

而後咱們在後面的地方就能夠採用pkg.XXX的方式訪問其中的數據了
值得注意的是這裏使用的是underscore模板引擎,因此你在這裏能夠寫不少東西

uglify是一個插件的,咱們在package依賴項進行了配置,這個時候咱們爲系統配置了一個任務
uglify(壓縮),他會幹這幾個事情:

① 在src中找到zepto進行壓縮(具體名字在package中找到)
② 找到dest目錄,沒有就新建,而後將壓縮文件搞進去
③ 在上面加幾個描述語言

這個任務配置其實就是一個方法接口調用,按照規範來就好,暫時不予關注,內幕後期來
這裏只是定義了相關參數,可是並未加載實際函數,因此後面立刻就有一句:

grunt.loadNpmTasks('grunt-contrib-uglify');

用於加載相關插件

最後註冊一個自定義任務(其實也是默認任務),因此咱們下面的命令行是等效的:

grunt == grunt uglify

至此,咱們就簡單解析了一番grunt的整個操做,下面來合併文件的例子

合併文件

合併文件依賴於grunt-contrib-concat插件,因此咱們的package依賴項要新增一項

"devDependencies": {
  "grunt": "~0.4.1",
  "grunt-contrib-jshint": "~0.6.3",
  "grunt-contrib-concat": "~0.3.0",
  "grunt-contrib-uglify": "~0.2.1",
  "grunt-contrib-requirejs": "~0.4.1",
  "grunt-contrib-copy": "~0.4.1",
  "grunt-contrib-clean": "~0.5.0",
  "grunt-strip": "~0.2.1"
},

而後再將代碼寫成這個樣子

module.exports = function (grunt) {
  // 項目配置
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['src/zepto.js', 'src/underscore.js', 'src/backbone.js'],
        dest: 'dest/libs.js'
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-concat');
  // 默認任務
  grunt.registerTask('default', ['concat']);
}

運行後,神奇的一幕發生了:

三個文件被壓縮成了一個,可是沒有壓縮,因此,咱們這裏再加一步操做,將之壓縮後再合併

module.exports = function (grunt) {
  // 項目配置
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['src/zepto.js', 'src/underscore.js', 'src/backbone.js'],
        dest: 'dest/libs.js'
      }
    },
    uglify: {
      build: {
        src: 'dest/libs.js',
        dest: 'dest/libs.min.js'
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  // 默認任務
  grunt.registerTask('default', ['concat', 'uglify']);
}

我這裏的作法是先合併造成一個libs,而後再將libs壓縮成libs.min.js

因此咱們這裏換個作法,先壓縮再合併,其實unglify已經幹了這些事情了

module.exports = function (grunt) {
  // 項目配置
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
      "my_target": {
        "files": {
          'dest/libs.min.js': ['src/zepto.js', 'src/underscore.js', 'src/backbone.js']
        }
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-uglify');
  // 默認任務
  grunt.registerTask('default', ['uglify']);
}

因此,咱們就暫時不去關注concat了

最後,今天時間不早了,咱們最後研究下grunt配合require因而便結束今天的學習吧

合併requireJS管理的文件

有了前面基礎後,咱們來幹一件平時很頭疼的事情,即是將require管理的全部js文件給壓縮了合併爲一個文件
首先咱們創建一個簡單的程序,裏面使用了zepto、backbone、underscore(事實上我並未使用什麼)

在main.js中新增代碼:

require.config({
 baseUrl: '',
 shim: {
  $: {
      exports: 'zepto'
  },
  _: {
   exports: '_'
  },
  B: {
   deps: [
    '_',
    '$'
     ],
   exports: 'Backbone'
  }
 },
 paths: {
  '$': 'src/zepto',
  '_': 'src/underscore',
  'B': 'src/backbone'
 }
});
requirejs(['B'], function (b) {
});

這樣的話運行會自動加載幾個文件,咱們如今但願將之合併爲一個libs.js該怎麼幹呢???

咱們這裏使用自定義任務方法來作,由於咱們好像沒有介紹他

要使用requireJS相關須要插件 

grunt.loadNpmTasks('grunt-contrib-requirejs');

由於咱們之後可能存在配置文件存在各個項目文件的狀況,因此咱們這裏將requireJs相關的配置放入gruntCfg.json中

這樣咱們的package.json就沒有什麼實際意義了:

{
  "name": "demo",
  "version": "0.1.0",
  "description": "demo",
  "license": "MIT",
  "devDependencies": {
 "grunt": "~0.4.1",
 "grunt-contrib-jshint": "~0.6.3",
 "grunt-contrib-concat": "~0.3.0",
 "grunt-contrib-uglify": "~0.2.1",
 "grunt-contrib-requirejs": "~0.4.1",
 "grunt-contrib-copy": "~0.4.1",
 "grunt-contrib-clean": "~0.5.0",
 "grunt-strip": "~0.2.1"
 
  },
  "dependencies": {
    "express": "3.x"
  }
}

咱們這裏設置的require相關的grunt配置文件以下(gruntCfg.json):

{
  "requirejs": {
    "main": {
      "options": {
        "baseUrl": "",
        "paths": {
          "$": "src/zepto",
          "_": "src/underscore",
          "B": "src/backbone",
          "Test": "src/Test"
        },
        "web": {
          "include": [
            "$",
            "_",
            "B",
            "Test"
          ],
          "out": "dest/libs.js"
        }
      }
    }
  }
}

這裏咱們要打包這些文件搞到dest的libs.js文件中,這個文件照作就行,最後核心代碼以下:

module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  //爲了介紹自定義任務搞了一個這個
  grunt.registerTask('build', 'require demo', function () {
    //任務列表
    var tasks = ['requirejs'];
    //源碼文件
    var srcDir = 'src';
    //目標文件
    var destDir = 'dest';
    //設置參數
    grunt.config.set('config', {
      srcDir: srcDir,
      destDir: destDir
    });
    //設置requireJs的信息
    var taskCfg = grunt.file.readJSON('gruntCfg.json');
    var options = taskCfg.requirejs.main.options,
        platformCfg = options.web,
        includes = platformCfg.include,
        paths = options.paths;
    var pos = -1;
    var requireTask = taskCfg.requirejs;
    options.path = paths;
    options.out = platformCfg.out;
    options.include = includes;
    //運行任務
    grunt.task.run(tasks);
    grunt.config.set("requirejs", requireTask);
  });
}

搞完了運行就好:grunt build

grunt build

最後發現葉小釵三字,我就放心了,安全!!!!!!

下集預告

1 HTML文件打包

2 樣式文件打包

3 移動打包文件

咱們的開發版本與使用版本可能不在一個位置哦

4 分支處理

不一樣分支打包

5 native包與HTML5包

在HTML5嵌入webview的時代,咱們固然存在一次打包既要造成網站文件也要造成app文件

6 分頻道打包

固然可能存在分頻道分分支打包的狀況

今日到此爲止,待續......

相關文章
相關標籤/搜索