Webpack 知识点总结

随着现代前端开发的规模日益庞大,几乎已经不能抛开诸如 React 或 Vue 等前端开发框架来独立开发了,这些框架很大程度上的提高了我们的开发效率,但是框架中所使用特殊文件,比如 jsxvuescssless 等,浏览器是无法直接识别的,必须经过编译后才能在浏览器中使用。于是在众多的前端工程化工具中,Webpack 脱颖而出成为了当今最流行的前端构建工具。 [1]

webpack

Webpack 配置模板:

// webpack.config.js
const path = require("path");
module.exports = {
  entry: "./app/entry", // string | object | array
  // Webpack打包的入口
  output: {
    // 定义webpack如何输出的选项
    path: path.resolve(__dirname, "dist"), // string
    // 所有输出文件的目标路径
    filename: "[chunkhash].js", // string
    // 「入口(entry chunk)」文件命名模版
    publicPath: "/assets/", // string
    // 构建文件的输出目录
    /* 其它高级配置 */
  },
  module: {
    // 模块相关配置
    rules: [
      // 配置模块loaders,解析规则
      {
        test: /\.jsx?$/, // RegExp | string
        include: [
          // 和test一样,必须匹配选项
          path.resolve(__dirname, "app"),
        ],
        exclude: [
          // 必不匹配选项(优先级高于test和include)
          path.resolve(__dirname, "app/demo-files"),
        ],
        loader: "babel-loader", // 模块上下文解析
        options: {
          // loader的可选项
          presets: ["es2015"],
        },
      },
    ],
  },
  resolve: {
    //  解析模块的可选项
    modules: [
      // 模块的查找目录
      "node_modules",
      path.resolve(__dirname, "app"),
    ],
    extensions: [".js", ".json", ".jsx", ".css"], // 用到的文件的扩展
    alias: {
      // 模块别名列表
      module: "new-module",
    },
  },
  devtool: "source-map", // enum
  // 为浏览器开发者工具添加元数据增强调试
  plugins: [
    // 附加插件列表
    // ...
  ],
};

Webpack 的运行流程是怎样的?

Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:[2]
  1. 初始化参数:从配置文件 webpack.config.js 和命令行中读取与合并参数,初始化本次构建的配置参数,得出最终的参数;
  2. 开始编译:用上一步得到的参数初始化 Compiler 对象,加载配置文件的所有 plugin,执行对象的 run 方法开始执行编译;
  3. 确定入口:根据配置中的 entry 找出所有的入口文件,递归遍历所有的入口文件;
  4. 编译模块:从入口文件出发,调用所有配置的 loader 对模块进行编译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。
  5. 输出资源:所有文件的编译及转化都已经完成,也就是最终输出的资源,其中包括即将输出的资源、代码块 Chunk 等等信息。
运行流程图:[3]
Webpack 运行流程图

Webpack 的 Loader 是什么?

Webpack 只能理解 JavaScriptJSON 文件,这是 Webpack 开箱可用的自带能力。loader 可以让 Webpack 能够去处理其他类型的文件,比如 .scss.ts,并将它们转换为有效的功能离散的 chunk 文件以供应用程序使用,以及被添加到依赖图中,也可将内联图像转换为 data URL。简单来说,loader 可以将一段代码转换成另一端代码,通常用来将一段特殊代码转换成一段浏览器可识别的代码。

loader从下到上地取值(evaluate)/执行(execute),也就是是从后往前执行。在下面的示例中,从 ts-loader开始执行,然后继续执行 css-loader,最后以 raw-loader 为结束。loader 有两个属性:test,正则表达式,用于识别出哪些文件会被转换,use 定义在进行转换时应该使用哪个 loader,可以是字符串、数组和对象。[4]

// webpack.config.js
module.exports = {
  output: {
    filename: "my-first-webpack.bundle.js",
  },
  module: {
    rules: [
      { test: /\.txt$/, use: "raw-loader" }, // 通过 npm 安装
      {
        test: /\\.css$/,
        use: [
          {
            loader: "css-loader", // 通过 npm 安装
            options: { modules: true },
          },
        ],
      },
      { test: /\\.ts$/, use: "ts-loader" }, // 通过 npm 安装
    ],
  },
};

有哪些常见的 Loader ?👉 Loaders

  • raw-loader:加载文件原始内容(utf-8)
  • file-loader:把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件 (处理图片和字体)
  • url-loader:与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)
  • source-map-loader:加载额外的 Source Map 文件,以方便断点调试
  • svg-inline-loader:将压缩后的 SVG 内容注入代码中
  • image-loader:加载并且压缩图片文件
  • json-loader 加载 JSON 文件(默认包含)
  • handlebars-loader: 将 Handlebars 模版编译成函数并返回
  • babel-loader:把 ES6 转换成 ES5
  • ts-loader: 将 TypeScript 转换成 JavaScript
  • awesome-typescript-loader:将 TypeScript 转换成 JavaScript,性能优于 ts-loader
  • sass-loader:将SCSS/SASS代码转换成CSS
  • css-loader:加载 CSS,支持模块化、压缩、文件导入等特性
  • style-loader:把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS
  • postcss-loader:扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀
  • eslint-loader:通过 ESLint 检查 JavaScript 代码
  • tslint-loader:通过 TSLint检查 TypeScript 代码
  • mocha-loader:加载 Mocha 测试用例的代码
  • coverjs-loader:计算测试的覆盖率
  • vue-loader:加载 Vue.js 单文件组件
  • i18n-loader: 国际化
  • cache-loader: 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里

Webpack 的 Plugin 是什么?

loader 用于转换某些类型的模块,而 plugin(插件)则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。想要使用一个 plugin,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过 option 自定义,也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例。[5]

// webpack.config.js
const webpack = require('webpack'); // 用于访问内置插件
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装

module.exports = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

有哪些常见的 Plugin ?Plugins

  • define-plugin:定义环境变量 (Webpack4 之后指定 mode 会自动配置)
  • ignore-plugin:忽略部分文件
  • html-webpack-plugin:简化 HTML 文件创建 (依赖于 html-loader)
  • web-webpack-plugin:可方便地为单页应用输出 HTML,比 html-webpack-plugin 好用
  • uglifyjs-webpack-plugin:不支持 ES6 压缩 (Webpack4 以前)
  • terser-webpack-plugin: 支持压缩 ES6 (Webpack4)
  • webpack-parallel-uglify-plugin: 多进程执行代码压缩,提升构建速度
  • mini-css-extract-plugin: 分离样式文件,CSS 提取为独立文件,支持按需加载 (替代extract-text-webpack-plugin)
  • serviceworker-webpack-plugin:为网页应用增加离线缓存功能
  • clean-webpack-plugin: 目录清理
  • ModuleConcatenationPlugin: 开启 Scope Hoisting
  • speed-measure-webpack-plugin: 可以看到每个 Loader 和 Plugin 执行耗时 (整个打包耗时、每个 Plugin 和 Loader 耗时)
  • webpack-bundle-analyzer: 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块)

Webpack 的热更新原理是怎样的?

Webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。

HMR 工作流程

  1. Webpack 通过 Watch 模式可以侦听文件的变化,当文件发生改变时,会根据配置进行重新编译(Compile),并将编译后的代码保存在内存中。
  2. webpack-dev-server 也会对文件变化进行监控(需要配置 devServer.watchContentBase = true),但不会进行重新编译,而是监听这些配置文件中静态文件的变化,变化后会通知浏览器进行直接刷新,而不是 HMR
  3. 在浏览器和服务端之间有一个通过 SocketJs 建立的 websocket 长连接。webpack-dev-server 会将 Webpack 编译打包时的各个阶段的状态信息和 hash 值一并告知 webpack-dev-server/client(位于浏览器端)。
  4. 但是 webpack-dev-server/client 并不能够请求更新的代码,而是把这些工作交给了 webpack/hot/dev-serverwebpack/hot/dev-server 的工作就是根据 webpack-dev-server/client 传来的信息以及 dev-server 的配置决定是刷新浏览器还是 HMR
  5. HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到 webpack/hot/dev-server 传递的新模块的 hash 值,通过 JsonpMainTemplate.runtimewebpack-dev-server 发送 Ajax 请求获取到返回的 Json,该 Json 包含了所有要更新的模块的 hash 值,之后通过 Jsonp 请求,获取到最新的模块代码。
  6. 接下来,HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
  7. 如果 HMR 失败,则通过刷新浏览器来获取最新打包代码。

  1. 关于webpack的面试题

  2. 「吐血整理」再来一打Webpack面试题

  3. Webpack揭秘

  4. loaders

  5. plugins

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351