從前端打包的歷史談起javascript
在很長的一段前端歷史裏,是不存在打包這個說法的。那個時候頁面基本是純靜態的或者服務端輸出的, 沒有 AJAX,也沒有 jQuery。Google 推出 Gmail 的時候(2004 年),XMLHttpRequest, 也就是咱們俗稱的 AJAX被拾起的時候,前端開發者開始往頁面裏插入各類庫和插件,咱們的 js 文件程指數倍的開始增長了。JSMin、YUI Compressor、Closure Compiler、UglifyJS 等 js 文件壓縮合並工具陸陸續續誕生了。壓縮工具是有了,但咱們得要執行它,最簡單的辦法呢,就是 windows 上搞個 bat 腳本,mac / linux 上搞個 bash 腳本,哪幾個文件要合併在一塊的,哪幾個要壓縮的,發佈的時候運行一下腳本,生成壓縮後的文件。css
這時候commonJS出現了,若是想在a.js引入b.js和c.js,大概語法是html
var b = require(./b.js); var c = require(./c.js);
b.js和c.js導出方式是大概這樣的前端
exports.add = function(a, b) { return a+b; }
而後再a.js中可使用b模塊的add方法java
var n = b.add(5, 8);
// b.js module.exports = { add(a, b){ return a+b; } } // or exports.add = function(a,b) { return a+b; } // a.js var b = require('./b.js'); var n = b.add(5,8);
上述代碼中, module.exports 和 exports 很容易混淆,下面看下大體的內部實現node
var module = require('./b.js'); module.add // 包裝了一層當即執行函數,防止全局變量污染,重要的是module,module是node獨有的一個變量 module.exports = { add: function(a,b) { return a+b; } } // 基本實現 var module = { exports: {} // exports是個空對象 } var exports = module.exports var load = function(module) { // 須要導出的東西 var add = function(a, b) { return a+b; } module.exports = add; return module.exports; }
module.exports和exports用法如出一轍,可是不能對exports直接賦值,沒有任何效果。linux
可是commonJS是node獨有的規範,瀏覽器中並不適用,由於require()的返回是同步的,服務器加載資源的時候並不能異步的讀取。在瀏覽器中若是使用這種方式就會堵塞js腳本的執行,因此瀏覽器中只能使用Browserify解析。Browserify和webpack幾乎同時出現,簡單介紹下Browserify: 其目的是讓前端也能使用commonJS的語法來加載js,它會從入口js開始,把全部的require()調用文件打包併合併到一個文件,這樣就解決了異步加載的問題。可是對比webpack,他的缺點也是明顯的: webpack
1.不支持按需加載,Browserify不支持把代碼打包成多個文件。git
2.對非js文件的加載不夠完善,好比html中的img標籤,只能轉成Data URI的形式,並不能替換爲打包後的路徑。在配合gulp或者grunt使用時增長了難度。github
3.只支持commonJS規範,不支持後續介紹的AMD和ES6 Module。
因此webpack一統了天下。
因而,在commonJS的基礎上,2011又出現了 Asynchronous Module Definition,也是就是AMD規範,AMD規範使用異步回調的語法來並行下載多個依賴項,基本語法以下
require(['./b.js', './c.js'], function(b,c){ var n = b.add(5,8);
console.log(c) })
同時,導出的時候也須要使用異步回調的方式,好比,c模塊又依賴了d.js
defined(['./d'], function(d){ return d.PI })
總結下AMD: 定義模塊使用defined()函數,引入使用reqire()函數,二者的區別是,前者必需要在回調函數中返回一個值做爲導出的東西,後者確不須要任何導出,同時也沒法做爲被依賴項被其餘文件導入,所以通常用於入口文件。
AMD是由RequireJS提出的。若是想了解能夠查看其文檔。可是如今基本已經被淘汰了。
js的模塊化問題解決後,css模塊化也被各類各樣的css預處理器所處理: less、sass、stylus、scss等等。
後來有了ES6規範,提出了模塊化的概念,配合babel能夠直接使用 ES6模塊化
// b.js export function a() {} export function b() {} // c.js export default function() {} // a.js import {a, b} from './b.js' import ModuleC from './c.js'
對於commonJS和ES6 module 的區別簡單總結以下:
1. 前者支持動態導入,也就是能夠這樣寫 require(`${path}/b.js`), 後者目前不支持,可是已有提案。
2. 前者是同步導入,由於用於服務器,文件都在本地,同步導入即便卡主主線程也影響不大;後者是異步導入,由於用於瀏覽器,須要從服務器下載文件,若是使用同步導入會影響頁面渲染。
3. 前者在導出時是值拷貝,就算導出的值發生變化了,導入的值也不會改變。因此若是導入結束後想更新值,必須從新導入一次;後者才用的是實時綁定的方式, 導入導出的值都指向同一個內存地址,因此導入值會跟隨導出值變化。
4. ES6 module 會編譯成爲 require/exports 來執行。
原文出處:https://www.cnblogs.com/jasonwang2y60/p/10795103.html