原文地址: https://github.com/HolyZheng/...
模塊化主要體現的是一種分而治之的思想。分而治之是軟件工程的重要思想,是複雜系統開發和維護的基石。模塊化則是前端最流行的分治手段。javascript
分而治之:將一個大問題分解成多個較爲獨立的與原問題性質相同的小問題,將全部的小問題的解答組合起來便可獲得大問題的答案。
模塊化的工程意義首先在於分治的思想,對功能進行分治,有利於咱們的維護;其次是複用,有利於咱們的開發。css
最先的時期,前端的模塊化方案很簡單,就是經過命名空間,或module模式模擬類提供私有和共有方法來實現模塊化,可是這些模塊都不是以文件爲單位,而是以對象爲單位。前端
var namespace = { methodOne: function () { /* ...*/ }, methodTwo: function () { /* ...*/ } } namespace.methodOne()
var module = (function() { var _private = 'something', var getData = function () { console.log(_private) } return { getData: getData } })()
未解決問題: 原始的script tag,難以維護,依賴模糊,請求過多。
如 LABjs ,經過LAB.js來加載js文件代替醜陋的script tag,一種基於文件的依賴管理。java
如YUI,一個基於模塊的依賴管理庫。node
隨後出現了CommonJS,AMD/CMD,ES6 Module等方案,以及Browserify/Webpack等模塊打包工具。webpack
好比咱們的node.js,使用的即是CommomJS規範。經過require,module.exports,exports來進行導入和導出,這裏exports是module.exports的一個引用。git
var http = require('http'); var server = http.createServer(); module.exports = { myserver: server }
同步模塊化的應用場景:對於服務器而言,全部的模塊都是存在本地硬盤中的,讀取速度快,因此能夠採用同步的方式讀取模塊。
採用異步方式加載模塊,經過define來定義一個模塊,經過require來引入模塊,模塊的加載不影響後面語句的執行,全部依賴於這些模塊的語句都寫在一個回調函數中,加載完畢後,這個回調函數才運行。如:es6
// 定義一個模塊,name爲定義的模塊名稱,foo爲該模塊依賴的其餘模塊 define( 'name', [ 'foo' ], function(foo) { function outPutFoo () { console.log(foo.data) } return { outPutFoo: outPutFoo } })
// 導入模塊 require(['name'], function (name) { name.outPutFoo(); })
異步模塊化的產生主要是由於同步加載方式沒法應用到瀏覽器等受網速等限制加載速度較慢且不穩定的場景,因此經過異步加載的方式防止代碼執行受阻,頁面中止渲染等問題。
CMD規範是國內SeaJS的推廣過程當中產生的,CMD規範中一個模塊是一個文件。github
// 定義一個模塊,可經過return, exports, mudule.exports決定要導出的內容 define(function (require, exports, module) { var one = require('./one') one.do() // 就近依賴,按需加載 var two = require('./two') two.do() })
AMD規範的require.js與CMD規範的sea.jsweb
require.js主要解決的問題:
- 管理文件之間的依賴性
- 避免瀏覽器由於加載依賴而中止頁面渲染,失去響應。
定義模塊
define(function () { // ... }) // 依賴moduleB define(['moduleB'], function (moduleB) { // ... }) // 定義命名模塊moduleA define('moduleA', ['moduleB'], function { // ... })
引入模塊
require(['moduleA'], function (moduleA) { // ... })
若是不在統一目錄,能夠經過config來自定義。
require.config({ baseUrl: "...", path: { "moduleA": "....", "moduleB": "..." } })
cmd規範的sea.js由於已經廢棄了,因此就再也不詳細說了。
es6帶來了語言原生的模塊化方案。
const methodOne = params => { console.log(params) } const methodTwo = params => { console.log(params) } // 導出方式 1 export default { methodOne, methodTwo } // 導出方式 2 export { methodOne, methodTwo }
// 引入方式 1 對應導出方式 1 import module from './module' module.methodOne(); // 引入方式2 對應導出方式 2 import { methodOne } from './module' methodOne();
使得CommonJS In Brower成爲可能,它經過將require()函數解析爲ast(抽象化語法樹)來遍歷咱們的整個關係依賴圖。咱們能夠在前端代碼中使用CommonJS規範來模塊化的開發咱們的應用,而後經過Browerify進行打包。
本質上webpack是一個現代JavaScript應用程序的靜態模塊打包器。它遞歸的構建一個依賴關係圖,其中包含應用程序的每一個模塊,而後將這些模塊打包成一個或多個bundle.js。
webpack 支持 CommonJS,AMD,ES6等規範,因此咱們在代碼中可使用多種模塊加載規範,並且經過loader,它不只能夠處理JavaScript,還能夠處理像css,圖片等等的靜態資源。
前端做爲一種GUI軟件——圖形用戶界面(Graphical User Interface),在複雜的項目種,除了js/css的模塊化,咱們還須要對UI進行分治,也就是組件化開發。
組件化的理念:
組件化的工程意義首先就是分治,其次就是複用。合理的模塊化和組件化可使系統功能分治到獨立的更小的工程中去,顆粒度越細,組織形式越鬆散,開發人員之間的開發就不會產生過多的依賴,提升開發效率,同時整個項目的維護也變得簡單可行。
參考
---前端工程基礎
---javascript模塊化7日談