神族九帝's blog 神族九帝's blog
首页
  • 神卡套餐 (opens new window)
  • 神族九帝 (opens new window)
  • 网盘资源 (opens new window)
  • 今日热点 (opens new window)
  • 在线PS (opens new window)
  • IT工具 (opens new window)
  • FC游戏 (opens new window)
  • 在线壁纸 (opens new window)
  • 面试突击
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 工作笔记
  • 前端基础建设与架构 30 讲
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • 思维导图
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • React
  • 更多
  • 未来要做的事
  • Stirling-PDF
  • ComfyUI
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 收藏夹
  • 更多
GitHub (opens new window)

神族九帝,永不言弃

首页
  • 神卡套餐 (opens new window)
  • 神族九帝 (opens new window)
  • 网盘资源 (opens new window)
  • 今日热点 (opens new window)
  • 在线PS (opens new window)
  • IT工具 (opens new window)
  • FC游戏 (opens new window)
  • 在线壁纸 (opens new window)
  • 面试突击
  • 复习指导
  • HTML
  • CSS
  • JavaScript
  • 设计模式
  • 浏览器
  • 手写系列
  • Vue
  • Webpack
  • Http
  • 前端优化
  • 项目
  • 面试真题
  • 算法
  • 精选文章
  • 八股文
  • 前端工程化
  • 工作笔记
  • 前端基础建设与架构 30 讲
  • vue2源码学习
  • 剖析vuejs内部运行机制
  • TypeScript 入门实战笔记
  • vue3源码学习
  • 2周刷完100道前端优质面试真题
  • 思维导图
  • npm发包
  • 重学node
  • 前端性能优化方法与实战
  • webpack原理与实战
  • webGl
  • 前端优化
  • Web3
  • React
  • 更多
  • 未来要做的事
  • Stirling-PDF
  • ComfyUI
  • 宝塔面板+青龙面板
  • 安卓手机当服务器使用
  • 京东自动评价代码
  • 搭建x-ui免流服务器(已失效)
  • 海外联盟
  • 好玩的docker
  • 收藏夹
  • 更多
GitHub (opens new window)
  • 工作笔记

  • 前端基础建设与架构 30 讲

  • vue2源码学习

  • 剖析vuejs内部运行机制

  • TypeScript 入门实战笔记

  • vue3源码学习

  • 2周刷完100道前端优质面试真题

  • 思维导图

  • npm发包

  • 重学node

  • 前端性能优化方法与实战

  • webpack原理与实战

    • 开篇词:Webpack 现代化前端应用的基石
    • 第01讲:Webpack 究竟解决了什么问题?
    • 第02讲:如何使用 Webpack 实现模块化打包?
    • 第03讲:如何通过 Loader 实现特殊资源加载?
    • 第04讲:如何利用插件机制横向扩展 Webpack 的构建能力?
    • 第05讲:探索 Webpack 运行机制与核心工作原理
    • 第06讲:如何使用 Dev Server 提高你的本地开发效率?
    • 第07讲:如何配置 Webpack SourceMap 的最佳实践?
    • 第08讲:如何让你的模块支持热替换(HMR)机制?
    • 第09讲:Tree Shaking 和 sideEffects
    • 第10讲:Code Splitting(分块打包)
    • 第11讲:如何优化Webpack的构建速度和打包结果
      • 第12讲:如何选择打包工具:Rollup 和 Webpack ?
      • 第13讲:如何使用 Parcel 零配置完成打包任务?
      • 加餐:Vue3 到底带来了哪些变化
    • webGl

    • 前端优化

    • Web3

    • React

    • 更多

    • 笔记
    • webpack原理与实战
    wu529778790
    2021-11-09

    第11讲:如何优化Webpack的构建速度和打包结果

    我们分别尝试一下通过这两种方式,为开发环境和生产环境创建不同配置。

    首先我们来看在配置文件中添加判断的方式。我们回到配置文件中,Webpack 配置文件还支持导出一个函数,然后在函数中返回所需要的配置对象。这个函数可以接收两个参数,第一个是 env,是我们通过 CLI 传递的环境名参数,第二个是 argv,是运行 CLI 过程中的所有参数。具体代码如下:

    20211109223103

    那我们就可以借助这个特点,为开发环境和生产环境创建不同配置。我先将不同模式下公共的配置定义为一个 config 对象,具体代码如下:

    20211109223119

    然后通过判断,再为 config 对象添加不同环境下的特殊配置。具体如下:

    20211109223136

    例如这里,我们判断 env 等于 development(开发模式)的时候,我们将 mode 设置为 development,将 devtool 设置为 cheap-eval-module-source-map;而当 env 等于 production(生产模式)时,我们又将 mode 和 devtool 设置为生产模式下需要的值。

    当然,你还可以分别为不同模式设置其他不同的属性、插件,这也都是类似的。

    通过这种方式完成配置过后,我们打开命令行终端,这里我们再去执行 webpack 命令时就可以通过 --env 参数去指定具体的环境名称,从而实现在不同环境中使用不同的配置。

    那这就是通过在 Webpack 配置文件导出的函数中对环境进行判断,从而实现不同环境对应不同配置。这种方式是 Webpack 建议的方式。

    你也可以直接定义环境变量,然后在全局判断环境变量,根据环境变量的不同导出不同配置。这种方式也是类似的,这里我们就不做过多介绍了。

    不同环境的配置文件

    通过判断环境名参数返回不同配置对象的方式只适用于中小型项目,因为一旦项目变得复杂,我们的配置也会一起变得复杂起来。所以对于大型的项目来说,还是建议使用不同环境对应不同配置文件的方式来实现。

    一般在这种方式下,项目中最少会有三个 webpack 的配置文件。其中两个用来分别适配开发环境和生产环境,另外一个则是公共配置。因为开发环境和生产环境的配置并不是完全不同的,所以需要一个公共文件来抽象两者相同的配置。具体配置文件结构如下:

    20211109223245

    首先我们在项目根目录下新建一个 webpack.common.js,在这个文件中导出不同模式下的公共配置;然后再来创建一个 webpack.dev.js 和一个 webpack.prod.js 分别定义开发和生产环境特殊的配置。

    在不同环境的具体配置中我们先导入公共配置对象,然后这里可以使用 Object.assign 方法把公共配置对象复制到具体环境的配置对象中,并且同时去覆盖其中的一些配置。具体如下:

    20211109223313

    如果你熟悉 Object.assign 方法,就应该知道,这个方法会完全覆盖掉前一个对象中的同名属性。这个特点对于普通值类型属性的覆盖都没有什么问题。但是像配置中的 plugins 这种数组,我们只是希望在原有公共配置的插件基础上添加一些插件,那 Object.assign 就做不到了。

    所以我们需要更合适的方法来合并这里的配置与公共的配置。你可以使用 Lodash 提供的 merge 函数来实现,不过社区中提供了更为专业的模块 webpack-merge,它专门用来满足我们这里合并 Webpack 配置的需求。

    我们可以先通过 npm 安装一下 webpack-merge 模块。具体命令如下:

    npm i webpack-merge --save-dev
    # or yarn add webpack-merge --dev
    

    安装完成过后我们回到配置文件中,这里先载入这个模块。那这个模块导出的就是一个 merge 函数,我们使用这个函数来合并这里的配置与公共的配置。具体代码如下:

    20211109223427

    使用 webpack-merge 过后,我们这里的配置对象就可以跟普通的 webpack 配置一样,需要什么就配置什么,merge 函数内部会自动处理合并的逻辑。

    分别配置完成过后,我们再次回到命令行终端,然后尝试运行 webpack 打包。不过因为这里已经没有默认的配置文件了,所以我们需要通过 --config 参数来指定我们所使用的配置文件路径。例如:

    webpack --config webpack.prod.js
    

    当然,如果你觉得这样操作让我们的命令变得更复杂了,那你可以把这个构建命令定义到 npm scripts 中,方便使用。

    生产模式下的优化插件

    在 Webpack 4 中新增的 production 模式下,内部就自动开启了很多通用的优化功能。对于使用者而言,开箱即用是非常方便的,但是对于学习者而言,这种开箱即用会导致我们忽略掉很多需要了解的东西。以至于出现问题无从下手。


    如果你想要深入了解 Webpack 的使用,我建议你去单独研究每一个配置背后的作用。这里我们先一起学习 production 模式下几个主要的优化功能,顺便了解一下 Webpack 如何优化打包结果。

    Define Plugin

    首先是 DefinePlugin,DefinePlugin 是用来为我们代码中注入全局成员的。在 production 模式下,默认通过这个插件往代码中注入了一个 process.env.NODE_ENV。很多第三方模块都是通过这个成员去判断运行环境,从而决定是否执行例如打印日志之类的操作。

    这里我们来单独使用一下这个插件。我们回到配置文件中,DefinePlugin 是一个内置的插件,所以我们先导入 webpack 模块,然后再到 plugins 中添加这个插件。这个插件的构造函数接收一个对象参数,对象中的成员都可以被注入到代码中。具体代码如下:

    20211109223608

    例如我们这里通过 DefinePlugin 定义一个 API_BASE_URL,用来为我们的代码注入 API 服务地址,它的值是一个字符串。

    然后我们回到代码中打印这个 API_BASE_URL。具体代码如下:

    完成以后我们打开控制台,然后运行 webpack 打包。打包完成过后我们找到打包的结果,然后找到 main.js 对应的模块。具体结果如下:

    20211109223624

    这里我们发现 DefinePlugin 其实就是把我们配置的字符串内容直接替换到了代码中,而目前这个字符串的内容为 https://api.example.com,字符串中并没有包含引号,所以替换进来语法自然有问题。

    正确的做法是传入一个字符串字面量语句。具体实现如下:

    20211109223720

    这样代码内的 API_BASE_URL 就会被替换为 "https://api.example.com"。具体结果如下:

    20211109223745

    另外,这里有一个非常常用的小技巧,如果我们需要注入的是一个值,就可以通过 JSON.stringify 的方式来得到表示这个值的字面量。这样就不容易出错了。具体实现如下:

    20211109223810

    DefinePlugin 的作用虽然简单,但是却非常有用,我们可以用它在代码中注入一些可能变化的值。

    Mini CSS Extract Plugin

    对于 CSS 文件的打包,一般我们会使用 style-loader 进行处理,这种处理方式最终的打包结果就是 CSS 代码会内嵌到 JS 代码中。

    mini-css-extract-plugin 是一个可以将 CSS 代码从打包结果中提取出来的插件,它的使用非常简单,同样也需要先通过 npm 安装一下这个插件。具体命令如下:

    npm i mini-css-extract-plugin --save-dev
    

    安装完成过后,我们回到 Webpack 的配置文件。具体配置如下:

    20211109223900

    我们这里先导入这个插件模块,导入过后我们就可以将这个插件添加到配置对象的 plugins 数组中了。这样 Mini CSS Extract Plugin 在工作时就会自动提取代码中的 CSS 了。

    除此以外,Mini CSS Extract Plugin 还需要我们使用 MiniCssExtractPlugin 中提供的 loader 去替换掉 style-loader,以此来捕获到所有的样式。

    这样的话,打包过后,样式就会存放在独立的文件中,直接通过 link 标签引入页面。

    不过这里需要注意的是,如果你的 CSS 体积不是很大的话,提取到单个文件中,效果可能适得其反,因为单独的文件就需要单独请求一次。个人经验是如果 CSS 超过 200KB 才需要考虑是否提取出来,作为单独的文件。

    Optimize CSS Assets Webpack Plugin

    使用了 Mini CSS Extract Plugin 过后,样式就被提取到单独的 CSS 文件中了。但是这里同样有一个小问题。

    我们回到命令行,这里我们以生产模式运行打包。那按照之前的了解,生产模式下会自动压缩输出的结果,我们可以打开打包生成的 JS 文件。具体结果如下:

    20211109224019

    然后我们再打开输出的样式文件。具体结果如下:

    20211109224100

    这里我们发现 JavaScript 文件正常被压缩了,而样式文件并没有被压缩。

    这是因为,Webpack 内置的压缩插件仅仅是针对 JS 文件的压缩,其他资源文件的压缩都需要额外的插件。

    Webpack 官方推荐了一个 Optimize CSS Assets Webpack Plugin 插件。我们可以使用这个插件来压缩我们的样式文件。

    我们回到命令行,先来安装这个插件,具体命令如下:

    npm i optimize-css-assets-webpack-plugin --save-dev
    

    安装完成过后,我们回到配置文件中,添加对应的配置。具体代码如下:

    20211109224206

    这里同样先导入这个插件,导入完成以后我们把这个插件添加到 plugins 数组中。

    那此时我们再次回到命令行运行打包。

    打包完成过后,我们的样式文件就会以压缩格式输出了。具体结果如下:

    20211109224227

    不过这里还有个额外的小点,可能你会在这个插件的官方文档中发现,文档中的这个插件并不是配置在 plugins 数组中的,而是添加到了 optimization 对象中的 minimizer 属性中。具体如下:

    20211109224320

    那这是为什么呢?

    其实也很简单,如果我们配置到 plugins 属性中,那么这个插件在任何情况下都会工作。而配置到 minimizer 中,就只会在 minimize 特性开启时才工作。

    所以 Webpack 建议像这种压缩插件,应该我们配置到 minimizer 中,便于 minimize 选项的统一控制。

    但是这么配置也有个缺点,此时我们再次运行生产模式打包,打包完成后再来看一眼输出的 JS 文件,此时你会发现,原本可以自动压缩的 JS,现在却不能压缩了。具体 JS 的输出结果如下:

    那这是因为我们设置了 minimizer,Webpack 认为我们需要使用自定义压缩器插件,那内部的 JS 压缩器就会被覆盖掉。我们必须手动再添加回来。

    内置的 JS 压缩插件叫作 terser-webpack-plugin,我们回到命令行手动安装一下这个模块。

    npm i terser-webpack-plugin --save-dev
    

    安装完成过后,这里我们再手动添加这个模块到 minimizer 配置当中。具体代码如下:

    20211109224447


    # 精选评论

    # **春:

    老师,你的 git 仓库地址是啥。想看看代码

    #     讲师回复:

        https://github.com/zce/webpack-demo

    # **程:

    我想问下 loader 是倒序执行的,那 optimization 的 minimizer 也是倒序 执行 吗?

    #     讲师回复:

        每种资源最终只需要使用一个 minimizer,不回涉及到多个压缩器同时压缩同一个资源的情况,也就不会有先后执行的问题

    # **德:

    webpack5 可以用 '...' 把默认的 minimizer 展开,方便很多了

    编辑 (opens new window)
    上次更新: 2025/03/11, 11:29:39
    第10讲:Code Splitting(分块打包)
    第12讲:如何选择打包工具:Rollup 和 Webpack ?

    ← 第10讲:Code Splitting(分块打包) 第12讲:如何选择打包工具:Rollup 和 Webpack ?→

    最近更新
    01
    Code Review
    10-14
    02
    ComfyUI
    10-11
    03
    vscode插件开发
    08-24
    更多文章>
    Power by vuepress | Copyright © 2015-2025 神族九帝
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×