前端工程化篇

1.模塊化機制

1.什麼是模塊?

  • 將一個複雜的程序依據必定的規則(規範)封裝成幾個塊(文件), 並進行組合在一塊兒
  • 塊的內部數據與實現是私有的, 只是向外部暴露一些接口(方法)與外部其它模塊通訊

2.模塊化的進化過程

  • 全局function模式 : 將不一樣的功能封裝成不一樣的全局函數javascript

    • 編碼: 將不一樣的功能封裝成不一樣的全局函數
    • 問題: 污染全局命名空間, 容易引發命名衝突或數據不安全,並且模塊成員之間看不出直接關係
    function m1(){
      //...
    }
    function m2(){
      //...
    }
    複製代碼
  • namespace模式 : 簡單對象封裝css

    • 做用: 減小了全局變量,解決命名衝突
    • 問題: 數據不安全(外部能夠直接修改模塊內部的數據)
    let myModule = {
      data: 'www.baidu.com',
      foo() {
        console.log(`foo() ${this.data}`)
      },
      bar() {
        console.log(`bar() ${this.data}`)
      }
    }
    myModule.data = 'other data' //能直接修改模塊內部的數據
    myModule.foo() // foo() other data
    複製代碼

    這樣的寫法會暴露全部模塊成員,內部狀態能夠被外部改寫。html

  • IIFE模式:匿名函數自調用(閉包)前端

    • 做用: 數據是私有的, 外部只能經過暴露的方法操做
    • 編碼: 將數據和行爲封裝到一個函數內部, 經過給window添加屬性來向外暴露接口
    • 問題: 若是當前這個模塊依賴另外一個模塊怎麼辦?
    // index.html文件
    <script type="text/javascript" src="module.js"></script>
    <script type="text/javascript"> myModule.foo() myModule.bar() console.log(myModule.data) //undefined 不能訪問模塊內部數據 myModule.data = 'xxxx' //不是修改的模塊內部的data myModule.foo() //沒有改變 </script>
    複製代碼
    // module.js文件
    (function(window) {
      let data = 'www.baidu.com'
      //操做數據的函數
      function foo() {
        //用於暴露有函數
        console.log(`foo() ${data}`)
      }
      function bar() {
        //用於暴露有函數
        console.log(`bar() ${data}`)
        otherFun() //內部調用
      }
      function otherFun() {
        //內部私有的函數
        console.log('otherFun()')
      }
      //暴露行爲
      window.myModule = { foo, bar } //ES6寫法
    })(window)
    複製代碼

    最後獲得的結果:java

    1250759466-5c1c3943927e8_fix732.png

  • IIFE模式加強 : 引入依賴jquery

這就是現代模塊實現的基石webpack

// module.js文件
(function(window, $) {
  let data = 'www.baidu.com'
  //操做數據的函數
  function foo() {
    //用於暴露有函數
    console.log(`foo() ${data}`)
    $('body').css('background', 'red')
  }
  function bar() {
    //用於暴露有函數
    console.log(`bar() ${data}`)
    otherFun() //內部調用
  }
  function otherFun() {
    //內部私有的函數
    console.log('otherFun()')
  }
  //暴露行爲
  window.myModule = { foo, bar }
})(window, jQuery)
複製代碼
// index.html文件
  <!-- 引入的js必須有必定順序 -->
  <script type="text/javascript" src="jquery-1.10.1.js"></script>
  <script type="text/javascript" src="module.js"></script>
  <script type="text/javascript"> myModule.foo() </script>
複製代碼

上例子經過jquery方法將頁面的背景顏色改爲紅色,因此必須先引入jQuery庫,就把這個庫看成參數傳入。這樣作除了保證模塊的獨立性,還使得模塊之間的依賴關係變得明顯。web

3. 模塊化的好處

  • 避免命名衝突(減小命名空間污染)
  • 更好的分離, 按需加載
  • 更高複用性
  • 高可維護性

4. 引入多個<script>後出現出現問題

  • 請求過多

首先咱們要依賴多個模塊,那樣就會發送多個請求,致使請求過多編程

  • 依賴模糊

咱們不知道他們的具體依賴關係是什麼,也就是說很容易由於不瞭解他們之間的依賴關係致使加載前後順序出錯。瀏覽器

  • 難以維護

以上兩種緣由就致使了很難維護,極可能出現牽一髮而動全身的狀況致使項目出現嚴重的問題。 模塊化當然有多個好處,然而一個頁面須要引入多個js文件,就會出現以上這些問題。而這些問題能夠經過模塊化規範來解決,下面介紹開發中最流行的commonjs, AMD, ES6, CMD規範。

5.模塊化規範

  • 1.CommonJS

    • 在服務器端,模塊的加載是運行時同步加載的;在瀏覽器端,模塊須要提早編譯打包處理。
    • 特色
      • 全部代碼都運行在模塊做用域,不會污染全局做用域。
      • 模塊能夠屢次加載,可是隻會在第一次加載時運行一次,而後運行結果就被緩存了,之後再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。
      • 模塊加載的順序,按照其在代碼中出現的順序。
    • 基本語法
      • 暴露模塊:module.exports = value或exports.xxx = value
      • 引入模塊:require(xxx),若是是第三方模塊,xxx爲模塊名;若是是自定義模塊,xxx爲模塊文件路徑
    • 模塊的加載機制
      • CommonJS模塊的加載機制是,輸入的是被輸出的值的拷貝。也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值。
  • 2.AMD

    • AMD規範基本語法

    定義暴露模塊:

    //定義沒有依賴的模塊
    define(function(){
       return 模塊
    })
    複製代碼
    //定義有依賴的模塊
    define(['module1', 'module2'], function(m1, m2){
       return 模塊
    })
    複製代碼

    引入使用模塊:

    require(['module1', 'module2'], function(m1, m2){
       使用m1/m2
    })
    複製代碼

    AMD模塊定義的方法很是清晰,不會污染全局環境,可以清楚地顯示依賴關係。

  • 3.CMD

    • CMD規範基本語法

      定義暴露模塊:

    //定義沒有依賴的模塊
    define(function(require, exports, module){
      exports.xxx = value
      module.exports = value
    })
    複製代碼
    //定義有依賴的模塊
    define(function(require, exports, module){
      //引入依賴模塊(同步)
      var module2 = require('./module2')
      //引入依賴模塊(異步)
        require.async('./module3', function (m3) {
        })
      //暴露模塊
      exports.xxx = value
    })
    複製代碼
    • 引入使用模塊:
    define(function (require) {
      var m1 = require('./module1')
      var m4 = require('./module4')
      m1.show()
      m4.show()
    })
    複製代碼
  • 4.ES6模塊化

    • ES6模塊化語法

      • export命令用於規定模塊的對外接口,import命令用於輸入其餘模塊提供的功能。
      /** 定義模塊 math.js **/
      var basicNum = 0;
      var add = function (a, b) {
          return a + b;
      };
      export { basicNum, add };
      /** 引用模塊 **/
      import { basicNum, add } from './math';
      function test(ele) {
          ele.textContent = add(99 + basicNum);
      }
      複製代碼

      export default命令,爲模塊指定默認輸出。

      // export-default.js
      export default function () {
        console.log('foo');
      }
      
      // import-default.js
      import customName from './export-default';
      customName(); // 'foo'
      複製代碼
    • ES6 模塊與 CommonJS 模塊的差別

      它們有兩個重大差別:

      • ① CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。

      • ② CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口。

6.總結

  • CommonJS規範主要用於服務端編程,加載模塊是同步的,這並不適合在瀏覽器環境,由於同步意味着阻塞加載,瀏覽器資源是異步加載的,所以有了AMD CMD解決方案。
  • AMD規範在瀏覽器環境中異步加載模塊,並且能夠並行加載多個模塊。不過,AMD規範開發成本高,代碼的閱讀和書寫比較困難,模塊定義方式的語義不暢。
  • CMD規範與AMD規範很類似,都用於瀏覽器編程,依賴就近,延遲執行,能夠很容易在Node.js中運行。不過,依賴SPM 打包,模塊的加載邏輯偏重
  • ES6 在語言標準的層面上,實現了模塊功能,並且實現得至關簡單,徹底能夠取代 CommonJS 和 AMD 規範,成爲瀏覽器和服務器通用的模塊解決方案。

2.Tree-Shaking

定義:

雖然依賴了某個模塊,但其實只使用其中的某些功能。經過 tree-shaking,將沒有使用的模塊搖掉,這樣來達到刪除無用代碼的目的。

具體能夠看這遍文章

3.uglify原理

    1. 將code轉換成AST
    1. 將AST進行優化,生成一個更小的AST
    1. 將新生成的AST再轉化成code

4.webpack

5.前端微服務

多是你見過最完善的微前端解決方案

相關文章
相關標籤/搜索