Webpack: 前端资深构建工具

概述

  • 如果你是一名前端工程师,相信之前或多或少听过、用过 Webpack 这一构建工具,它能够融合多种工程化工具,将开发阶段的应用代码编译、打包成适合网络分发、客户端运行的应用产物
  • 如今,Webpack 已经深深渗入到前端工程的方方面面,几乎已经成为我们日常工作绕不过去的必备基础设施之一
  • 问题是,我们为什么需要使用这种非常复杂的构建工具?我认为最大的原因是:时代变了

构建工具的发展

  • 在远古时代,我们只能用原生 JavaScript(ES5)、CSS、HTML 方式编写页面代码,开发与生产环境代码基本一致,开发与运行效率都非常低;
  • 其次,页面的图片、代码、CSS 等资源都能且只能通过 imgscriptlink 等标签插入到页面中,我们需要非常精细地管理、设计各个标签出现的位置、顺序,这也会占用我们非常多的精力与注意力
  • 直到 2009年 Node 与 RequireJS 的出现才打破这一僵局,让我们在代码被放到浏览器运行起来之前,有机会做一些预处理工作 —— 开发与生产环境终于有了隔离管理的实现方案
  • 再往后,出现了越来越多解决具体问题的效率工具,我们开始尝试使用 Babel、TypeScript、CoffeeScript 等,绕过 ES5 诸多低效语言特性、陷阱;尝试通过 Less、Sass、Stylus 等工具,为页面样式开发引入逻辑运算、数学运算、嵌套、继承等结构化语言特性,等等
  • 这些工程化工具能不同程度弥补浏览器、语言、规范本身的设计缺陷,我们终于不需要再关注一些低效的技术细节、Trick,将更多注意力放在业务代码上,以更高效的方式方法编写出越来越复杂、庞大的 Web 应用
  • 这个阶段前端领域可谓蓬勃发展,前端工程师的能力边界也在不断扩大,但却引来了另一个问题:如何管理这些工具与工具背后的工程化逻辑?我们需要一套足够开放,能融合诸多工程化工具,彻底抹平开发与生产环境差异的一体化工程方案,这也正是 Webpack 需要解决的问题

为什么是 Webpack?

  • Webpack 是一种用于构建 JavaScript 应用程序的静态模块打包器,它能够以一种相对一致且开放的处理方式,加载应用中的所有资源文件(图片、CSS、视频、字体文件等),并将其合并打包成浏览器兼容的 Web 资源文件。
  • 注意,上面说的“一致且开放”的加载模型,这在当时算的上是非常 Breaking Change 的设计!

  • Webpack 之前社区虽然已经实现了许多模块打包器,例如 Gulp、Grunt、RequireJS、Browserify、Closure Compiler 等,但它们或简单合并执行多种构建任务;或聚焦于模块化方案的兼容处理;或仅仅实现 JavaScript 层面的工程化(合并、压缩、混淆)能力,都缺乏一个能够兼容处理所有资源、普适的抽象思维框架 —— 这意味着应对不同资源,需要使用不同的特化处理逻辑,且不同类型文件之间无法信息互通。

  • 而 Webpack 则忽略具体资源类型之间的差异,将所有代码/非代码文件都统一看作 Module —— 模块对象,以相同的加载、解析、依赖管理、优化、合并流程实现打包,并借助 Loader、Plugin 两种开放接口将资源差异处理逻辑转交由社区实现,实现统一资源构建模型,这种设计有很多优点:

    • 所有资源都是 Module,所以可以用同一套代码实现诸多特性,包括:代码压缩、Hot Module Replacement、缓存等;
    • 打包时,资源与资源之间非常容易实现信息互换,例如可以轻易在 HTML 插入 Base64 格式的图片;
    • 借助 Loader,Webpack 几乎可以用任意方式处理任意类型的资源,例如可以用 Less、Stylus、Sass 等预编译 CSS 代码。
  • 甚至在 Webpack 之后出现的许多新打包工具,例如 Rollup、Parcel、Snowpack 等,都或多或少受这种设计影响。

  • 其次,Webpack 极强的开放性,也让它得以成为前端工程化环境的 基座,我们可以围绕 Webpack 轻易接入一系列工程化工具,例如 TypeScript、CoffeScript、Babel 一类的 JavaScript 编译工具;或者 Less、Sass、Stylus、PostCSS 等 CSS 预处理器;或者 Jest、Karma 等测试框架,等等。

  • 这些工具都不同程度上补充了 Webpack 不同方面的工程化能力,使得它能够成为一个大一统的资源处理框架,满足现代 Web 工程在效率、质量、性能等方面的诉求,甚至能够应对小程序、微前端、SSR、SSG、桌面应用程序、NPM 包等诸多应用场景。也因此,即使在当下百花齐放的 Web 工程化领域中,Webpack 依然是最为广泛使用的构建工具之一。

  • 截止目前,Webpack 已经发布了最新的 5.92.1 版本,经过 5 个大版本迭代以及社区的不断努力,现如今的 Webpack 已经非常非常成熟,在基础构建能力之外还提供了诸多锦上添花的工程化工具,包括:

    • 基于 Module Federation 的微前端方案;
    • 基于 webpack-dev-server 的 Hot Module Replacement ;
    • 基于 Terser、Tree-shaking、SplitChunks 等工具的 JavaScript 代码压缩、优化、混淆方案;
    • 基于 lazyCompilation 的延迟编译功能;
  • 有利于提升应用性能的异步模块加载能力;

  • 有利于提升构建性能的持久化缓存能力;

  • 内置 JavaScript、JSON、二进制资源解析、生成能力;

  • ……

  • 并且,自 2012 年首次发布至今,Webpack 还处于快速迭代成长阶段,社区依然保持极大活力,算是真真正正经得起时间考验的开源项目。在可预期的未来,Webpack 依然会占据极大市场份额,依然是我们手头上几乎万能的瑞士军刀。

Webpack 还有学习价值吗?

  • 如今,Webpack 已经发展的几乎无所不能,但代价则是上手学习成本非常高,学习曲线非常陡峭!

  • 这一方面是因为 Webpack 确实是一个极度复杂的构建系统,应用层面、实现层面都有非常多不明觉厉的名词、概念、逻辑模型。另一方面是缺少特别优质的学习资料,Webpack 官方虽然也提供了许多说明文档,但基本上都停留在应用层面;国内外社区也有一些优质文章、视频教程,但数量偏少,缺乏体系化与深度。

那么,问题来了,这么难的一件事情,我们真的有必要学吗?

  • 非常有必要!正是因为 Webpack 很难,静得下心来深挖的人少,所以 深入学习 Webpack,不仅能帮助你更快解决具体的工程技术问题,还能形成属于你个人的,极具区分度的核心竞争力!

  • 对于很多开发同学,很长时间都停留在极其浅层的应用阶段 —— 所谓的配置工程师,每次启动一个新的 Web 项目时,都会优先选用 Vue CLI、Create-React-App、Yeoman 等工具先搭好项目脚手架,这个阶段不需要关心怎么写 Webpack 配置,用哪些 Plugin、Loader 等。

  • 但在项目后期需要添加一些针对性的功能,或解决疑难杂症,或做一些构建性能优化时,往往就需要不断翻阅资料,花大量时间才找到正确答案。问题是,这种方式只能解决眼下具体问题,下一个问题出现时,还是得重复花费大量时间翻阅资料,学习效率极低。

  • 终于有天,当你受不了这种重复浪费时间的行为,沉下心来翻阅资料,甚至研读源码之后,才算是理解了内里的许多乾坤,能够通过调整配置、自定义 Loader/Plugin 等方式,迅速解决许多业务中出现的问题。这种能力持续沉淀,茁壮发展之后,逐渐成了区分于其他同学的非常重要的竞争力。

其次,在当下 Vite、WMR、Snowpack 等新一代 Unbundle 工具百花齐放的背景下,我们还有必要花这么大力气学 Webpack 吗?

  • 第一,根据 State-of-JS 2021 的统计数据,2021年 Webpack 还保持高达 75% 的使用率,依然是大多数!虽然未来必然会有许多用户在特定场景下选用其它构建工具,但短期内还不太可能撼动 Webpack 的头部地位。
  • 到了 2022版本 State-of-JS 2022,Webpack 降低到了 63.2%,Vite 依旧是榜首,之后的数据还没有出来
  • 第二,Vite 一类 Unbundle 工具定位于解决特定问题,而 Webpack 则几乎无所不能,功能覆盖小程序、桌面应用、微前端、WASM 等诸多场景,许多情况下 Webpack 依然是最优解,当然Vite也在进化中,也有了一些出色的解决方案

  • 第三,同类工具或多或少都有借鉴 Webpack 之处,虽然具体实现差异很大,但解决工程化问题的思路基本一致,所谓一通百通,深入理解 Webpack 底层逻辑,以及处理具体问题的方式方法后,相同的知识必然也能套用到同类工具中。

  • 第四,Webpack 还在持续迭代发展,V5 之后推出的持久化缓存、lazyCompilation 等特性极大强化了构建性能,未来虽不大可能超越 Unbundle 方案的性能优势,但相信会逐渐缩小差距,直至可被用户接受。

  • 所以,Webpack 依然是一个值得长期投入学习,对个人、团队都极具成长意义的技术方向。

如何高效学习 Webpack?

  • 既然 Webpack 应用范围这么广,学习价值这么高,为何社区相关的技术讨论热度却一直不愠不火呢?我认为最主要的原因还是在于 Webpack 实在太复杂了:上百种内置配置项,7万多行代码,以及几乎数不清的开源/闭源组件,涉及的知识点多、杂、深,已经不能仅仅停留在单一构建工具层面,而是需要扩展开来学习一整套工程化思维与方法论。

  • 在这种背景下,我们该如何学透这么复杂繁琐的内容,深度掌握 Webpack 应用方法与实现原理呢?答案是:由浅入深、循序渐进,有章法有体系地学

  • 具体怎么个“由浅入深”、“有体系”法?我认为比较高效的学习路径应该是:

第一步:上手实践各种场景下的构建配置方法,捋清楚最基本的使用规则。

  • Webpack 始终是一个工具,就像一把瑞士军刀,无论你多了解它的组成结构,有多精深的理论知识,没有经过大量实战应用,你就始终还是停留在门外汉水平。

  • 不过,即使只是考虑“怎么用”,问题已经很复杂了,毕竟光 Webpack 内置的就有上百种配置项,且许多配置规则 —— 如 devtoolmoduleresolve ,背后都隐含一套自洽但晦涩的工程逻辑 —— 即使你已经是一个比较资深的前端,也大概率需要花费不少时间才能理解这些工程逻辑。

  • 延展开来,为了应对各种场景下特化的资源处理需求,社区还实现了数千种 Loader、Plugin 组件,这些组件本身各自解决了什么问题?怎么用?怎么串联起来放一起用?等等。

  • 这里的重点是,通过各种应用场景摸清使用规律,结构化地理解各基础配置项与常见组件的用法。

第二步:初步理解底层构建流程,学会分析性能卡点并据此做出正确性能优化。

  • 只会用还不行,你还得学会怎么用好,怎么用尽可能少的时间构建出性能足够好的应用。这部分涉及内容比较广,纵向可以深挖到操作系统、计算机网络原理等,横向可以扩展到 ECMAScript 规范、多媒体资源编解码等,关键在于掌握分析方法,理解底层机制,做到融会贯通,举一反三。

第三步:深入 Webpack 扩展规则,理解 Loader 与 Plugin 能做什么,怎么做。

  • 在会用且用的比较好的基础上,我们就该开始琢磨琢磨 Loader 与 Plugin 这两种扩展方式了。
  • 实际上,Webpack 主体只是实现了最核心的构建工具流与 Loader、Plugin 架构,大部分具体功能都是通过具体插件与 Loader 实现的
  • 所以,学习这两种扩展组件的开发方法,进而理解两者能做什么、怎么做等,一是能帮助我们更深层次理解 Webpack 的构建过程;二是在遇到疑难杂症时能帮助我们迅速定位问题位置;三是必要时可以自己上手实现一些定制需求。

第四步:深挖源码,理解 Webpack 底层工作原理,加强应用与扩展能力。

  • 经过上面三个步骤,相信你已经成为一个非常成熟的 Webpack 使用者,但知其然还需知其所以然,接下来我们还是得深入 Webpack 源码,学习从启动构建,到递归编译模块代码,到封装打包,再到代码优化最终输出资产文件整个过程
  • 只有理解了这个过程我们才算是真正吃透 Webpack 应用到原理整个知识体系,才能更深入理解各个配置项到底作用在哪些位置;哪些步骤容易造成性能卡点,我们要怎么优化;各个 Hook 到底在什么时间点,怎么触发等等

Webpack 5 的知识体系


我们按照四个方向展开:

  • 基础用法篇:首先,我会聚焦在应用层面,先简要讲解 Webpack 基本配置规则;之后针对具体场景、技术栈介绍更具体的方法、工具与技巧,例如:如何搭建完备的 JavaScript、CSS 开发环境;如何搭建微前端、NPM 包、桌面应用等,帮助你成为 纯熟的 Webpack 使用者
  • 性能优化篇:熟练基本使用方法后,我们会开始关注构建与应用性能方面,这部分我打算先介绍如何分析构建性能,以及若干实用性能分析工具;之后从 Webpack 底层原理以及诸多计算机原理出发,倒推 Webpack 构建以及 Web 应用性能优化方法与理论依据,让你 能够应对各种各式各样的性能问题
  • 扩展能力篇:会用且知道怎么更好应用之后,我们会开始关注 Webpack 扩展技巧,我会首先解释 Loader、Plugin 两种组件的作用、形态与基本设计逻辑,让你对两种组件有一个感性认知;其次我会从若干知名开源项目中提炼出一些常见的功能用例,实例剖析如何在 Loader 与 Plugin 实现各式各样的功能需求;最后,我还会介绍如何借助若干开发工具实现一些非功能需求,包括:调试、测试、日志、参数校验等等。最终,必然能让你深度理解这两种扩展方式,有能力开发出足够健壮、优雅的功能组件
  • 核心原理篇:最后,我会抽丝剥茧,用尽可能通俗易懂的话语带你过一遍 Webpack 的主要构建流程,之后介绍源码中一些非常重要的设计概念,包括 Dependency Graph、Chunk、Runtime 等,帮你在脑海中架构起 Webpack 底层运行模型。在此基础上,再深入剖析Webpack 体系下如何实现 Tree-Shaking、HMR、Sourcemap 这几个特别有代表性的功能,务必让你能串起整个构建框架,成为 Webpack 资深玩家

总结

  • 最后,学习 Webpack 是一件小众、难度大,需要付出大量精力与耐心的事情,但它能帮助你沉淀更深层次的前端工程技能,让你在日常业务开发技能之外积累更有竞争力的技术能力
  • 多总结可以在学习 Webpack 的路上少走弯路,高效学习,彻底掌握核心原理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/35154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单了解IoC

IoC 什么是IoC? IoC(Inversion of Control),即控制反转,这是一种设计思想,在Spring指将对象的控制权交给Spring容器,由容器来实现对象的创建、管理,程序员只需要从容器获取想要的对…

java设计模式(四)原型模式(Prototype Pattern)

1、模式介绍: 原型模式(Prototype Pattern)是一种创建型设计模式,它允许对象在创建新实例时通过复制现有实例而不是通过实例化新对象来完成。这样做可以避免耗费大量的资源和时间来初始化对象。原型模式涉及一个被复制的原型对象…

ES6模板字符串详解

ES6是JavaScript语言的一次重大更新,引入了许多新特性和语法改进,其中模板字符串是一个非常实用和灵活的语法特性。它可以让我们从数组或对象中提取值,并赋给对应的变量,让代码变得更加简洁和易读。 本文将深入探讨ES6解构赋值的语…

Nginx开发--动静分离和URLRewrite

05 【动静分离和URLRewrite】 1.动静分离介绍 为了提高网站的响应速度,减轻程序服务器(Tomcat,Jboss等)的负载,对于静态资源,如图片、js、css等文件,可以在反向代理服务器中进行缓存&#xff…

减少液氮罐内液氮损耗的方法

监测与管理液氮容器的密封性能 液氮容器的密封性能直接影响液氮的损耗情况。一个常见的损耗源是容器本身的密封不良或老化导致的泄漏。为了有效减少液氮损耗,首先应当定期检查液氮容器的密封性能。这可以通过简单的方法如肉眼检查外观,或者更精确的方法…

xxl-job 分布式任务调度 基本使用

xxl-job 是一个分布式任务调度平台,使用非常方便。 官网:https://gitee.com/xuxueli0323/xxl-job 工作原理类似于nacos 执行器注册到调度中心 调度中心分配任务 执行器执行任务 docker-compose 配置 version: 3 services:xxl-job:image: xuxueli/xxl-…

科普文:外贸垃圾邮件判定

国外垃圾邮件判定规则 很多时候,外贸的沟通多以邮件为主,他们作为专业的采购商,每天邮箱里都会塞满了邮件。因此,为了提高工作效率,很多国外客户喜欢使用垃圾邮件过滤器来过滤掉一部分垃圾邮件。 以下几种情况会触发垃…

《重构》读书笔记【第1章 重构,第一个示例,第2章 重构原则】

文章目录 第1章 重构,第一个示例1.1 重构前1.2 重构后 第2章 重构原则2.1 何谓重构2.2 两顶帽子2.3 为何重构2.4 何时重构2.5 重构和开发过程 第1章 重构,第一个示例 我这里使用的IDE是IntelliJ IDEA 1.1 重构前 plays.js export const plays {&quo…

AcWing算法基础课笔记——高斯消元

高斯消元 用来求解方程组 a 11 x 1 a 12 x 2 ⋯ a 1 n x n b 1 a 21 x 1 a 22 x 2 ⋯ a 2 n x n b 2 … a n 1 x 1 a n 2 x 2 ⋯ a n n x n b n a_{11} x_1 a_{12} x_2 \dots a_{1n} x_n b_1\\ a_{21} x_1 a_{22} x_2 \dots a_{2n} x_n b_2\\ \dots \\ a…

论文导读 | Manufacturing Service Operations Management近期文章精选

编者按 在本系列文章中,我们梳理了顶刊Manufacturing & Service Operations Management5月份发布有关OR/OM以及相关应用的文章之基本信息,旨在帮助读者快速洞察行业/学界最新动态。 推荐文章1 ● 题目:Robust Drone Delivery with Weath…

【C++题解】1712. 输出满足条件的整数2

问题:1712. 输出满足条件的整数2 类型:简单循环 题目描述: 有这样的三位数,其百位、十位、个位的数字之和为偶数,且百位大于十位,十位大于个位,请输出满所有满足条件的整数。 输入&#xff1…

#05搜索法

要点: ①搜索法:穷举搜索、深度优先搜索、广度优先搜索、广深结合搜索、回溯法、分支限界法; ②解空间树:子集树、排列树、满m叉树。 ③回溯法及分支限界法求解问题的方法与步骤。 难点: 子集树、排列树和满m叉树…

小程序下拉刷新,加载更多数据,移动端分页

文章目录 页面结构图WXML页面代码js代码wxss代码总结备注 参考&#xff1a;https://juejin.cn/post/7222855604406796346 页面结构图 一般页面就4个结构&#xff1a;最外滚动层、数据展示层、暂无数据层、没有更多数据层。 如图&#xff1a; WXML页面代码 <scroll-view …

Golang | Leetcode Golang题解之第191题位1的个数

题目&#xff1a; 题解&#xff1a; func hammingWeight(num uint32) (ones int) {for ; num > 0; num & num - 1 {ones}return }

# Kafka_深入探秘者(5):kafka 分区

Kafka_深入探秘者&#xff08;5&#xff09;&#xff1a;kafka 分区 一、kafka 副本机制 1、Kafka 可以将主题划分为多个分区(Partition)&#xff0c;会根据分区规则选择把消息存储到哪个分区中&#xff0c;只要如果分区规则设置的合理&#xff0c;那么所有的消息将会被均匀的…

Golang | Leetcode Golang题解之第198题打家劫舍

题目&#xff1a; 题解&#xff1a; func rob(nums []int) int {if len(nums) 0 {return 0}if len(nums) 1 {return nums[0]}first : nums[0]second : max(nums[0], nums[1])for i : 2; i < len(nums); i {first, second second, max(first nums[i], second)}return se…

openEuler离线安装nginx

目录 1.创建储存目录 2.切换到储存目录 3.首先在外网的环境下下载nginx的rpm包 4.目录打包tar包拷贝到离线路径 5.安装nginx 6.启动 nginx 7.停止 nginx 8.重新加载 nginx 配置 9.重新启动 nginx&#xff08;先停止再启动 nginx&#xff09; 10.检查 nginx 服务…

【分布式系统】Zookeeper学习笔记

基本概念 Zookeeper工作机制 从设计模式角度理解: 是一个基于观察者模式设计的分布式服务管理框架; 负责存储和管理大家都关心的数据, 一旦这些数据的状态发生变化, Zookeeper就将负责通知已经在Zookeeper上注册的那些观察值做出相应的反应. Zookeeper特点 Zookeeper有: 一…

EdgeOne 边缘函数 + Hono.js + Fauna 搭建个人博客

一、背景 虽然 “博客” 已经是很多很多年前流行的东西了&#xff0c;但是时至今日&#xff0c;仍然有一部分人在维护自己的博客站点&#xff0c;输出不少高质量的文章。 我使用过几种博客托管平台或静态博客生成框架&#xff0c;前段时间使用Hono.jsFauna &#xff0c;基于 …

RK3568平台开发系列讲解(I2C篇)利用逻辑分析仪进行I2C总线的全面分析

🚀返回专栏总目录 文章目录 1. 基础协议1.1. 协议简介1.2. 物理信号1.3. 总线连接沉淀、分享、成长,让自己和他人都能有所收获!😄 1. 基础协议 1.1. 协议简介 IIC-BUS(Inter-IntegratedCircuit Bus)最早是由PHilip半导体(现在被NXP收购)于1982年开发。 主要是用来方…