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完全火了,走向了世界。

中国有句话叫作“以史为鉴,能够知兴替”。在了解这些历史的时候除了以为颇有意思,也会有一些思考:在历史的大潮里,有多少人是能够作那个改变方向的人?又有多少人死在了历史的长河里?要想不被淹死,只有奋力向上。

相关文章
相关标签/搜索