# 第 02 讲:如何使用 Webpack 实现模块化打包?

模块化打包方案或工具的设想或者说是诉求:

  • 能够将散落的模块打包到一起;
  • 能够编译代码中的新特性;
  • 能够支持不同种类的前端资源模块。

目前,前端领域有一些工具能够很好的满足以上这 3 个需求,其中最为主流的就是 Webpack、Parcel 和 Rollup,我们以 Webpack 为例:

  • Webpack 作为一个模块打包工具,本身就可以解决模块化代码打包的问题,将零散的 JavaScript 代码打包到一个 JS 文件中。

  • 对于有环境兼容问题的代码,Webpack 可以在打包过程中通过 Loader 机制对其实现编译转换,然后再进行打包。

  • 对于不同类型的前端模块类型,Webpack 支持在 JavaScript 中以模块化的方式载入任意类型的资源文件,例如,我们可以通过 Webpack 实现在 JavaScript 中加载 CSS 文件,被加载的 CSS 文件将会通过 style 标签的方式工作。

除此之外,Webpack 还具备代码拆分的能力,它能够将应用中所有的模块按照我们的需要分块打包。这样一来,就不用担心全部代码打包到一起,产生单个文件过大,导致加载慢的问题。我们可以把应用初次加载所必需的模块打包到一起,其他的模块再单独打包,等到应用工作过程中实际需要用到某个模块,再异步加载该模块,实现增量加载,或者叫作渐进式加载,非常适合现代化的大型 Web 应用。

当然,除了 Webpack,其他的打包工具也都类似,总之,所有的打包工具都是以实现模块化为目标,让我们可以在开发阶段更好的享受模块化带来的优势,同时又不必担心模块化在生产环境中产生新的问题。

# Webpack 快速上手

Webpack 作为目前最主流的前端模块打包器,提供了一整套前端项目模块化方案,而不仅仅局限于对 JavaScript 的模块化。通过 Webpack,我们可以轻松的对前端项目开发过程中涉及的所有资源进行模块化。

因为 Webpack 的设计思想比较先进,起初的使用过程比较烦琐,再加上文档也晦涩难懂,所以在最开始的时候,Webpack 对开发者并不友好,但是随着版本的迭代,官方文档的不断更新,目前 Webpack 对开发者已经非常友好了。此外,随着 React 和 Vue.js 这类框架的普及,Webpack 也随之受到了越来越多的关注,现阶段可以覆盖绝大多数现代 Web 应用的开发过程。

接下来我将通过一个案例,带你快速了解 Webpack 的基本使用,具体操作如下所示:

└─ 02-configuation
   ├── src
   │   ├── heading.js
   │   └── index.js
   └── index.html
// ./src/heading.js
export default () => {
  const element = document.createElement('h2');
  element.textContent = 'Hello webpack';
  element.addEventListener('click', () => alert('Hello webpack'));
  return element;
};
// ./src/index.js
import createHeading from './heading.js';
const heading = createHeading();
document.body.append(heading);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Webpack - 快速上手</title>
  </head>
  <body>
    <script type="module" src="src/index.js"></script>
  </body>
</html>

P.S. type="module" 这种用法是 ES Modules 中提出的标准,用来区分加载的是一个普通 JS 脚本还是一个模块。

在上面这个案例中,我们创建了两个 JS 文件,其中 heading.js 中以 ES Modules 的方式导出了一个创建元素的函数,然后在 index.js 中导入 heading.js 并使用了这个模块,最后在 html 文件中通过 script 标签,以模块化的方式引入了 index.js,

按照 ES Modules 的标准,这里的 index.html 可以直接在浏览器中正常工作,但是对于不支持 ES Modules 标准的浏览器,直接使用就会出现错误,所以我们需要使用 Webpack 这样的工具,将我们这里按照模块化方式拆分的 JS 代码再次打包到一起。

接下来我们就尝试引入 Webpack 去处理上述案例中的 JS 模块打包。由于 Webpack 是一个 npm 工具模块,所以我们先初始化一个 package.json 文件,用来管理 npm 依赖版本,完成之后,再来安装 Webpack 的核心模块以及它的 CLI 模块,具体操作如下:

$ npm init --yes
$ npm i webpack webpack-cli --save-dev

有了 Webpack 后,就可以直接运行 webpack 命令来打包 JS 模块代码,具体操作如下

$ npx webpack

这个命令在执行的过程中,Webpack 会自动从 src/index.js 文件开始打包,然后根据代码中的模块导入操作,自动将所有用到的模块代码打包到一起。

完成之后,控制台会提示:顺着 index.js 有两个 JS 文件被打包到了一起。与之对应的就是项目的根目录下多出了一个 dist 目录,我们的打包结果就存放在这个目录下的 main.js 文件中,具体操作如下图所示:

这里我们回到 index.html 中修改引入文件的路径,由于打包后的代码就不会再有 import 和 export 了,所以我们可以删除 type="module"。再次回到浏览器中,查看这个页面,这时我们的代码仍然可以正常工作,index.html 的代码如下所示:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Webpack - 快速上手</title>
  </head>
  <body>
    <script src="dist/main.js"></script>
  </body>
</html>

# 配置 Webpack 的打包过程

Webpack 4 以后的版本支持零配置的方式直接启动打包,整个过程会按照约定将 src/index.js 作为打包入口,最终打包的结果会存放到 dist/main.js 中。

在项目的根目录下添加一个 webpack.config.js。 webpack.config.js 是一个运行在 Node.js 环境中的 JS 文件,也就是说我们需要按照 CommonJS 的方式编写代码,这个文件可以导出一个对象。