Webpack原理(1) — Why Webpack

本文首發於個人我的博客: teobler.com, 轉載請註明出處javascript

咱們怎麼使用JS

衆所周知,咱們在HTML文件中使用JavaScript只能經過script標籤來引入:html

<script src="./index.js"></script>

<script> console.log('Hello World'); </script>
複製代碼

若是隻是這樣用,有什麼問題呢?這樣引入JavaScript是沒辦法大量引入的,什麼算大量呢?也不用多,加入某個頁面我須要20個JavaScript文件,怎麼辦?好像我只能加20個script標籤,而後一個一個去請求。可是這樣的話首先會使頁面加載變慢,你須要在加載頁面後去請求大量的script,更爲重要的是,瀏覽器是有請求限制的:前端

瀏覽器只容許必定數量的請求可以 'fetch data',因此若是在同一時刻發起大量的請求的話,對於瀏覽器來講會有至關嚴重的性能問題。可能有人會說,9102年了,我用HTTP/2啊,沒問題。是,對於大部分狀況來講的確沒有問題了,name對於特殊狀況呢?好比Airbnb和MS的outlook,他們用超過3000個modules去進行構建。java

咋辦呢?那我把全部須要的JavaScript代碼寫到同一個文件裏就行了嘛,是的,歷史就是這麼發展的,因此老程序員們可能都見到過那種一萬十萬行的巨大的JavaScript文件。這種辦法的確緩解了上述問題,但是,這樣的文件,我還須要講缺點嘛?不說別的,假如我用到的某個function有問題,我想debug一下,咋整呢?鬧呢?我在第一行定義了一個變量,我要去第一萬行找它,而後這他麼仍是一個全局變量,咋玩呢?react

而後呢,萬能的前端同窗們想到了一個辦法 — IIFE 啥是IIFE呢 — immediately invoked function expression,中文是當即執行函數,它能夠幹啥用呢:webpack

var outerScope = 1;

const whatever = (function(dataWillUsedInside){
    var outerScope = 0;
    return {
        someAttribute: 'youWantThis'
    }
})(0);

// 1
console.log(outerScope);
複製代碼

這下游戲規則好像變簡單了一點了,咱們能夠本身寫不少JS文件,而後把它們封裝成一個個的IIFE,而後封裝到一個文件裏面,好了,解決了一個問題,至少變量污染的問題解決了嘛。而後呢,開始進入工具時代了,這個時候你們開始尋找各類各樣的工具 — make, grunt, gulp, broccoli...git

那麼新的問題又來了 — 若是我想修改下某個文件,而後呢,我須要編譯全部的文件,包括那些我都沒有動過的。第二個問題是,好比我想引某個庫,按需引用?不存在的,我只能一坨的引進來,這就有點可怕了,尤爲仍是以當時的網絡情況來看。並且說不定你還須要引好多個庫呢,那也只能所有放進來。並且這樣編寫成IIFE的「文件」因爲各類緣由會致使你的網頁加載很慢。程序員

JS的模塊化

因此這個時候前端的同窗們又開始想辦法了,咱們得有模塊化這個東西呀。Node其實就是把V8「拿」到了server端,那麼問題來了,沒有了browser,沒有了DOM,咱們還怎麼使用JS?因此Node.JS的出現帶來了模塊化,帶來了CommonJS。github

// index.js
const path = require('path');
const [add, subtract] = require(''./math');

/*
 * math.js (has two named exports [add, subtract])
 */
const divideFn = require('./division');

exports.add = (first, second) => first + second;
exports.subtract = (first, second) => first - second;
exports.divide = divideFn;

/*
 * dibision.js (has a exports 'divide')
 */
module.exports = (first, second) => first / second;
複製代碼

上面的代碼是一個簡單的CommonJS的例子,有三個文件,他們能夠經過使用require相互引用。你可使用匿名的默認exports,也可使用具名的導出。以後再在別的文件內以特定的語法導入。因此到如今咱們就解決了做用域的問題,咱們再也不須要IFFE了,這個時候咱們不用再擔憂變量污染的問題了,同時也解決了IFFE的缺點。而同時出現的NPM更是讓各個開發者本身寫的各類包可以讓每個人使用。web

但是還有問題,這玩意兒是Node的,不支持瀏覽器。並且若是你是一個寫過別的語言的程序員的話你也應該知道動態綁定,可是CommonJS並不支持動態綁定。因而自我引用和循環引用層出不窮。並且他的同步算法賊慢。又爲了解決這些問題,出現了一些有意思的東西:browserify, requireJS, systemJS…這些工具的目的很簡單,就是讓你可以在瀏覽器裏面使用CommonJS。可是它們並不支持靜態引入,也就是說你要用某個庫你仍是隻能所有引進來。並且也並非全部人在寫庫的時候都會使用CommonJS,畢竟還有個AMD不是嗎。因此能夠說這套玩意兒不能算是'module system'。

因而ES Module出現了。聽說與之相關的文檔,在1998年就能看到,因此這是一個斷斷續續設計並開發了大概10多20年的玩意兒,不過他的語法更友好了些,至少不是一些require之類的讓人看到一頭霧水的詞語了:

import {uniq, forOf, bar} from 'lodash-es';
import * as utils from 'utils';

export const uniqConst = uniq([1, 2, 3, 4]);
複製代碼

如今看起來咱們好像有了一個完整的module system了,重用,封裝這些基本特性看起來都還不錯。可是呢?幾個問題又來了:這玩意兒好像挺難使用在Node裏面的 — 這也是如今好多團隊正在努力的方向;並且它直接在瀏覽器裏面使用的話 — 很是很是慢,慢到你覺得網站掛了,並且不用多,10個modules就能達到這個效果。由於在瀏覽器從上到下讀取這個JS文件的時候,首先遇到import,而後去找這個包在哪,找到相應的路徑,而後驗證一下這些東西還能不能用,最後把這個文件讀進來,而後繼續在這個文件裏重複這個步驟 — 一直到全部的依賴都讀完了。須要注意的是,這一切都是在runtime完成的,也就是在加載你的網頁的時候。

webpack橫空出世

以前咱們提到過,一個NPM中的包多是用的不一樣的module format,你不能說哪種是不對的不能使用的,因此在面對不一樣的方法的時候你也須要使用不一樣的使用方法。並且須要說明的是,上面咱們說的全部東西都只是關於JS的,別忘了一個web app還有CSS還有各類靜態資源。咱們須要的是一個支持全部module format,而且同時還能支持除了JS之外的別的文件的一個「系統」或者說工具。

webpack是什麼?

webpack is a module bundler lets you write any module format(mixed also), compiles then for the browser. And it supports static async bundling.

很簡單有很強大的定義對吧,它幾乎解決了上面全部的問題,那麼它是怎麼被創造出來的呢?這是一個有意思的小故事。

2012年,一個叫作Tobias的,在Newberg(美國一個城市)讀master的德國人要寫一片學位論文。他以前是寫c#的,歷來沒有寫過一個web界面。他在一些特定的場景須要用到Google Web Toolkit中的一個叫作code splitting的功能。而在他的論文中他須要寫一個web app,他就想找一個包含這個功能的庫來用。他找到的這個庫叫webmake,這也是一個bundler。可是卻沒有code splitting這個功能,因而他提了一個issue,而且寫了一堆如何實現這個功能的代碼,但願維護者可以加入這個功能。在一番討論事後維護者拒絕了他,因而在通過贊成以後,他把這個庫fork到了了過去並本身加上了這個功能,給新的庫取名爲webpack。

2014年,Dan Abramov在Stack Overflow上提了一個關於hot module replacement的問題,Tobias用很大的篇幅給他介紹了這個還在開發的功能,詳細解釋了這個功能怎麼在webpack裏工做的,以及這個功能有多棒,你能夠不用刷新瀏覽器了!

2015年,這時在Instagram工做的Pete Hunt經過一次演講告訴了世界他們是如何使用webpack打包發佈他們的react app的。而後你懂得,webpack就火了。像Facebook這樣的公司也開始使用webpack了。可是其實Tobias只是每週大概花5 6個小時在webpack中。

是的,在這兩個討論中,webpack完全火了,走向了世界。

中國有句話叫作「以史爲鑑,能夠知興替」。在瞭解這些歷史的時候除了以爲頗有意思,也會有一些思考:在歷史的大潮裏,有多少人是能夠作那個改變方向的人?又有多少人死在了歷史的長河裏?要想不被淹死,只有奮力向上。

相關文章
相關標籤/搜索