從前端模塊化編程切入想聊聊前端的將來(文末有我想問的問題)

1. JavaScript模塊化簡述👦

1.1 爲何須要模塊化

  1. 沒有模塊化前的項目,經常在一個JS文件中會有不少功能的代碼,這使得文件很大,分類性不強,天然而然不易維護;
  2. 那麼咱們將一個大的JS文件根據必定的規範拆分紅幾個小的文件的話將會便於管理,能夠提升複用性,隨之,能夠起到分治的效果;
  3. 一個複雜的項目確定有不少類似的功能模塊,若是每次都須要從新編寫模塊確定既費時又耗力。一樣,某個功能別人已經造好了輪子,咱們就調來用用就好,這時就要引用別人編寫模塊,引用的前提是要有統一的「打開姿式」,若是每一個人有各自的寫法,那麼確定會亂套,因此會引出模塊化規範;
  4. 如今經常使用的JavaScript模塊化規範有四種: CommonjsAMD , CMD , ES6模塊化 。我的理解,ES6模塊化纔是主流。

1.2 模塊的定義

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

因此,咱們發現學習或創建模塊就是抓住兩點:如何引入模塊?如何暴露模塊?javascript

1.3 模塊化的定義

編碼時是按照模塊一個一個編碼的, 整個項目就是一個模塊化的項目css

1.4 模塊化的優點

  • 方便維護代碼,更好的分離,按需加載
  • 提升代碼複用性
  • 下降代碼耦合度(降偶)
  • 分治思想——模塊化不只僅只是複用,無論你未來是否要複用某段代碼,你都有充分的理由將其分治爲一個模塊。(咱們在開發中有時候常常會出現一個模塊,實則只用到了一次,但仍是抽離出來做爲單個獨立的模塊,這就是分而治之的軟件工程的思想,在前端模塊化一樣適用)

2. 模塊化的進化史👺

2.1 全局Function模式

module1.js (定義一個模塊1)html

//數據
let data1 = 'module one data'

//操做數據的函數
function foo() {
  console.log(`foo() ${data1}`)
}
function bar() {
  console.log(`bar() ${data1}`)
}
複製代碼

module2.js (定義一個模塊2)前端

let data2 = 'module two data';

function foo() {  //與模塊1中的函數衝突了
  console.log(`foo() ${data2}`)
}
複製代碼

test.html (去使用定義好的模塊1和模塊2)java

//同步引入,若函數衝突,則後面覆蓋前面
<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript">
  foo()   //foo() module two data
  bar()   //bar() module one data
</script>
複製代碼

說明:node

  • 全局函數模式: 將不一樣的功能封裝成不一樣的全局函數
  • 問題: Global被污染了, 很容易引發命名衝突(好比模塊中的data1 data2都是全局變量)

2.2 namespace模式

module1.js (定義一個模塊1)jquery

let moduleOne = {
  data: 'module one data',
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}
複製代碼

module2.js (定義一個模塊2)git

let moduleTwo = {
  data: 'module two data',
  foo() {
    console.log(`foo() ${this.data}`)
  },
  bar() {
    console.log(`bar() ${this.data}`)
  }
}
複製代碼

test.html (去使用定義好的模塊1和模塊2)es6

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript">
  moduleOne.foo()   //foo() module one data
  moduleOne.bar()   //bar() module one data

  moduleTwo.foo()  //foo() module two data
  moduleTwo.bar()  //bar() module two data

  moduleOne.data = 'update data' //能直接修改模塊內部的數據
  moduleOne.foo()  //foo() update data
</script>
複製代碼

說明:github

  • namespace模式: 簡單對象封裝
  • 做用: 減小了全局變量 (如兩個模塊的 data 都不是全局變量了,而是對象的某一個屬性 )
  • 問題: 不安全,能夠直接修改模塊內部的數據

2.3 IIFE模式

module1.js (定義一個模塊1)

(function (window) {
  //數據
  let data = 'IIFE module data'

  //操做數據的函數
  function foo() { //用於暴露的函數
    console.log(`foo() ${data}`)
  }

  function bar() {//用於暴露的函數
    console.log(`bar() ${data}`)
    otherFun() //內部調用
  }

  function otherFun() { //內部私有的函數
    console.log('privateFunction go otherFun()')
  }

  //暴露foo函數和bar函數
  window.moduleOne = {foo, bar}
})(window)
複製代碼

test.html (去使用定義好的模塊1)

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript">
  moduleOne.foo()  //foo() IIFE module data
  moduleOne.bar()  //bar() IIFE module data    privateFunction go otherFun()
  //moduleOne.otherFun()  //報錯,moduleOne.otherFun is not a function
  console.log(moduleOne.data) //undefined 由於我暴露的moduleOne對象中無data
  moduleOne.data = 'xxxx' //不是修改的模塊內部的data,而是在moduleOne新增data屬性
  moduleOne.foo() //驗證內部的data沒有改變  仍是會輸出 foo() IIFE module data
</script>
複製代碼

說明:

  • IIFE模式: 匿名函數自調用(閉包)
  • IIFE : immediately-invoked function expression(當即調用函數表達式)
  • 做用: 數據是私有的, 外部只能經過暴露的方法操做
  • 問題: 若是當前這個模塊依賴另外一個模塊怎麼辦? 見下面IIFE加強版的(模塊依賴於jQuery)

2.4 IIFE模式加強

引入jquery到項目中

module1.js (定義一個模塊1)

(function (window,$) {
  //數據
  let data = 'IIFE Strong module data'

  //操做數據的函數
  function foo() { //用於暴露的函數
    console.log(`foo() ${data}`)
    $('body').css('background', 'red')
  }

  function bar() {//用於暴露的函數
    console.log(`bar() ${data}`)
    otherFun() //內部調用
  }

  function otherFun() { //內部私有的函數
    console.log('privateFunction go otherFun()')
  }

  //暴露foo函數和bar函數
  window.moduleOne = {foo, bar}
})(window,jQuery)
複製代碼

test.html (去使用定義好的模塊1)

<!--引入的js必須有必定順序-->
<script type="text/javascript" src="jquery-1.10.1.js"></script>
<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript">
  moduleOne.foo()  //foo() IIFE Strong module data  並且頁面背景會變色
</script>
複製代碼

說明:

  • IIFE模式加強 : 引入依賴

  • 這就是現代模塊實現的基石。其實很像了,有引入和暴露兩個方面。

  • 存在的問題:一個頁面須要引入多個JS的問題

    <script type="text/javascript" src="module1.js"></script>
    <script type="text/javascript" src="module2.js"></script>
    <script type="text/javascript" src="module3.js"></script>
    <script type="text/javascript" src="module4.js"></script>
    複製代碼

    請求過多:一個script標籤就是一次請求
    依賴模糊:看不出來誰依賴着誰?哪些模塊是有依賴關係的,很難看出來。
    難以維護:內部依賴關係混亂也就難以維護啦

3. 現代模塊化方案🏆

3.1 CommonJS

CommonJS 是服務器端模塊的規範,Node.js 就是採用了這個規範。但目前也可用於瀏覽器端,須要使用 Browserify 進行提早編譯打包。

CommonJS 模塊化的引入方式使用require ; 暴露的方式使用module.exportsexports

COMMONJS

CommonJS基於服務器端

  1. 下載安裝node.js

  2. 建立項目結構

    |-modules
      |-module1.js
      |-module2.js
      |-module3.js
    |-index.js
    複製代碼
  3. 模塊化編碼 module1.js (定義一個模塊1)
    定義一個沒有依賴的模塊,此模塊用來定義配置常量

    const newsUrl = 'http://localhost:3000/news';
    const commentsUrl = 'http://localhost:3000/comments';
    //經過exports暴露出去
    exports.newsUrl = newsUrl;
    exports.commentsUrl = commentsUrl;
    複製代碼

    module2.js(定義一個模塊2)
    定義一個有依賴的模塊(這個模塊2又依賴模塊1,故須要引入模塊1),用來模擬發送請求獲取數據的一個模塊

    //引入依賴
    const m1 = require('./module1');
    
    //定義發送請求的方法
    function getNews(url) {
      console.log('發送請求獲取數據,請求地址爲:' + url);
      return 'newsData';
    }
    function getComments(url) {
      console.log('發送請求獲取數據,請求地址爲:' + url);
      return 'commentsData';
    }
    
    const newsData = getNews(m1.newsUrl);
    const commentsData = getComments(m1.commentsUrl);
    
    //經過module.exports暴露模塊
    module.exports = {
      newsData,
      commentsData
    }
    複製代碼

    module3.js(定義一個模塊3)
    定義一個模塊,用來顯示用戶數據

    //定義顯示內容的方法
    function showData(data) {
      console.log('要顯示的信息:' + data);
    }
    //經過module.exports暴露模塊
    module.exports = showData;
    複製代碼

    index.js (主模塊,用來啓動整個項目)
    須要引入全部須要啓動的模塊

    const m2 = require('./modules/module2');
    const showData = require('./modules/module3');
    
    showData(m2.newsData);
    showData(m2.commentsData)
    複製代碼

    結果輸出:

    發送請求獲取數據,請求地址爲:http://localhost:3000/news
    發送請求獲取數據,請求地址爲:http://localhost:3000/comments
    要顯示的信息:newsData
    要顯示的信息:commentsData
    複製代碼
  4. 經過node運行index.js
    執行命令: node index.js

CommonJS基於瀏覽器端

  1. 建立項目結構

    |-dist    //打包生成文件的目錄
    |-src    //源碼所在的目錄
      |-module1.js
      |-module2.js
      |-module3.js
      |-index.js //應用主源文件(只需打包主模塊)
    |-index.html //引入dist裏面的打包好的js文件,[須要在html文件中引入就是基於瀏覽器端咯]
    複製代碼
  2. 下載browserify
    全局安裝下載: npm install browserify -g

  3. 定義模塊代碼 module1.js
    定義一個沒有依賴的模塊,此模塊用來定義配置常量

    //定義配置常量
    const newsUrl = 'http://localhost:3000/news';
    const commentsUrl = 'http://localhost:3000/comments';
    //暴露出去
    exports.newsUrl = newsUrl;
    exports.commentsUrl = commentsUrl;
    複製代碼

    module2.js
    定義一個有依賴的模塊(依賴模塊1),用來模擬發送請求獲取數據的一個模塊

    //引入依賴
    const m1 = require('./module1');
    
    //定義發送請求的方法
    function getNews(url) {
      console.log('發送請求獲取數據,請求地址爲:' + url);
      return 'newsData';
    }
    function getComments(url) {
      console.log('發送請求獲取數據,請求地址爲:' + url);
      return 'commentsData';
    }
    
    const newsData = getNews(m1.newsUrl);
    const commentsData = getComments(m1.commentsUrl);
    
    //暴露模塊
    module.exports = {
      newsData,
      commentsData
    }
    複製代碼

    module3.js
    定義一個模塊,用來顯示用戶數據

    //定義顯示內容的方法
    function showData(data) {
      console.log('要顯示的信息:' + data);
    }
    //暴露模塊
    module.exports = showData;
    複製代碼

    index.js (應用的主模塊JS)
    主模塊,用來啓動整個項目。須要引入全部須要啓動的模塊。

    const m2 = require('./module2');
    const showData = require('./module3');
    
    showData(m2.newsData);
    showData(m2.commentsData);
    複製代碼

    打包處理index.js
    執行命令:browserify src/index.js -o dist/bundle.js
    src/index.js 表示就是src目錄下的index主模塊
    -o 表示 outfile
    dist/bundle.js 表示打包處理結果生成到dist/bundle.js

    在主頁面index.html中使用引入:
    直接引入主模塊就能夠了,由於主模塊上就有各類依賴,他會自動去解析打包處理。

    <script type="text/javascript" src="dist/bundle.js"></script>
    複製代碼

    結果輸出:

    發送請求獲取數據,請求地址爲:http://localhost:3000/news
    發送請求獲取數據,請求地址爲:http://localhost:3000/comments
    要顯示的信息:newsData
    要顯示的信息:commentsData
    複製代碼

    若是直接引用未打包處理的index.js 則會報錯:

    引入方式:<script src="src/index.js"></script>
    報錯信息爲:Uncaught ReferenceError: require is not defined-->
    複製代碼

    咱們如今是基於瀏覽器端的使用。只有在node環境下才能夠直接使用未打包的index.js引入,由於在node環境下有exportsmodularrequire 這些全局方法。node函數中是這樣的:function (exports, require, module, filename, dirname) {},因此咱們引入一個browserify就會自動配置好這些參數。

完全說明白module.exportsexports的區別:

nodejs中,module是一個全局變量,相似於在瀏覽器端的window也是一個全局變量同樣的道理。

module.exports 初始的時候置爲{}, exports也指向這個空對象。

內部的代碼實現是:

var module = {
  id: 'xxxx', // 我總得知道怎麼去找到他吧
  exports: {}, // exports 就是個空對象
}

var exports = module.exports;  //exports是對module.exports的引用
//也就是exports如今指向的內存地址和module.exports指向的內存地址是同樣的
複製代碼

上面的代碼能夠看出咱們日常使用的exports是對module.exports的一個引用,二者都是指向同一個對象。

用一句話來講明就是,模塊的require(引入)能看到的只有module.exports這個對象,它是看不到exports對象的,而咱們在編寫模塊時用到的exports對象實際上只是對module.exports的引用。(exports = module.exports)。

咱們可使用exports.a = ‘xxx’exports.b = function () {} 添加方法或屬性,本質上它也添加在module.exports所指向的對象身上。可是你不能直接exports = { a: 'xxx'} 這樣子的意義就是將exports從新指向新的對象!它和module.exports就不是指向同一個對象,也就這二者已經失去了關係,而nodejsrequire(引入)能看到的是module.exports指向的對象。

module.exports
故,咱們通常都會直接使用 module.exports
再舉例說明二者區別:

function foo() {
  console.log('foo');
}

function bar() {
  console.log('bar');
}
複製代碼

想要將這兩個函數暴露出去,能夠直接使用exports

exports.foo = foo;
exports.bar = bar;
複製代碼

也能夠對module.exports賦值

module.exports = {
  foo: foo,
  bar: bar
}
複製代碼

可是不能直接對exports賦值

// 錯誤
exports = {
  foo: foo,
  bar: bar
}
複製代碼

由於這樣作僅僅改變了exports的引用,而不改變module.exports。 好,劇終。這個問題講明白了吧。

總結CommonJS
特色:同步加載,有緩存
用法:(抓住引入和暴露)

  • 暴露模塊
    exports
    module.exports
  • 引入模塊
    require(路徑參數)
    路徑: 自定義模塊:路徑必須以./或者 ../開頭
    第三方模塊/內置模塊/核心模塊:路徑直接使用模塊名稱

主要是在服務器端使用的,可是也能在瀏覽器端運行,須要藉助browserify進行編譯。

3.2 AMD

CommonJS規範加載模塊是同步的,也就是說,只有加載完成,才能執行後面的操做。因爲Node.js主要用於服務器編程,模塊文件通常都已經存在於本地硬盤,因此加載起來比較快,因此同步加載沒有問題。可是若是是瀏覽器端,同步加載很容易阻塞,這時候AMD規範就出來了。AMD規範則是非同步加載模塊,容許指定回調函數。故瀏覽器端通常會使用AMD規範。

AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出 。

AMD

  1. 下載require.js, 並引入

    官網: http://www.requirejs.cn/
    github : https://github.com/requirejs/requirejs
    require.js導入項目: js/libs/require.js

  2. 建立項目結構

    |-libs
      |-require.js
    |-modules
      |-alerter.js
      |-dataService.js
    |-main.js
    |-index.html
    複製代碼
  3. 定義require.js的模塊代碼
    dataService.js (定義一個無依賴的模塊)

    define(function () {
      let msg = 'hello world lyuya';
      function dataServer() {
        return msg.toUpperCase();
      }
      //暴露這個模塊
      return dataServer;
    });
    複製代碼

    alerter.js (定義一個有依賴的模塊)
    定義方法:define(['模塊1', '模塊2', '模塊3'], function (m1, m2,m3) {}) 注意先後一一對應

    //必定要注意一一對應,前面有,後面必定要有,別忘記後面的傳參
    define(['dataServer'],function (dataServer) {
      let msg = dataServer();
      function alerter() {
        alert(msg);
      }
      return alerter;
    });
    複製代碼
  4. 應用主(入口):main.js (主模塊)

    //配置模塊的路徑
    requirejs.config({
      baseUrl:'./',  //配置全部引入模塊的公共路徑(基本路徑)
      //模塊標識名與模塊路徑映射
      paths : {
        // 模塊名稱(必定要與引入的模塊名稱一一對應): 模塊的路徑
        dataServer: 'modular/dataServer',  
        //必定不能寫文件的後綴名,它會自動補全
        alerter: 'modular/alerter',
        //庫/框架本身實現模塊化的功能,定義了暴露模塊的名稱
        jquery: 'libs/jquery-1.10.1'
      }
    })
    
    //主模塊,下面requirejs能夠用require代替,require是異步可緩存的
    requirejs(['alerter','jquery'],function (alerter,$) {
      alerter();
      $('body').css('background','pink')
    });
    複製代碼
  5. 在頁面index.html中使用模塊

    <!--src引入requirejs模塊去用這個模塊解析主模塊-->
    
    <script data-main="./main" src="./libs/require.js"></script>
    複製代碼

總結requireJS
特色:異步加載,有緩存
用法:(抓住引入和暴露)

  • 暴露模塊
    在模塊內部使用return
  • 定義模塊
    define(['模塊名'], function (模塊暴露內容) {})
    require(['模塊名'], function (模塊暴露內容) {})
    在模塊內部可使用require定義異步模塊
  • 主模塊:
    requirejs.config({}) 配置使用的模塊路徑
    requirejs(['模塊名'], function (模塊暴露內容) {})
  • html文件引入script標籤
    <script data-main='app.js' src='require.js'></script>

AMD(通用模塊定義)主要是在瀏覽器使用的。

3.3 CMD

CMD是根據CommonJS和AMD基礎上提出的。
CMD(通用模塊定義)和AMD(異步模塊定)是比較類似的。
RequireJS 遵循的是 AMD(異步模塊定義)規範,SeaJS 遵循的是 CMD (通用模塊定義)規範。
seaJS 是國人阿里創建的,表明着海納百川之意。

在這裏插入圖片描述

  1. 下載sea.js, 並引入

    官網: http://seajs.org/
    github : https://github.com/seajs/seajs
    sea.js導入項目: libs/sea.js

  2. 建立項目結構

    |-libs 
      |-sea.js 
    |-modules 
      |-module1.js 
      |-module2.js 
      |-module3.js 
      |-module4.js 
    |-main.js 
    |-index.html
    複製代碼
  3. 定義sea.js的模塊代碼
    module1.js

    define(function (require, exports, module) {
        /* require: 引入依賴模塊 exports: 暴露模塊 module: 暴露模塊 */
        const msg = 'moduleone';
        function getMsg() {
          console.log('module1 getMsg() ' + msg);
          return msg;
        }
        //暴露模塊
        module.exports = getMsg;
      })
    複製代碼

    module2.js

    define(function (require, exports, module) {
        exports.msg1 = 'lyuya';
        exports.msg2 = 'hello';
      })
    複製代碼

    module3.js

    define(function (require, exports, module) {
        //同步引入模塊
        const getMsg = require('./module1');
    
        let msg = getMsg();
    
        msg = msg.toUpperCase();
    
        module.exports = {
          msg
        }
    
      })
    複製代碼

    module4.js

    //異步引入模塊
        require.async('./module2', function (m2) {
          console.log(m2.msg1, m2.msg2);
        })
        console.log('module4執行了~~~');
      })
    複製代碼

    main.js :主(入口)模塊

    define(function (require) {
        const m3 = require('./module3');
        require('./module4');
    
        console.log(m3.msg);
      })
    複製代碼

    index.html:

    <script type="text/javascript" src="libs/sea.js"></script> 
    <script type="text/javascript"> seajs.use('./modules/main') </script>
    複製代碼

    結果輸出:

    module1 getMsg() moduleone      =====module1.js:12
    
     module4執行了~~~               =====module4.js:9 
    
     MODULEONE                       =====main.js:9
    
     lyuya hello                 =====module4.js:7 
    複製代碼

總結seaJS

特色:異步加載,有緩存
用法:

  • 定義模塊
    define(function (require, exports, module) {})

  • 引入模塊
    同步加載require()
    異步加載require.async(['模塊名'], function (模塊暴露內容) {})

  • 暴露模塊
    exports
    module.exports

  • html文件引入script標籤
    <script src='sea.js'></script>
    <script>seajs.use('app.js')</script>

seajsrequirejs同樣主要在瀏覽器中使用。其實這兩個通常都不多使用。用的比較多的是commonjs 和立刻要介紹的es6模塊化

3.4 ES6模塊化⭐⭐

ES6模塊化的出現,給前端更大的方便。旨在成爲瀏覽器和服務器通用的模塊解決方案,但仍是主要專門針對瀏覽器端。其模塊功能主要由兩個命令構成:exportimport。如今不少項目都在使用ES6模塊化規範。

ES6模塊化

  1. 定義package.json文件

  2. 安裝babel-cli, babel-preset-es2015browserify

    npm install babel-cli browserify -g
    npm install babel-preset-es2015 --save-dev
    preset 預設(將es6轉換成es5的全部插件打包)

  3. 定義.babelrc文件

    {
     "presets": ["es2015"]
    }
    複製代碼
  4. 編碼
    module1.js
    分別暴露 後面須要完整的定義(變量或函數定義)

    export function foo() {
       console.log('module1 foo()');
     }
     export function bar() {
       console.log('module1 bar()');
     }
     export const DATA_ARR = [1, 3, 5, 1]
    複製代碼

    module2.js
    統一暴露 暴露的是一個對象,要暴露的數據添加爲對象的屬性/方法

    let data = 'module2 data'
     
     function fun1() {
       console.log('module2 fun1() ' + data);
     }
     
     function fun2() {
       console.log('module2 fun2() ' + data);
     }
     
     export {fun1, fun2}
    複製代碼

    module3.js
    靜默暴露 只能暴露一個內容,默認暴露的本質:定義了default變量,將後面的值賦值給default變量,暴露出去

    export default {
       name: 'Tom',
       setName: function (name) {
         this.name = name
       }
     }
    複製代碼

    app.js 主模塊用import引入模塊

    import {foo, bar} from './module1'
     import {DATA_ARR} from './module1'
     import {fun1, fun2} from './module2'
     import person from './module3'
    
     import $ from 'jquery'  //引入第三方jQuery模塊 npm install jquery@1 --save
    
     $('body').css('background', 'red')
    
     foo()
     bar()
     console.log(DATA_ARR);
     fun1()
     fun2()
    
     person.setName('JACK')
     console.log(person.name);
    複製代碼

    輸出結果:

    module1 foo()
     module1 bar()
     [1, 3, 5, 1]
     module2 fun1() 
     module2 fun2() 
     JACK
    複製代碼
  5. 編譯
    使用Babel將ES6編譯爲ES5代碼(但包含CommonJS語法):babel src -d build
    使用Browserify編譯js:browserify build/app.js -o dist/bundle.js

  6. 在頁面index.html中引入測試
    <script type="text/javascript" src="lib/bundle.js"></script>

總結ES6
特色:動態引入(按需加載),沒有緩存
用法:(抓住引入和暴露)

  • 引入模塊使用import
    • 對於統一暴露/分別暴露
      import {模塊暴露的內容} from '模塊路徑';import * as m1 from './module1'
      這二者暴露的本質是對象,接收的時候只能以對象的解構賦值的方式來接收值
    • 對於默認暴露
      直接使用import 模塊暴露的內容 from '模塊路徑'
      默認暴露,暴露任意數據類型,暴露什麼數據類型,接收什麼數據類型
  • 暴露模塊使用export
    • 分別暴露 (基本不用)
    • 統一暴露 (暴露多個內容)
    • 默認暴露 (暴露單個內容)

主要是用在瀏覽器,服務器端也使用。可是如今瀏覽器和服務器均不支持ES6的模塊化語法,因此要藉助工具來編譯運行

  • babel 將ES6 - ES5 (ES6的模塊化語法 編譯成commonjs
  • browserifycommonjs語法編譯成能讓瀏覽器識別的語法

3. 模塊化的擴展閱讀

前端模塊化開發那點歷史
Javascript模塊化編程@阮一峯
知乎專欄 | AMD和CMD的區別

4. 本片我想說的話 🙈 🙈

既然說到模塊化,其實我更想說說模塊化與組件化。這兩個概念在前端領域已經十分廣泛。

先有模塊化後有組件化。組件化是創建在模塊化思想上的一次演進,一個變種。因此,咱們會在軟件工程體系中看過一句話:模塊化是組件化的基石。

組件化和模塊化的思想都是分而治之的思想。但仍是有細小的區分,他們的側重點有所不一樣。

組件化更加傾向於UI層面上,是一個能夠獨立展現內容的「積木」,好比一個頁面的頭部組件,包含結構HTML、樣式CSS、邏輯JS、以及靜態資源圖片組合一個集合體。一個頁面是由衆多組件組成的,就像由衆多「積木」搭成的「城堡」同樣; 模塊化更加傾向於功能或者數據的封裝,通常由幾個組件或1個組件構成的帶有必定功能的集合體;

引用一下@張雲龍「👈大神」對組件化的理解:

組件化的理解JS
就如上圖的這個 title組件,包含告終構HTML、樣式CSS、邏輯JS、以及靜態資源圖片,每每組件的組成就是以上四個方面。這個 header文件夾咱們能夠拿到其餘項目中使用,它具備能夠獨立展現內容的特色。

結合前面提到的模塊化開發,整個前端項目能夠劃分爲這麼幾種開發概念:

前端模塊化開發
那麼它們之間的關係以下圖所示,一個 應用由多個下圖的 頁面組成。一個 頁面由多個 組件組合。組件中可依賴JS模塊。

組件與模塊之間的區別
因此,前端開發如今不只僅只是別人說的「畫畫頁面實現點效果」的職位,它是實現軟件的圖形用戶界面(Graphical User Interface,簡稱GUI),是一名軟件工程師。如今前端開發都是基於模塊化和組件化的開發,能夠說算是工程化的項目了。從單頁面(SPA)的應用就能夠看出JavaScript大大改善了Web應用的用戶體驗。從谷歌提出PWA(Progressive Web Apps)就能夠看出前端在領域的成長。

不只僅如此,多終端也已經成爲時下以及將來的一個必然趨勢,移動端、PC端、觸摸屏、智能設備、物聯網等等,相信前端在跨端的領域下確定會有更好的解決方案。

可是,若是從整個軟件工程來看,咱們就會意識到一個慘痛的事實:前端工程師在整個系統工程中的地位過低了。前端是處於系統軟件的上游(用戶入口),所以沒有其餘系統會來調取前端系統的服務。然後端它在軟件開發中處於下游,後端一方面要爲前端提供接口服務,一方面要向中後臺以及數據層索取服務,對接層次會更多,地位也就更高了。由此致使,感受每次需求評估前端每每是最後一道坎,由於上游依託下游,就只能是下游先行了,總體上就會感受前端對業務的參與度過低了。

甚至,2019了。如今仍是有不少團隊會把前端開發歸類爲產品或設計崗位底下,嗯,我很差說什麼,唉···。

你在的公司前端的組織架構是腫麼樣吶??? 🙋🙋

前端將來必定不會差,就像在人工智能和大數據領域下,不止於前端,前端徹底能夠融合和細化下去。

引用一位螞蟻夥伴的話來講:前兩年的前端主要矛盾是日益爆發的前端新技術同前端程序猿學不動之間的矛盾,而如今主要矛盾發生了變化,變成了前端日益增加的工程地位訴求同前端工程侷限性之間的矛盾。(這人考研政治絕對高分!)

相學長|爲前端工程之崛起而編程

在這樣新的矛盾下,咱們就要化被動爲主動,改接受爲影響。

好啦,好好學習吧,作一個π型人。打鐵還需自身硬。Confidence~🙌

今天是2019年3月8日,農曆二月二(龍擡頭),星期五,陰陰天氣。我在深圳祝福各位女同胞唷節日快樂永遠美麗,祝福男同胞單身幸福~biubiu💖💗💙💚💛💜💝

去泡個澡,今晚早點休息,明天還要去北京大學深圳醫院。

此文檔做者:呂涯 CSDN主頁:https://blog.csdn.net/LY_code 掘金主頁:https://juejin.im/user/5b220d93e51d4558e03cb948 如有錯誤,及時提出,一塊兒學習,共同進步。謝謝。 😝😝😝

相關文章
相關標籤/搜索