Webpack实战:入门、进阶与调优(第2版)
上QQ阅读APP看书,第一时间看更新

1.2 为什么需要Webpack

开发一个简单的Web应用,其实只需要浏览器和一个简单的编辑器就可以了。最早的Web应用就是这么开发的,因为需求很简单。当应用的规模大了之后,就必须借助一定的工具,否则人工维护代码的成本将逐渐变得难以承受。使用工具可以让开发效率成倍地提升,所谓“工欲善其事,必先利其器”就是这个意思。

说回Webpack,既然它解决的最主要问题是模块打包,那么为了更好地阐述Webpack的作用,我们必须先谈谈模块。

1.2.1 何为模块

我们每时每刻都在与模块打交道,比如,在工程中引入一个日期处理的npm包,或者编写一个提供工具方法的JS文件,这些包和文件都可以称为模块。

在设计程序结构时,把所有代码都堆到一起是非常糟糕的做法。更好的组织方式是按照特定的功能将其拆分为多个代码段,每个代码段实现一个特定的目的。你可以对其进行独立的设计、开发和测试,最终通过接口来将它们组合在一起。这就是基本的模块化思想。

如果把程序比作一个城市,这个城市内部有不同的职能部门,如学校、医院、消防局等。程序中的模块就像这些职能部门一样,每一个都有其特定的功能。各个模块协同工作,才能保证程序的正常运转。

1.2.2 JavaScript中的模块

在大多数程序语言(如C、C++、Java)中,开发者都可以直接使用模块进行开发。工程中的各个模块在经过编译、链接等过程后会被整合成单一的可执行文件并交由系统运行。

对于JavaScript来说,情况则有所不同。在过去的很长一段时间里,JavaScript这门语言并没有模块这一概念。如果工程中有多个JS文件,我们只能通过script标签将它们一个个插入页面中。

为何偏偏JavaScript没有模块呢?如果要追溯历史原因,JavaScript之父Brendan Eich最初设计这门语言时只是将它定位成一个小型的脚本语言,用来实现网页上一些简单的动态特性,远没有考虑到会用它实现今天这样复杂的场景,模块化当然也就显得多余了。

随着技术的发展,JavaScript已经不仅仅用来实现简单的表单提交等功能,引入多个script文件到页面中逐渐成为一种常态,但我们发现这种做法有很多缺点。

·需要手动维护JavaScript的加载顺序。页面的多个script之间通常会有依赖关系,但由于这种依赖关系是隐式的,除了添加注释以外很难清晰地指明谁依赖了谁,所以当页面中加载的文件过多时很容易出现问题。

·每一个script标签都意味着需要向服务器请求一次静态资源,在HTTP 2还没有出现的时期,建立连接的成本是很高的,过多的请求会严重拖慢网页的渲染速度。

·在每个script标签中,顶层作用域即全局作用域,没有任何处理而直接在代码中进行变量或函数声明会污染全局作用域。

模块化则解决了上述所有问题。

·通过导入和导出语句我们可以清晰地看到模块间的依赖关系,这点在后面会做详细的介绍。

·模块可以借助工具来进行打包,所以在页面中只需要加载合并后的资源文件,减少了网络开销。

·多个模块之间的作用域是隔离的,彼此不会有命名冲突。

从2009年开始,JavaScript社区开始对模块化进行不断的尝试,并先后给出了AMD、CommonJS、CMD等解决方案。但这些都只是由社区提出的,并不能算作语言本身的特性。而在2015年,ECMAScript 6.0(ES6)正式定义了JavaScript模块标准,使这门语言在诞生了20年之后终于拥有了模块这一概念。

ES6模块标准目前已经得到了大多数现代浏览器的支持,但在实际应用方面还需要等待一段时间,主要有以下几点原因。

·无法使用代码分片(code splitting)和删除死代码(tree shaking)(Webpack的两个特别重要的特性,后文会介绍)。

·大多数npm模块还是CommonJS的形式,而浏览器并不支持其语法,因此这些包没有办法直接拿来用。

·仍然需要考虑个别浏览器及平台的兼容性问题。

那么,如何才能让我们的工程在使用模块化的同时也能正常运行在浏览器中呢?这就到了模块打包工具出场的时候了。

1.2.3 模块打包工具

模块打包工具(module bundler)的任务就是解决模块间的依赖,使其打包后的结果能运行在浏览器上。它的工作方式主要分为两种。

·将存在依赖关系的模块按照特定规则合并为单个JS文件,一次全部加载进页面中。

·在页面初始时加载一个入口模块,异步加载其他模块。

目前社区中比较流行的模块打包工具有Webpack、Vite、Parcel、Rollup等。

1.2.4 为什么选择Webpack

对比同类模块打包工具,Webpack具备以下几点优势。

1)Webpack默认支持多种模块标准,包括AMD、CommonJS以及最新的ES6模块,而其他工具大多只能支持一到两种。Webpack对于一些同时使用多种模块标准的工程非常有用,它会帮我们处理好不同类型模块之间的依赖关系。

2)Webpack有完备的代码分片解决方案。从字面意思去理解,它可以分割打包后的资源,在首屏只加载必要的部分,将不太重要的功能放到后面动态加载。这对于资源体积较大的应用来说尤为重要,可以有效地减小资源体积,提升首页渲染速度。

3)Webpack可以处理各种类型的资源。除了JavaScript以外,Webpack还可以处理样式、模板,甚至图片等,而开发者需要做的仅仅是导入它们。比如你可以从JavaScript文件导入一个CSS或者PNG,而这一切最终都可以由第4章讲到的loader来处理。

4)Webpack拥有庞大的社区支持。除了Webpack核心库以外,还有无数开发者来为它编写周边插件和工具。对于绝大多数的需求,你都可以直接在社区找到已有解决方案,甚至会找到多个解决方案。

以上我们对Webpack进行了简要介绍,但是说再多也不如实际操作一次,现在上手试一试吧。