前端自動化 模塊化開發

前端自動化 模塊化開發

# Grunt

爲何Grunt

####在前端開發的過程當中,咱們常常會作一些跟功能、代碼無關的重複的事情,好比複製、粘貼、壓縮等等,咱們須要有一個前端自動化的工具。

什麼是Grunt

###免費的小祕書 Grunt官網

怎麼用Grunt

  • 前提:node npm
  • 安裝grunt命令行工具 npm install -g grunt-cli
  • 在工做目錄安裝grunt npm install grunt --save-dev
  • 編輯Gruntfile.js文件
  • 在命令行執行grunt命令

關於Gruntfile.js的內容

格式以下,三步上籃:javascript

module.exports=function(grunt){//包裹函數,全部代碼都在這裏
    grunt.initConfig({});//1配置任務內容
    grunt.loadNpmTasks();//2加載插件
    grunt.registerTask();//3註冊任務
}

initconfig——配置
能夠有多個插件名,每一個的插件名-加載插件名-註冊任務中執行的插件名字要一致。
每一個插件名能夠有多個任務描述,默認所有執行,也能夠指定執行某些任務。css

grunt.initConfig({
    插件名1: {
        任務描述1: {
            //描述xxx
        },
        任務描述2: {
            //描述xxx2
        }
    },
    插件名2: {
        任務描述3: {
            //描述xxx3
        }
    }
});
好比:
uglify: {
    main: {
        //描述
        src:    '1.js',//源文件
        dest:   '1.min.js'//目標文件
    }
}

loadNpmTasks——引入插件html

grunt.loadNpmTasks('grunt-contrib-uglify');
關於grunt的插件。。。

registerTask——註冊任務前端

grunt.registerTask('default', ['uglify']);

關於執行grunt命令

執行的是registerTask註冊的任務java

Tips:

  • 插件基本都能自動建立文件夾
  • 重複執行grunt的話,已經存在的文件會被覆蓋,不報錯,不在後面添加。
  • 通配符 *號 代指全部
  • 通配符 **號 代指全部,包括沒有
  • cwd 描述想要做爲當前文件夾的文件夾路徑
  • expand,分開成一個個的文件,uglify能夠壓縮文件到一個文件,cssmin不能夠
  • ext參數,設置後綴名
  • grunt中的模板 <%= grunt.template.today("yyyy-mm-dd HH-MM-ss") %>, 也能夠放一個常量json進來能夠在模板中使用,避免重複寫,也便於更改
    結合<%= %>使用模板
  • grunt輸出 grunt > log.txt
  • concat 鏈接起來,不壓縮,生成的是一個文件【注意: 順序未知】
  • grunt.file上面有基於nodeJs的fs包裝好的操做文件的方法,好比:grunt.file.readJSON()一般用來讀取json文件,直接轉化爲可用的json
  • copy 帶文件夾層級複製,複製多個文件時,要有expand,不然會報錯
  • watch —— 監測,(自動化)

AMD和CMD

WHY——模塊化編程 vs 原始代碼

轉自阮一峯的博客:最先的時候,全部Javascript代碼都寫在一個文件裏面,只要加載這一個文件就夠了。後來,代碼愈來愈多,一個文件不夠了,必須分紅多個文件,依次加載。下面的網頁代碼,相信不少人都見過。node

<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
<script src="4.js"></script>
<script src="5.js"></script>
<script src="6.js"></script>

這段代碼依次加載多個js文件。隨着代碼愈來愈多,當依賴關係很複雜的時候,代碼的編寫和維護都會變得困難。就算是代碼做者本人,在後期維護起來也會愈來愈吃力,更不敢想多人合做了。jquery

在前端開發過程當中,常常會出現一個單文件幾千行甚至近萬行的狀況。這種大文件,對協做開發、後續維護、性能調優等都不利。模塊化開發初衷是幫助前端開發工程師將大文件拆分紅小文件,能保持小顆粒度的模塊化開發,同時不須要過多考慮依賴關係,讓依賴管理輕鬆自如,將更多精力聚焦在代碼自己的邏輯上。git

HOW——AMD和CMD之爭

先分開介紹,再對比
CMD seaJs 玉伯
玉伯(王保平),淘寶前端類庫 KISSY、前端模塊化開發框架SeaJS、前端基礎類庫Arale的創始人。
玉伯github


CMD規範的定義

  • 懶加載——Execution must be lazy.
  • 一個模塊就是一個文件,代碼的書寫格式以下:define(factory);
  • define 是一個全局函數,用來定義模塊。
  • define 接受 factory 參數,factory 能夠是一個函數,也能夠是一個對象或字符串。npm

    • factory 爲對象、字符串時,表示模塊的接口就是該對象、字符串
    • factory 爲函數時,表示是模塊的構造方法。執行該構造方法,能夠獲得模塊向外提供的接口。factory 方法在執行時,默認會傳入三個參數:require、exports 和 module:

      define(function(require, exports, module) {//參數的順序必須是這樣的
        // 模塊代碼
        //require是獲取其餘模塊的函數
        //exports用來輸出當前模塊
        //module用來輸出當前模塊
        //exports 僅僅是 module.exports 的一個引用。在 factory 內部給 exports 從新賦值時,並不會改變 module.exports 的值。所以給 exports 賦值是無效的,不能用來更改模塊接口。
      });
  • 常用的 API 只有 define, require, exports, module.exports而已,簡單明瞭

seaJs的用法

最簡單的seaJs案例

//主html
<!doctype html>
<html>
    <head>
        <script src="../sea-modules/seajs/seajs/2.2.0/sea.js"></script>
        <script>
            seajs.use("main");//main是main.js,是用define定義的模塊
        </script>
    </head>
    <body>
    頁面內容
    </body>
</html>
//main.js
define(function(require) {
    alert(1);
});
  • 主文件配置參數 seajs.config(); 官方介紹
    seajs.config({//paths 配置能夠結合 alias 配置一塊兒使用,讓模塊引用很是方便。 // 設置路徑,方便跨目錄調用 paths: { 'arale': 'https://a.alipayobjects.com/arale', 'jquery': 'https://a.alipayobjects.com/jquery' }, // 設置別名,方便調用 alias: { 'class': 'arale/class/1.0.0/class', 'jquery': 'jquery/jquery/1.10.1/jquery' } });
  • 主文件使用模塊:seajs.use();——頭(or衣領)API介紹
    // 加載一個模塊 seajs.use('./a'); // 加載一個模塊,在加載完成時,執行回調 seajs.use('./a', function(a) { a.doSomething(); }); // 加載多個模塊,在加載完成時,執行回調 seajs.use(['./a', './b'], function(a, b) { a.doSomething(); b.doSomething(); });
  • 如何定義模塊
    用define來定義模塊。Sea.js 推崇一個模塊一個文件,遵循統一的寫法:
    define(function(require, exports, module) { // 模塊代碼 // exports 被require的對象上的屬性或方法 // 對外提供 foo 屬性 // 在外部使用:require(xx).foo exports.foo = 'bar'; // 對外提供 doSomething 方法 // 在外部使用:require(xx).dosomething exports.doSomething = function() {}; //********************// // module.exports 就是被require的對象 module.exports = { name: 'a', doSomething: function() {}; }; });
  • 如何引用模塊
    require 用來獲取指定模塊的接口。
    define(function(require, exports, module) { // 獲取模塊 a 的接口 var a = require('./a'); // 調用模塊 a 的方法 a.doSomething(); });
  • 總結:用define來定義模塊,一個模塊就是一個文件,在模塊裏用require來引用其餘模塊,在主html文件裏引入seajs後用seajs.use()來開啓js文件。

AMD requireJs

AMD規範的定義

  • 全稱 Asynchronous Module Definition——異步模塊定義規範。
  • 模塊和模塊的依賴能夠被異步加載。
  • 模塊的依賴被異步加載完成之後,工廠函數纔會執行。
  • define 是一個全局函數,用來定義模塊。
  • define 能夠接受多種格式的參數,不過一般能夠是:

    • define(依賴的數組,工廠函數);
    • define(工廠函數);
    • define(一個對象);
  • 一個模塊就是一個文件

requireJs的用法

最簡單的requireJs案例

//主html
<!doctype html>
<html>
    <head>
        <script src="js/require.js"></script>
        <script>
            require(['jquery'], function($){
                alert('jquery loaded');
            });
        </script>
    </head>
    <body>
    頁面內容
    </body>
</html>

or:

//主html
<!doctype html>
<html>
    <head>
        <script src="js/require.js" data-main="js/main.js"></script>
    </head>
    <body>
    // 這樣寫,會異步加載data-main指定的js文件,並把data-main所在的路徑做爲config配置的baseUrl。若是不想異步,就像上面同樣寫。
    頁面內容
    </body>
</html>
//main.js
require(['jquery'], function($){//會在jquery模塊執行完成後,把jquery的輸出作爲參數傳入後面的工廠函數,並執行工廠函數
    alert('jquery loaded');
});
  • 配置: 可使用require.config來設置依賴的模塊的名稱和對應的路徑,也能夠在引入require.js以前定義一個名字爲require的json。兩種方式均可以進行配置。; requireJs配置官方介紹
    <script src="scripts/require.js"></script> <script> require.config({ baseUrl: "/another/path", paths: { "some": "some/v1.0" } }); require( ["some/module", "my/module"], function(someModule, myModule) { //..... } ); </script> 或者是: <script> var require = { baseUrl: "/another/path", paths: { "some": "some/v1.0" } }; </script> <script src="scripts/require.js"></script>
  • 主文件如何使用模塊:從上面已經能夠看到,不一樣於seaJs的使用seajs.use()函數,requireJs使用require()函數來開始執行。
  • 如何定義模塊
    用define來定義模塊:常見的3種狀況

    • define(依賴的數組,工廠函數);

      define(['aModule','bModule'],function(a,b) {
        // 模塊代碼
        // 這個定義的模塊在被調用時,aModule和bModule模塊加載完成以後,纔會以他們的返回值做爲參數執行工廠函數
      });
    • define(工廠函數); 語法糖

      define(function(require, exports, module) {
        // 模塊代碼
        // 這種方式實際上是requireJs的語法糖,能夠在函數裏面用變量接受require過來的模塊(就像seaJs作的那樣),並不真的是同步require那個代碼,而是用的Function.prototype.toString()轉換成數組裏面的格式(怎麼轉換的我們無論)後異步下載後執行回調。
      });
    • define(一個對象);

      define({
          color: "black",
          size: "12"
      });
  • 如何引用模塊
    用require來獲取指定模塊的接口(常見有2種):

    • require(依賴的數組,工廠函數);

      require(['aModule','bModule'],function(a,b) {
        // 模塊代碼
        // aModule和bModule模塊加載完成以後,纔會以他們的返回值做爲參數執行工廠函數
      });
      • require(依賴的數組);
      //只是用來作一個頭,異步引入js後本身不用再作其餘事情
      require(['aModule','bModule']) ;
  • 總結:
    用define來定義模塊,一個模塊就是一個文件。
    define新模塊時用數組提早聲明依賴的模塊。
    在主html文件裏引入requirejs後用require()來開啓js文件。

RequireJS 與 SeaJs 的異同

共同點:

  • 都是模塊加載器,倡導模塊化開發理念
  • 核心價值是讓 JavaScript 的模塊化開發變得簡單天然

不一樣點:

  • RequireJS是異步加載模塊,SeaJs是同步加載模塊
  • RequireJS是提早聲明並加載依賴,SeaJs是按需加載依賴模塊

咱們目前使用的是 RequireJS。

相關文章
相關標籤/搜索