沐游虞笔记
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 必看导言

    • 就业的核心问题

      • 课件
    • 表现力的训练

      • 课件
  • 简历制作

    • 课件
    • 简历准备课堂笔记
    • 个人信息课堂笔记
    • 求职意向课堂笔记
    • 技术栈课堂笔记
    • 教育经历课堂笔记
    • 个人优势与评价课堂笔记
    • 工作经历课堂笔记
    • 项目
    • 项目亮难点问题

    • 项目经历

  • 项目准备

    • 课件
    • 课件
  • 技术重点

    • 划重点

    • 非技术环节
  • 简历投递和面试准备

    • 简历投递
    • 面试准备
  • 笔面试环节知识讲解
  • 项目准备
  • 难点攻关
  • Webpack构建优化
  • 课件资料
luzhichang
2024-09-18
目录

02-面试讲解

# Webpack构建优化面试讲解

# 技术点图谱

涉及的技术点如下:

  1. swc
  2. thread-loader
  3. webpack5 持久化缓存技术
  4. hash
  5. terser-webpack-plugin
image-20240618105400935

# 难点描述

模拟问题:我看到你写了一个项目亮点,是优化 webpack 构建时间,这边关于 webpack 的打包流程,你有了解过么?

问题分析

这是一个偏向八股文的问题:

  1. 打包流程不要回答错
  2. 不断的往自己的项目上面去靠拢

参考答案

你好,老师,这边因为我要做 webpack 的构建优化,所以针对 webpack 的打包流程我是有所了解的。webpack 的打包流程大致可以分为以下几个步骤:

  1. 初始化:webpack 通过配置文件和 Shell 参数,初始化参数,确定入口文件、输出路径、加载器、插件等信息。接下来读取配置文件,并合并默认配置、CLI 参数等,生成最终的配置对象。
  2. 编译:从入口文件开始,递归解析模块依赖,找到所有需要打包的模块。之后使用 loader 对每个模块进行转换,转换成浏览器能够识别的 JS 代码。
  3. 构建模块依赖图:webpack 会为每个模块创建一个模块对象,并根据模块的依赖关系,生成一个模块依赖图(Dependency Graph)。
  4. 生成代码块(chunk):根据入口和依赖图,将所有模块分组,生成一个个包含多个模块的代码块(chunk),这些 chunk 会根据配置生成不同的输出文件。
  5. 输出:将生成的代码块输出到指定的文件夹,并根据配置生成对应的静态资源文件。
  6. 插件处理:在整个构建过程中,webpack 会在特定的生命周期钩子上执行插件,插件可以对打包的各个阶段进行干预和处理。

正是因为了解 webpack 整体的打包流程,所以我发现了很多可以优化的地方,然后进一步着力于构建的优化,大幅度缩减了构建所花费的时间。(钩子🪝)

模拟问题:我看到你写的构建时间从 8min 缩减至 10s 内,那么你能具体说一下你是如何做的么?还有你这里所写的所缩减的时间,是具体测量了的么?通过什么方式去测量的?

问题分析

  1. 简单介绍一下做这个事情的背景
  2. 通过什么工具去量化时间
  3. 你思考的方案以及最终落地的方案
  4. 落地方案的一个整体效果

参考答案

好的,那我把具体如何进行优化的,展开来讲一下。

我先说一下当时为什么需要做这个事儿吧。我们项目一开始就是基于 webpack 搭建的,随着后面项目越来越大,模块越来越多,构建的时间也越来越夸张。最开始还能够忍受,早上到公司先把项目跑起来,等它构建,然后开始小组会议,小组会议结束后回去差不多项目也跑起来了。但是后面随着模块越来越多,会都开完了回去项目都还在构建,于是我们小组讨论,这个问题必须得解决了,因为整个团队里面,就我对工程化有一些研究,所以指派我来完成这项任务。(简单阐述做这个事情的背景)

我当时首先想到了 Vite,因为 Vite 可以直接跳过打包的步骤,但是因为我们这个项目基于 webpack,体量很大,里面用到了很多 webpack 生态的插件和 loader,冒然迁移到 Vite 可能会带来一些未知的风险,例如在 Vite 生态中找不到对标的插件,那么我们就需要在 Vite 中通过自定义插件来实现那个插件的功能,这个工作量是不可预估的。(强调你是如何思考的)

所以,既然无法切换构建工具,那意味着无法跳过打包这个过程,因此我需要知道是哪些地方消耗了那么多时间。在 webpack 中有一个插件 speed-measure-webpack-plugin,我就是通过这个插件去查看的构建时间,它会出一份报告,包含总体构建时间、各阶段的耗时、插件耗时、loader 耗时,这样我就能非常清楚究竟是哪些地方耗时。

通过插件的分析结果来看,我发现 Babel 在编译 JS 时特别耗时,还有就是一些 loader,比如处理 CSS 的 css-loader,在解析和处理过程中也挺耗时的。因此我考虑的主要优化方案有:

  1. 用 swc 替换 babel 进行编译工作
  2. thread-loader 解决 loader 解析耗时问题

(你思考出来的方案是什么)

另外还配合了一些额外的优化手段。(钩子🪝)最终落地的方案效果非常好,再次用 speed-measure-webpack-plugin 插件进行构建时间分析,基本上构建时间在 10 多秒左右。(落地方案的一个整体效果)

就看老师您是否需要我把这些优化手段展开来说一下不?(钩子🪝)

# 技术点叙述

# 1. swc

模拟问题:你说你用到了 swc,那么就先讲一讲这个吧,什么是 swc,它的优势有什么?你为什么用它来替换 babel ?

问题分析

  1. 简单介绍什么是 swc
  2. 结合你的项目说一下优化前后的区别
  3. 放下一个钩子

参考答案

swc 是一个用 rust 写的 JS/TS 编译器,因为基于 rust,所以编译速度非常快,而且 swc 能够兼容大多数 babel 插件和配置,因此迁移起来没有太高的成本。(做一个简单的介绍)

做开始做优化之前,我们项目的构建时间差不多要花费 8~10分钟左右,替换为 swc 编译后,构建时间减少到了约 3 分钟左右。(优化前后的区别)

所以整个优化方案中 swc 是最重要,占大头的。而 loader 解析耗时的问题,我是通过 thread-loader 来解决的,thread-loader 不知道面试老师您之前了解过么?(钩子🪝)

# 2. thread-loader

模拟问题:你这边说一下呢?它是如何解决 loader 解析耗时问题的?

问题分析

  1. 介绍一下 thread-loader
  2. 结合你的项目,用了后的效果
  3. 抛出下一个钩子

参考答案

thread-loader 可以通过多线程并行处理 loader 操作,这样就减少了主线程的负载。(简单介绍)

当我们用了 thread-loader 以后,处理图片、CSS 相关 loader 的耗时问题也就解决了,构建时间进一步缩减到了 2 分钟。(使用后效果)

所以 swc 和 thread-loader 是整个优化方案中最核心的手段,剩下一些其他的优化手段,倒不是说没用,但主要是起到一个锦上添花的作用,一步一步将 2 分钟的构建时间继续优化到 10s 以内。就看老师您这边需要我介绍额外的那些优化手段不?

# 3. 持久化缓存和 hash

模拟问题:可以,你就挨着挨着讲吧?讲一下你剩下的那些优化手段,是如何将目前的 2 分钟优化到最后 10s 以内的?

问题分析

介绍剩余的优化手段即可。这里先说两个,看一下面试官的反馈。

参考答案

当时我们的项目,使用的 webpack 版本是 webpack5,所以我想到了可以利用 webpack5 的持久化缓存技术,来进一步压缩构建的时间。webpack5 新提供的持久化缓存技术,能够把模块的编译结果、解析结果以及插件的执行结果缓存到内存或者文件里面,这样后续进行构建的时候就可以重用这些缓存数据,减少不必要的重复计算和编译。

当然,第一次启动项目的时候,时间上面没有太大变化,因为缓存还没有生成,但是之后缓存非常有用,特别开发环境下需要频繁构建,如果每次都是构建所有的文件会非常耗时,而缓存的存在能进一步缩短构建时间,从 2 分钟缩短到了 1 分钟。

加上了缓存后,当时感觉这套优化方案已经是极限了,并且整个小组的成员也非常满意,毕竟之前构建需要等待 8 分钟,现在只需要 1 分钟左右,大家感觉这已经很好了。(该话术主要是增加一个真实性)

但是我这个人,做事情喜欢尽自己的能力,尽量做到最好,所以我就在想还有没有能进一步优化的手段,那段时间在网上搜索相关的资料,看了很多技术文章,后来发现在开发环境下通过去掉打包 hash 能进一步压缩开发环境下的构建时间。(突出个人做事儿的风格或者说态度)

因为在开发环境中,不太需要 hash,hash 实际上是生产环境下利用浏览器缓存机制优化用户体验的一种手段。开发环境下会频繁的进行代码修改和构建,而生成 hash 会涉及到额外的计算和文件处理,增加不必要的构建时间。

去除 hash 后,开发环境下的构建时间进一步优化到 40 秒。

说实话,一开始我对 hash 并不是太在意的,但是去掉 hash 后,真的还进一步压缩了开发环境下的构建时间,我发现很多东西无法一概而论,不同类型、规模的项目,在 A 项目中毫无问题的一些东西,在 B 项目中可能就会存在一些问题或者隐患。这也是我通过这个项目所积累的一个宝贵经验。(该话术介绍你在该项目中沉淀下来的一些东西,凸显一个真实性)

最后一个优化手段就是升级一些老旧的插件,因为一些插件新版本相较于旧版本,会修复一些 bug,在性能、算法上面可能也会有一些提升。

# 4. 浏览器缓存机制

模拟问题:我看你刚才提到了浏览器缓存,你来具体说一下呢?浏览器缓存有哪些类型?不同的类型是在什么时候命中的?

问题分析

  1. 描述什么是浏览器缓存
  2. 什么是强缓存,什么是弱缓存,各自的命中机制
  3. 再次抛出插件的钩子

参考答案

浏览器缓存是浏览器内部的一种机制,用于缓存 HTML、CSS、JS 以及图片等资源,这样可以减少服务器负担,加快页面加载速度。浏览器缓存主要分为两种类型:强缓存和弱缓存。

  • 强缓存:是指浏览器在一定时间内直接从缓存中读取资源,而不发起请求到服务器。即使用户刷新页面,浏览器也不会向服务器请求资源。强缓存主要通过 HTTP 响应头中的 Expires 和 Cache-Control 字段来控制。
  • 弱缓存:弱缓存则是在强缓存没有命中时,会去检查弱缓存。弱缓存也被称之为协商缓存,浏览器在请求资源时,会先发送一个请求到服务器,询问资源是否有更新。如果资源没有更新,服务器会返回 304 状态码,告诉浏览器继续使用缓存,这就是命中了弱缓存。如果资源有更新,服务器则返回新的资源内容。弱缓存主要通过 HTTP 响应头中的 Last-Modified 和 ETag 字段来控制。

一般对于不经常变化的静态资源,如网站的图片、样式表、JS 库等,通常会使用强缓存,并设置较长的缓存时间。对于经常变化的动态资源,如 API 响应、用户数据等通常使用弱缓存。(介绍什么是浏览器缓存)

所以生产环境下为了充分利用浏览器缓存机制,一般会生成 hash 值,这样可以确保文件名唯一,当文件内容发生变化时,文件名也会变化,从而强制浏览器加载新的资源。但是开发环境下不需要,开发环境下代码频繁更改,生成 hash 反而浪费时间,特别我们的项目规模又比较大,去掉 hash 后构建时间居然有 20s 左右的优化,从 1min 降到了 40s 左右。

最后升级了一下插件,达到了最终的 10s 以内的效果。(钩子🪝)

# 5. terser-webpack-plugin

模拟问题:那你说一下你升级了什么插件?

问题分析

  1. 简单回答升级了什么插件
  2. 对整套落地方案进行一个总结

参考答案

当时升级了一个 terser-webpack-plugin 的插件,这个插件是做压缩的。因为打包的时候有一个重要的任务就是要压缩,而压缩所花费的时间也挺长的,我就琢磨着能不能减少一下压缩所花费的时间。

一开始想着了解一下这个插件是如何压缩的,压缩算法是什么。结果刚好看到了这个插件的 CHANGELOG 文档,发现从 5.2.0 版本开始引入了 swc 压缩器,我就估摸着性能上面能有大幅的提升,于是我就对这个插件进行了版本升级,不出所料,压缩的时间再一次得到了优化,到了目前的 10s 左右。

现在回想起这一整套构建优化的落地方案,从最初的 8min 降到 10s 以内,我还是挺有心得体会的。一开始只想着如何加快构建速度,但性能优化往往是各种方面的,降低构建时间是一个方面,合理的利用缓存也是一种有效的手段,使用多线程来规避耗时任务阻塞主线程,也是一种方案。(阐述自己的心得体会,也是对整个方案做一个总结)

总之这就是我针对 webpack 构建优化沉淀下来的一套落地方案,不知道老师您那边还有什么更好的提议不?

(结束🎉)


-EOF-

Theme by Vdoing | Copyright © 2021-2024 蜀ICP备2024068710号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式