为什么我们要使用 webpack

1,319 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

在 webpack 的官网中,它是这么描述的:

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler) 。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph) ,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle

我们可以看看 webpack 解决了哪些问题,从而分析为什么我们在平时需要使用 webpack 构建项目,当然目前也出现了很多可以替代 webpack 的竞品,比如 vite 。

传统开发

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>标题</title>
  </head>
  <body>
    <div>html 内容</div>
   
    <!-- 第三方库 -->
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>

    <!-- 自己的库 -->
    <script src="./scripts/common.js"></script>
    <script src="./scripts/product.js"></script>
    <script src="./scripts/payment.js"></script>
  </body>
</html>

如上述代码所示,传统开发需要遵循一些规则,比如先引入第三方的库,再引入自己的库;自己写的一些脚本,如果相互有依赖关系,需要注意引入顺序,这就会导致代码扩展性非常困难。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>标题</title>
  </head>
  <body>
    <div>html 内容</div>
   
    <!-- 第三方库 -->
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>

    <!-- 自己的库 -->
    <script src="./scripts/bundle.233abc233a.js"></script>
  </body>
</html>

如果是把自己的代码都整合到一个文件里,又会导致4个问题:

  1. 作用域问题(污染全局变量)
  2. 文件过大(网络加载慢,白屏)
  3. 可读性差
  4. 可维护性弱

作用域问题

Grunt 和 Gulp 作为任务执行器,利用 IIFE (Immediately Invoked Function Expression) 的机制拼接组合文件,这样就不用担心作用域的问题了。

;(function(){
    var myName = "Tom"
})()

console.log(myName) // undefined

如何拆分大文件

node.js 是一个 javascript 的运行环境,我们可以在非浏览器中运行 js 代码,特别是 npm 的出现,引发了 Web 开发的革命, webpack 其实就是运行在 node.js 中的。 common js (cjs) (一种 js 规范)中引入了 require 方法,可以加载模块代码。在浏览器中,不支持 cjs 的写法,除非使用 BrowserifyRequireJS

// math.js
const add = (a, b) => (a + b)
const minus = (a, b) => (a - b)

module.exports = {
    add,
    minus
}

// main.js
const math = require("./math.js")

math.add(4, 5) // 9

不过,随着 es6 module 的出现, cjs 已经过时。如果要在 script 标签中如果需要使用的话,需要添加属性 type="module"。目前大多数浏览器和 node.js 中已支持 esm ,逐渐成为标准。需要注意的是 esm 是编译时加载,因此不支持变量、表达式,而 cjs 时运行时动态加载

// math.js
const add = (a, b) => (a + b)
const minus = (a, b) => (a - b)

export {
    add,
    minus
}

// main.js
import math from './math.js'

math.add(4, 5) // 9

webpack 与竞品

  • Webpack:代码拆分、按需加载、静态资源引入,适合复杂应用
  • Parcel:零配置、快速打包、自动转换,适合简单应用
  • Rollup:整合资源为一处,适合类库
  • Vite:最新的黑马,用 esm 打包,按需编译、热更新