webpack

2,017 阅读4分钟

什么是webpack

webpack是一个用于现在javascript应用程序的静态模块打包工具

当webpack处理应用程序时,它会在内部构建一个依赖图,此依赖图对应映射到项目所需的每个模块,并生成一个或多个bundle。

loader与plugin的区别

loader 预处理函数,用于转换某些类型的模块

plugin 目的在于解决 loader 无法实现的其他事,用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

使用loader的方式

  1. 配置方式(推荐):在webpack.config.js文件中指定loader(注意:loader从右到左(或从下到上)的取值/执行
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          // [style-loader](/loaders/style-loader)
          { loader: 'style-loader' },
          // [css-loader](/loaders/css-loader)
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          },
          // [sass-loader](/loaders/sass-loader)
          { loader: 'sass-loader' }
        ]
      }
    ]
  }
};
  1. 内联方式:在每个import语句中显式指定loader
  • 使用 ! 前缀,将禁用所有已配置的 normal loader(普通 loader)
import Styles from '!style-loader!css-loader?modules!./styles.css';
  • !! 前缀,将禁用所有已配置的 loader(preLoader, loader, postLoader)
import Styles from '!!style-loader!css-loader?modules!./styles.css';
  • -! 前缀,将禁用所有已配置的 preLoader 和 loader,但是不禁用 postLoaders
import Styles from '-!style-loader!css-loader?modules!./styles.css';

尽可能使用 module.rules,因为这样可以减少源码中样板文件的代码量,并且可以在出错时,更快地调试和定位 loader 中的问题。

  1. cli方式:在shell命令中指定它们
webpack --module-bind pug-loader --module-bind 'css=style-loader!css-loader'

对 .jade 文件使用 pug-loader,以及对 .css 文件使用 style-loader 和 css-loader

loader的特性

  • loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的 JavaScript。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何操作。
  • loader 可以通过 options 对象配置(仍然支持使用 query 参数来设置选项,但是这种方式已被废弃)。
  • 除了常见的通过 package.json 的 main 来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用 loader 字段直接引用一个模块。
  • 插件(plugin)可以为 loader 带来更多特性。
  • loader 能够产生额外的任意文件。

webpack中的模块解析规则

使用 enhanced-resolve,webpack 能解析三种文件路径:

  • 绝对路径
import '/home/me/file';
import 'C:\\Users\\me\\file';

由于已经获得文件的绝对路径,因此不需要再做进一步解析。

  • 相对路径
import '../src/file1';
import './file2';

在这种情况下,使用 import 或 require 的资源文件所处的目录,被认为是上下文目录。在 import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径。

  • 模块路径(重点
import 'module';
import 'module/lib/file';

resolve.modules中指定的所有目录检索模块。 你可以通过配置别名的方式来替换初始模块路径,resolve.alias配置选项。

如果 package 中包含 package.json 文件,那么在 resolve.exportsFields 配置选项中指定的字段会被依次查找,package.json 中的第一个字段会根据 package 导出指南确定 package 中可用的 export。 一旦根据上述规则解析路径后,resolver 将会检查路径是指向文件还是文件夹。

  1. 指向文件:
    • 如果文件具有扩展名,则直接将文件打包。
    • 否则,将使用 resolve.extensions 选项作为文件扩展名来解析,此选项会告诉解析器在解析中能够接受那些扩展名(例如 .js,.jsx)。
  2. 指向一个文件夹,则进行如下步骤寻找具有正确扩展名的文件:
    • 如果文件夹中包含 package.json 文件,则会根据 resolve.mainFields 配置中的字段顺序查找,并根据 package.json 中的符合配置要求的第一个字段来确定文件路径。
    • 如果不存在 package.json 文件或 resolve.mainFields 没有返回有效路径,则会根据 resolve.mainFiles 配置选项中指定的文件名顺序查找,看是否能在 import/require 的目录下匹配到一个存在的文件名。
    • 然后使用 resolve.extensions 选项,以类似的方式解析文件扩展名。

什么是模块热替换

模块热替换(HMR - hot module replacement)功能会在应用程序运行过程中,替换、添加或删除 模块,而无需重新加载整个页面。

主要是通过以下几种方式,来显著加快开发速度:

  • 保留在完全重新加载页面期间丢失的应用程序状态。
  • 只更新变更内容,以节省宝贵的开发时间。
  • 在源代码中 CSS/JS 产生修改时,会立刻在浏览器中进行更新,这几乎相当于在浏览器 devtools 直接更改样式。