Webpack 简述

Webpack 是一个模块打包器。Webpack 单独与一些的 Task Runner 配合工作。然而,由于社区开发的 Webpack 插件,Bundler 和 Task Runner 之间的界限变得模糊。有时,这些插件用于执行通常在 Webpack 之外完成的任务,例如清理构建目录或部署构建代码。

热更新模块(HMR)有助于推广 Webpack 并使其在其他环境中的使用,例如 Ruby on Rails。尽管 Webpack 涵盖 “Web”一字,但 Webpack 并不仅限于 Web。它也可以用在其他场景中,如构建目标章节中所述。

如果您想更详细地了解构建工具及其历史记录,请查看构建工具比较附录。

Webpack 依赖于模块

在一个项目中,Webpack 包含输入输出两个部分。打包过程从用户定义的模块开始,在模块中又可以通过导入指向其他模块。

当您使用 Webpack 打包项目时,它会遍历导入,构建项目的依赖关系图,然后根据配置生成输出。此外,还可以定义拆分点,以在项目代码本身内创建单独的包。

Webpack支持开箱即用的 ES2015,CommonJS 和 AMD 模块格式。loader 机制也适用于 CSS,通过 css-loader,我们可以使用 @importurl() 来导入 css 文件。您还可以找到特定任务的插件,例如压缩,国际化,HMR等。

依赖图是描述节点如何相互关联的有向图。我们通过依赖图描述了文件之间的引用(requireimport)关系。Webpack 在不执行源代码的情况下静态遍历这些源代码,以生成创建 bundle 所需的依赖图

Webpack 的执行流程

Webpack 的执行过程,按照配置从入口文件输出代码结果

Webpack 通常从 JavaScript 模块开始遍历。在此过程中,Webpack 会根据 Loaders 配置评估模块是否匹配,并且会按照配置来转换匹配的模块。

解析过程

Entry 本身就是一个模块。当 Webpack 遇到一个 Entry 时,Webpack 会尝试使用 Entry 的 resolve 配置将 Entry 与文件系统中的文件匹配。除了node_modules 之外,您还可以告诉 Webpack 对特定目录执行查找。也可以调整 Webpack 匹配文件扩展名的方式,并且可以为目录定义特定的别名。使用包一章涵盖了更详细的说明。

如果解析通过失败,Webpack 会引发运行时错误。如果 Webpack 正确解析文件,Webpack 将根据 Loader 的定义对匹配的文件执行处理。每个 Loader 对模块内容应用特定的转换。

Loader 与待解析文件之间的匹配规则可以通过多种途径配置,包括按文件类型和按文件系统中的位置。Webpack的灵活性甚至允许您根据文件导入项目的位置将特定转换应用于文件。

Loader 的执行也具有相同的解析过程,Webpack 允许您在确定应使用哪个 Loader 时应用类似的逻辑。由于这个原因,Webpack 必须预先解析 Loader 的配置。如果 Webpack 无法查找到 Loader 程序,则会引发运行时错误。

通过 enhanced-resolve 包,Webpack 可以异步加载 Loader。

Webpack 可以处理任何文件类型

Webpack 在构造依赖图时解析它遇到的每个模块。如果 Entry 包含依赖项,则将针对每个依赖项递归执行该过程,直到遍历完成为止。Webpack 可以针对任何文件类型执行此过程,这与 Babel 或 Sass 编译器等专用工具不同。

Webpack 使您可以控制如何处理遇到的不同类型的资源。例如,您可以决定将资源内联到 JavaScript 代码中以避免被处理。Webpack 还允许您使用CSS 模块等技术将样式与组件结合,并避免一些 CSS 兼容性问题。这种灵活性使 Webpack 非常有价值。

虽然 Webpack 主要用于打包 JavaScript,但它可以捕获图像或字体等资源,并为它们发出单独的文件。Entry 只是打包过程的起点。Webpack 打包出的内容完全取决于您配置它的方式。

转换过程

假设所有的 Loader 都被找到,Webpack 将从下到上和从右到左(styleLoader(cssLoader('./main.css')))的对 Loader 进行匹配,同时依次通过每个匹配 Loader 来运行模块。因此,您将获得 Webpack 在打包结果中注入的输出。在 Loader 定义一章中将详细介绍该主题。

如果所有加载器执行都在没有运行时错误的情况下完成,则 Webpack 将源代码包含在最后一个包中。插件允许您在打包过程的不同阶段拦截运行时事件

虽然 Loader 可以做很多事情,但它们不能为高级任务提供足够的动力。插件可以拦截 Webpack 提供的运行时事件。一个很好的例子是包内容的提取,当 MiniCssExtractPlugin 与 Loader 一起使用时,从包中抽出 CSS 并将其提取到单独的文件中。如果没有这一步,CSS 将在生成的 JavaScript 中内联,因为 Webpack 默认将所有代码视为 JavaScript。内容提取将在Separating CSS章节中讨论。

最后

转换完每个模块后,Webpack 会写入Output。Output 包括一个启动脚本,其中包含一个描述如何在浏览器中开始执行结果的 manifest。如本书后面所述,可以将 manifest 提取到自己的文件中。Output 根据您使用的构建目标而有所不同(Web 不是唯一选项)。

这并不是打包过程的全部内容。例如,您可以定义特定的拆分点,其中 Webpack 生成基于应用程序逻辑加载的单独的包。Code Splitting 章节阐述了更多细节。

Webpack 是配置驱动的

Webpack 的核心依赖于配置。以下是根据官方webpack教程改编的示例配置,其中包含以下要点:

webpack.config.js

const webpack = require('webpack')

module.exports = {
  // 这里是打包入口
  entry: {
    app: './entry.js'
  },

  // 这里是打包出口
  output: {
    // 输出到同样的文件夹
    path: __dirname,

    // 通过某种模式使用入口文件的名字定义打包文件名称
    filename: '[name].js'
  },

  // 对于每一个文件导入提供一些解析规则
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.js$/,
        use: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  },

  // 定义一些插件,来处理转换过程外额外要做的事情
  plugins: [new webpack.DefinePlugin({ ... })],

  // 调整模块解析的算法
  resolve: {
    alias: { ... }
  }
}

Webpack 的配置模型有时会感觉有点不透明,因为配置文件可能看起来是单一庞杂的。除非你知道背后的想法,否则很难理解 Webpack 在做什么。提供条理清晰的配置方法是本书存在的主要目的之一。

资源的哈希值

使用 Webpack,您可以为每个包名称注入一个哈希值(例如,app.d587bbd6.js),以便重新部署时使客户端的旧代码失效。而打包时,进行代码分割允许客户端在理想情况下仅重新加载一小部分数据。

热模块更换

您可能已经熟悉了 LiveReloadBrowserSync 等工具。这些工具会在您进行代码更改时自动刷新浏览器。热模块更换(HMR)更进一步。在代码有变动的情况下,它允许应用程序在不强制刷新的情况下维持其状态。虽然这听起来不那么特别,但它可以在实践中产生很大的不同。

通过 livereactload 也可以在Browserify 中使用 HMR,因此它不是 Webpack 独有的功能。

代码拆分

除 HMR 外,Webpack 的打包功能也非常广泛。Webpack 允许您以各种方式分割代码。您甚至可以在应用程序执行时动态加载代码。这种延迟加载特别适用于更大型的应用程序,因为可以根据需要动态加载依赖项。

即使是小型应用程序也可以从代码分割中受益,因为它允许用户更快地获得可用的东西。毕竟,性能关乎用户体验。了解这些技术是值得的。

结论

Webpack 带来了较陡的学习曲线。然而,考虑到长期带来时间和精力上的节省,这是一个值得学习的工具。为了更好地了解它与其他工具的比较,请查看Webpack 官方比较

Webpack 不会解决所有问题。但是,它确实解决了打包问题。在开发过程中,不用为此担心。配合上 package.json 的使用,还会更加的便捷。

总结一下:

  • Webpack 是一个模块打包器,但您也可以使用它运行独立的小任务。
  • Webpack 依赖于模块依赖图。Webpack 遍历源代码构建图,并使用此信息和配置生成包。
  • Webpack 依赖于 Loader插件。Loader 在模块级别上运行,而插件依赖于 Webpack 提供的钩子,并且可以很好地访问打包过程。
  • Webpack的配置描述了如何转换图形资源以及它应该生成哪种输出。如果使用代码分割等功能,则可以将部分信息包含在源代码本身中。
  • 热模块更换(HMR)有助于推广 Webpack。这是一项功能,可以通过更新浏览器中的代码来增强开发体验,而无需刷新整页。
  • Webpack可以生成文件名的哈希值,允许您在内容更改时使旧代码失效。

在本书的下一部分中,您将学习使用 Webpack 构建开发配置,同时了解有关其基本概念的更多信息。

如果您仍然不理解 Webpack 或者为什么需要打包,请阅读为什么我要使用Webpack?

用户头像
登录后发表评论