webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler),将有依赖关系的模块打包成静态资源。
现存的模块打包器,不太适合大型项目(比如单页应用),以及在代码拆分和静态资源配合度不高。
目前有多种不同的规范和标准用来定义依赖和输出:
- <script> 标签 (不存在模块系统)
- CommonJS
- AMD 和一些民间版本
- ES6 模块系统
- .....
他们各有优缺,比如 <script> 标签最简单,但是不存在模块系统,js 脚本过多的时候,很难保证正确的加载顺序,以及全局对象的之间的冲突,因为是挂在window对象下执行的;
CommonJS 呢,是同步加载依赖模块并能对外暴露出接口,使用简单,npm 上有很多现成的优秀模块,但因为CommonJS 是同步的,因此不能同时请求多个模块,适合用在服务器端,但就不适合客户端的网络请求了,因为网络请求需要是异步的,否则会造成阻塞,页面假死,用户等待过久....;
AMD呢,专为解决异步加载而出现的,可以同时异步请求多个模块,但是缺点是代码过重,书写阅读繁琐,比如requirejs 的实现,需要先加载requirejs,否则 define,require 等用来定义模块,加载模块的名词,浏览器是不认识的;
ES6 的模块系统,代码清晰,静态分析容易,而且是写入到ES标准中,这是未来的趋势,但是目前的浏览器支持度还不是特别普及,毕竟有些用户在使用旧版本浏览器。
这时候 webpack 出来了,并不是要取代这些模块,以及已有的代码需要进行大改动,而是包容了一切,让开发者们继续自行选择其惯用的模块风格,只需要通过 webpack 进行打包,曾经的代码依然可以良好的工作。
此外,在模块传输中,有两个极端的例子:
- 一个模块用一个请求
- 多个模块用一个请求
前者可以按需加载,但是需要的请求过多时,启动就变得缓慢,推迟;而后者一次性请求所有模块,减少了请求数,但是暂时用不到的模块也一并传输,造成了带宽浪费。
而 webpack 自然就采用了折中的法子,编译所有模块时,将彼此关系密切的模块打包在一起,因此多个模块被分割成若干个小包,形成多次小请求,模块包可以按需加载,比如一个多页面网站,不同页面其实有很多公共的代码块,这时就可以优先加载,其他的按需加载。
至于代码如何分割,取决于开发者。
另外 webpack 野心很大,凭什么模块系统只对 javascript 进行模块化打包, 其实 css 样式、图片、网络字体、html模板 ..... 都可以模块化打包, 以及 类似 coffeescript 、elm、less、jade template等等都可以交给 webpack 来输出标准的 三大件:html css javascript。