grunt從入門到自定義項目模板


文章還可在我的github上找到,排版更友好一點:grunt從入門到自定義項目模板

一.Grunt入門介紹

1. Grunt是神馬

基於任務的命令行構建工具(針對JavaScript項目)

鏈接:http://gruntjs.com/

2. 使用Grunt的理由

前端的工具算得上是五花八門,在介紹如何Grunt之前,首先我們得反問自己:

  • Grunt能夠幫我們解決什么問題?
  • 是否有其他更合適的替代方案?

3. Grunt能夠幫我們解決什么問題?

作為一名開發人員,我們見過了不少功能胡里花哨但並不實用的工具。但是,我們很少會因為一個工具功能很強大而去使用它。更多地,是因為在工作中我們遇到了一些問題,而某個工具剛好幫我們解決了這些問題。

假設我們有個叫IMWEB_PROJ的項目,該項目主要包含兩個功能模塊,分別是moduleAmoduleB。回想一下,作為一名前端開發人員,從功能開發到產品正式上線,我們的工作流程是什么樣的:

正式進入編碼工作前,得做些准備工作:

  • 新建目錄IMWEB_PROJ,index.html為主入口;根目錄下面再另外新建三個目錄js、css、img,分別用來存放js文件、css文件、圖片
  • IMWEB_PROJ/js下新建個main.js作為項目主邏輯的入口,添加moduleA.js、modueB.js,對了,不能把我們的基礎組件Badjs.js、simple.js、nohost.js給忘了
  • IMWEB_PROJ/css下新建個reset.css,添加moduleA.css、moduleB.css

熱火朝天地編碼,產品終於即將上線,上線前的准備工作同樣不能馬虎

  • JSHint——檢查下JS代碼規范性,避免進行類似隱式全局變量這樣的坑里
  • concat——JS文件合並,合理減少請求數,提升加載速度
  • cssmin——CSS文件合並,合理減少請求數,提升加載速度
  • Uglyfy——壓縮文件,減少文件尺寸,提升用戶側加載速度
  • QUnit——單元測試,提高項目可維護性,結合遞歸測試可盡早發現潛在問題

上面的場景是不是很眼熟?重復而枯燥的工作占據了我們太多的時間,忘了誰說過,當重復做一件事超過三次,就應該考慮將它自動化。

Grunt正是為了解決上述問題而誕生,它將上面提到的項目結構生成、JSHint檢查、文件合並、壓縮、單元測試等繁瑣的工作變成一個個可自動化完成的任務,一鍵搞定。

4. 其他使用Grunt的理由

  • 文檔豐富:詳細的使用說明,從入門使用,到高級定制,非常詳盡
  • 插件豐富:基本能夠想到的常用的任務,都可以找到
  • 社區活躍:Grunt的開發團隊還是挺勤勞的,社區活躍度也挺高

5. 是否有其他更合適的替代方案?

當然有,而且不少,Ant、Yeoman、Mod、Fiddler+willow+qzmin等,先不展開

二. 從零開始使用Grunt

參考鏈接:http://gruntjs.com/getting-started

Grunt使用場景通常分兩種:

  1. 維護現有的Grunt項目——已經配置好的項目,下面以jQuery Plugin項目為例進行講解,簡單了解下一個Grunt項目的基本結構;
  2. 新創建的Grunt項目——包括項目目錄結構的創建,到Grunt任務的配置等;這里可以采用現有的Grunt模板,也可以采用自定義的模板;下文會采用自定義模板的形式,逐步講解如何創建一個**IMWEB團隊的前端基礎項目結構**

1. 環境以及依賴

Grunt以及Grunt的插件,都是通過npm進行安裝和管理,所以首先得安裝node環境,不贅述,見 http://nodejs.org/

2. 關於版本

注意:為了解決多版本並存的問題,從0.4.x版本開始,每個項目需獨立安裝Grunt及對應插件,版本分別如下:

  • Grunt 0.4.x
  • Nodejs >=0.8.0

3. 卸載老版本Grunt(版本<0.4.0)

grunt從版本0.3.X到0.4.x,變化比較大,主要是為了解決Grunt多版本共存的問題,有興趣的童鞋可以了解下。如果之前安裝了0.3.x版本,需先進行卸載

npm uninstall -g grunt

4. 安裝grunt-cli

grunt-cli的主要作用是讓我們可以運行Grunt命令,加上-g,則可以在任意目錄下運行,不展開

npm install -g grunt-cli

5. 安裝grunt-init

grunt-init是個腳手架工具,它可以幫你完成項目的自動化創建,包括項目的目錄結構,每個目錄里的文件等。具體情況要看你運行grunt-init指定的模板,以及創建過程中你對問題的回答,下文會簡單講到這個功能。

先運行下面命令安裝grunt-init,

npm install -g grunt-init

下面我們先通過安裝jQuery Plugin模板,來展示Gurnt模板的安裝,項目的創建,以及一個Grunt項目的目錄結構

三、jQuery Plugin示例:如何通過現有模板創建項目、運行Grunt任務

參考連接:http://gruntjs.com/project-scaffolding

1. 安裝jQuery Plugin模板

下面命令可以查看官方維護的Grunt模板

grunt-init --help

運行下面命令安裝jQuery模板

git clone git@github.com:gruntjs/grunt-init-jquery.git ~/.grunt-init/jquery

2. 根據jQuery Plugin模板創建項目

在上一步中我們已經安裝好了jQuery模板,接着運行下面命令,安裝jQuery項目

grunt-init jquery

按照引導回答下面問題,完成項目的創建

Please answer the following:
[?] Project name (test) DemoJQuery            
[?] Project title (DemojQuery)   
[?] Description (The best jQuery plugin ever.) just for test
[?] Version (0.1.0) 1.0.0
[?] Project git repository (git://github.com/root/test.git) 
[?] Project homepage (https://github.com/root/test) 
[?] Project issues tracker (https://github.com/root/test/issues) 
[?] Licenses (MIT) 
[?] Author name (none) 程序 猿 小卡
[?] Author email (none) 
[?] Author url (none) http://chyingp.cnblogs.com
[?] Required jQuery version (*) 1.9.0
[?] Do you need to make any changes to the above before continuing? (y/N) N

項目目錄結構如下:

//項目目錄結構
-rw-r--r--   1 root        staff  1670  5  9 15:13 CONTRIBUTING.md
-rw-r--r--   1 root        staff   559  5  9 15:13 DemoJQuery.jquery.json
-rw-r--r--   1 root        staff  2184  5  9 15:13 Gruntfile.js
-rw-r--r--   1 root        staff  1053  5  9 15:13 LICENSE-MIT
-rw-r--r--   1 root        staff   543  5  9 15:13 README.md
drwxr-xr-x   5 root        staff   170  5  9 15:13 libs
-rw-r--r--   1 root        staff   423  5  9 15:13 package.json
drwxr-xr-x   4 root        staff   136  5  9 15:13 src
drwxr-xr-x   5 root        staff   170  5  9 15:13 test

從上面的目錄結構,大致可以看出各個目錄、文件的作用,其中我們需要注意的是兩個文件Gruntfile.js、package.json,這兩個文件都需要放在項目跟目錄下。下面會稍微詳細介紹到:

  • Gruntfile.js 項目的Grunt配置信息,包括模塊依賴、任務定義
  • package.json 項目node模塊的依賴信息,主要根據Gruntfile生成

其他其他文件非Grunt項目必須的,可以暫時不去看它

3. 運行Grunt任務

首先運行下面命令,安裝所需node模塊,耐心等候安裝完即可

npm install

輸入下面命令,運行Grunt任務

grunt

輸出如下,done

Running "jshint:gruntfile" (jshint) task
>> 1 file lint free.

Running "jshint:src" (jshint) task
>> 1 file lint free.

...

4. 如何創建package.json

方式一:運行下面命令,通過逐步回答問題的方式創建基礎的package.json文件2```

npm install

方式二:創建空的package.json文件,拷貝下面內容,根據需要進行修改

{  "name": "HelloProj",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-jshint": "~0.1.1",
    "grunt-contrib-nodeunit": "~0.1.2"
  }
}

創建完package.json,運行如下命令,安裝所需插件

npm install

5. 如何安裝Grunt

運行如下命令,安裝最新版的Grunt

npm install grunt --save-dev

6. 創建Gruntfile.js

Gruntfile.js的配置文件格式並不復雜,不過剛開始看的時候會有些雲里霧里,直接拿官方范例進行修改即可。參考鏈接:http://gruntjs.com/sample-gruntfile

module.exports = function(grunt) {

    // 項目配置信息,這里只是演示用,內容隨便填的
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        uglify: {   //壓縮文件
            build: {
                src: 'src/<%= pkg.name %>.js',
                dest: 'build/<%= pkg.name %>.min.js'
            }
        },
        concat: {   //合並文件
            js:{
                src: ['js/moduleA.js', 'js/moduleB.js'],
                dest: 'dist/js/moduleA-moduleB.js'
            },
            css:{
                src:['dist/css/moduleA.css', 'dist/css/moduleB.css'],
                dest: 'dist/css/moduleB.css'
            }
        }
    });

    // 加載uglify插件,完成壓縮任務
    grunt.loadNpmTasks('grunt-contrib-uglify');

    // 加載concat插件,完成文件合並任務
    grunt.loadNpmTasks('grunt-contrib-concat');

    // 默認任務,如果運行grunt命令,且后面沒有指定任務,或為defalut時,運行這個
    grunt.registerTask('default', ['concat', 'uglify']);

};

其實這種方式還是有點麻煩,Grunt團隊還是比較人性化的,針對Gruntfile,還提供了一個單獨的plugin,讓我們免去重復勞動之苦,后面再講

四. imweb_template:自定義模板,創建IMWEB團隊專屬的前端項目骨架

1. 下載Grunt官方示例模板

下載鏈接:https://github.com/gruntjs/grunt-init-jquery

打開下載下來的示例目錄,可以看到如下內容:

-rwxr-xr-x@  1 casperchen  staff   877  2 18 09:00 README.md
-rwxr-xr-x@  1 casperchen  staff   138  2 18 09:00 rename.json
drwxr-xr-x@ 10 casperchen  staff   340  2 18 09:00 root
-rwxr-xr-x@  1 casperchen  staff  3521  2 18 09:00 template.js

簡單介紹下里面內容:

  • template.js 主模板文件,非常重要!里面主要內容有:項目創建時需要回答的問題,項目依賴的Grunt模塊(根據這個生成package.json)
  • rename.json 針對當前模板的目錄/文 件重命名規則,不贅述
  • root/ 重要!在這個目錄里的文件,通過該模板生成項目結構時,會將root目錄下的文件都拷貝到項目中去

2. 創建自定義項目之前

將之前下載的grunt-init-jquery-master重命名為imweb_template,然后就開始我們的模板自定義之旅了!鑒於這塊的內容實在太多,就不詳細講解,直接貼上修改后的文件,可以更為直觀,如需深入了解,可查看相關鏈接:http://gruntjs.com/project-scaffolding

3. 修改imweb_template/template.js

下面是template.js最常包含的一些內容,主要包括:

  • exports.description 模板簡單介紹信息
  • exports.notes 開始回答項目相關問題前,控制台打印的相關信息
  • exports.after 開始回答項目相關問題前,控制台打印的相關信息
  • init.process 項目創建的時候,需要回答的問題
  • init.writePackageJSON 生成package.json,供Grunt、npm使用
  /* 
   * 模板名字
   * https://gruntjs.com/ 
   *
   * 版權信息
   * Licensed under the MIT license.
   */

  'use strict';

  // 模板簡單介紹信息
  exports.description = '創建IMWEB專屬模板,帶文件合並壓縮哦!';

  // 開始回答項目相關問題前,控制台打印的相關信息
  exports.notes = '這段信息出現位置:回答各種項目相關的信息之前 ' +
    '\n\n'+
    '逐個填寫就行,如果不想填的會可以直接enter跳過';

  // 結束回答項目相關問題后,控制台打印出來的信息
  exports.after = '項目主框架已經搭建好了,現在可以運行 ' +
    '\n\n' +
    '1、npm install 安裝項目依賴的node模塊\n'+
    '2、grunt 運行任務,包括文件壓縮、合並、校驗等\n\n';

  // 如果運行grunt-init運行的那個目錄下,有目錄或文件符合warOn指定的模式
  // 則會跑出警告,防止用戶不小心把當前目錄下的文件覆蓋了,一般都為*,如果要強制運行,可加上--force
  // 例:grunt-init --force imweb_template
  exports.warnOn = '*';

  // The actual init template.
  exports.template = function(grunt, init, done) {

    init.process({type: 'IMWEB'}, [
      // 項目創建的時候,需要回答的問題
      init.prompt('name'),
      init.prompt('title'),
      init.prompt('description', 'IMWEB項目骨架'),
      init.prompt('version', '1.0.0'),
      init.prompt('author_name'),
      init.prompt('author_email'),
    ], function(err, props) {

      props.keywords = [];

      // 需要拷貝處理的文件,這句一般不用改它
      var files = init.filesToCopy(props);

      // 實際修改跟處理的文件,noProcess表示不進行處理
      init.copyAndProcess(files, props, {noProcess: 'libs/**'});

      // 生成package.json,供Grunt、npm使用
      init.writePackageJSON('package.json', {
        name: 'IMWEB-PROJ',
        version: '0.0.0-ignored',
        npm_test: 'grunt qunit',

        node_version: '>= 0.8.0',
        devDependencies: {
          'grunt-contrib-jshint': '~0.1.1',
          'grunt-contrib-qunit': '~0.1.1',
          'grunt-contrib-concat': '~0.1.2',
          'grunt-contrib-uglify': '~0.1.1',
          'grunt-contrib-cssmin': '~0.6.0',
          'grunt-contrib-watch': '~0.2.0',
          'grunt-contrib-clean': '~0.4.0',
        },
      });

      // All done!
      done();
    });
  };

4. 修改imweb_template/rename.json

reame.json的作用比較簡單,定義了從root目錄將文件拷貝到實際項目下時的路徑映射關系,以sourcepath: destpath的形式聲明。sourcepath是相對於root的路徑,而destpath則是相對於實際項目的路徑。

ps:當destpath為false時,sourcepath對應的文件不會被拷貝到項目中去

  {
    "src/*.js": "js/*.js",
    "test/test.html": "test/test.html"
  }

5. imweb_template/root 目錄

進入root目錄,可以看到很多文件,其中我們需要關注的有Gruntfile.js、README.md

  • Gruntfile.js 項目的任務配置信息,把基礎任務,如jshint、concat、uglify等配置好即可,其他的各個任務可自行擴充
  • README.md 項目的readme信息,一個調理清晰的readme很重要
-rwxr-xr-x@  1 casperchen  staff  2408  5 10 09:34 Gruntfile.js
-rwxr-xr-x@  1 casperchen  staff   605  2 18 09:00 README.md
drwxr-xr-x   4 casperchen  staff   136  5  9 20:31 css
drwxr-xr-x@  8 casperchen  staff   272  5  9 20:44 js
drwxr-xr-x@  5 casperchen  staff   170  2 18 09:00 libs
drwxr-xr-x@  5 casperchen  staff   170  2 18 09:00 test

6. 修改Gruntfile.js

對Gruntfile.js文件進行修改,如下,熟悉qzmin配置文件的童鞋應該很容易看懂

'use strict';

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
      ' */\n',
    // 任務配置信息

    clean: {  // Grunt任務開始前的清理工作
      files: ['dist']
    },
    concat: { //文件壓縮
      js_and_css: {
        files: {
          // js文件合並
          'dist/js/base.js': ['js/simple.js', 'js/badjs.js', 'js/nohost.js'],
          'dist/js/main.js': ['js/moduleA.js', 'js/moduleB.js' 'js/main.js'],

          // css文件合並
          'dist/css/style.css': ['css/reset.css', 'css/moduleA.css', 'css/moduleB.css']
        }
      }
    },
    uglify: { //js文件壓縮
      js: {
        files: {
          'dist/js/base.min.js': ['dist/js/base.js'],
          'dist/js/main.min.js': ['dist/js/main.js']
        }
      }
    },
    cssmin:{  //CSS文件壓縮
      css: {
        files: {
          'dist/css/style.min.css': ['dist/css/style.css']
        }
      }
    },
    qunit: {  //單元測試,范例中未啟用
      files: ['test/**/*.html']
    },
    jshint: { //文件校驗,范例中未啟用
      gruntfile: {
        options: {
          jshintrc: '.jshintrc'
        },
        src: 'Gruntfile.js'
      },
      src: {
        options: {
          jshintrc: 'js/.jshintrc'
        },
        src: ['js/**/*.js']
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/**/*.js']
      }
    },
    watch: {  //watch任務,實時監聽文件的變化,並進行編譯
      gruntfile: {
        files: '<%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      src: {
        files: '<%= jshint.src.src %>',
        tasks: ['jshint:src', 'qunit']
      },
      test: {
        files: '<%= jshint.test.src %>',
        tasks: ['jshint:test', 'qunit']
      }
    },
  });

  // 加載各種grunt插件完成任務
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // 默認任務
  grunt.registerTask('default', ['clean', 'concat', 'uglify', 'cssmin']);
  //grunt.registerTask('default', ['jshint', 'qunit', 'clean', 'concat', 'uglify']);

};

7. 進入實戰

花了一點時間把IMWEB_PROJ配置好,現在終於到了實際運作階段了。假設我們當前在目錄IMWEB_PROJ下,imweb_template為IMWEB_PROJ目錄當前僅有的內容

drwxr-xr-x@  8 casperchen  staff     272  5 10 00:59 imweb_template

操作步驟可參照**jQuery Plugin示例:如何通過現有模板創建項目、運行Grunt任務**,下面直接上命令

grunt-init --force imweb_template/
npm install
grunt

下面為運行grunt命令后控制台輸出的信息

Running "clean:files" (clean) task
Cleaning "dist"...OK

Running "concat:js_and_css" (concat) task
File "dist/js/base.js" created.
File "dist/js/main.js" created.
File "dist/css/style.css" created.

Running "uglify:js" (uglify) task
File "dist/js/base.min.js" created.
Uncompressed size: 96927 bytes.
Compressed size: 7609 bytes gzipped (34814 bytes minified).
File "dist/js/main.min.js" created.
Uncompressed size: 926 bytes.
Compressed size: 93 bytes gzipped (305 bytes minified).

Running "cssmin:css" (cssmin) task
File dist/css/style.min.css created.

Done, without errors.

可以看到HelloProj目錄下的內容發生了改變,enjoy yourself!

-rw-r--r--   1 root        staff    2398  5 10 14:39 Gruntfile.js
-rw-r--r--   1 root        staff     605  5 10 14:37 README.md
drwxr-xr-x   6 root        staff     204  5 10 14:37 css
drwxr-xr-x   4 root        staff     136  5 10 14:39 dist
drwxr-xr-x@  8 casperchen  staff     272  5 10 00:59 imweb_template
drwxr-xr-x  10 root        staff     340  5 10 14:37 js
drwxr-xr-x   5 root        staff     170  5  9 20:17 libs
drwxr-xr-x  10 casperchen  staff     340  5 10 09:28 node_modules
-rw-r--r--   1 root        staff     458  5 10 14:37 package.json
drwxr-xr-x   4 root        staff     136  5  9 20:17 src
drwxr-xr-x   5 root        staff     170  5  9 20:17 test

五. 關於Grunt、Ant、Mod的對比

上面對Grunt進行了入門介紹,下面簡單說下Ant、aven

  • Ant:做過java開發的童鞋一般都不會陌生,功能很強大,相對Grunt來說更容易入門,配置文件更加友好,據說yahoo前端團隊用的Ant,推薦個不錯的教程:http://www.book.36ria.com/ant/index.html#index
  • Mod:元彥童鞋開發維護,功能很強大,grunt能完成的,Mod都能完成,而且使用更加貼近我們的項目實踐,入門更簡單(有部分原因是因為mod集成了很多常用戶任務,而Grunt早期也是這么做的,不過因為多版本的問題放棄了這種做法),之前聽過元彥的分享,挺不錯的,打算在項目中試用下。github地址:https://github.com/modulejs/modjs

六. 寫在最后

由於時間問題,這里沒有對Grunt、Ant、Mod進行詳細的對比,來個todo吧~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM