原文链接:www.developerway.com/posts/initi…
探索核心网络指标、性能开发工具、初始加载性能的定义、衡量该性能的指标,以及缓存控制和不同网络条件对其的影响。
如今,随着人工智能驱动的代码生成技术蓬勃发展,编写React代码的重要性正在逐渐降低。现在任何人都能用React编写应用程序。但编写代码始终只是整个拼图中的一小块。我们仍需将应用部署到某个平台,向用户展示,确保其稳定性与运行速度,并处理无数其他事务。这些工作目前尚无法被人工智能取代——至少现在还不能。
因此,让我们聚焦于提升应用的运行速度。要实现这一目标,我们需要暂时跳出React的框架。因为在追求速度之前,我们首先需要明确"速度"的定义、衡量标准以及影响速度的关键因素。
剧透预警:本文除研究项目外不会涉及React。今天我们将聚焦基础内容:如何使用性能工具、核心网络指标入门、Chrome性能面板解析、初始加载性能的定义、相关指标的衡量方式,以及缓存控制与不同网络环境对其的影响。
介绍初始加载性能指标
当我打开浏览器并尝试访问最喜欢的网站时会发生什么?我在地址栏输入"www.my-website.com" ,浏览器向服务器发送一个GET请求,并收到一个HTML页面作为响应。
完成此过程所需的时间称为"首次字节到达时间"(TTFB):即从发送请求到结果开始到达之间的时间间隔。收到HTML后,浏览器必须尽快将该HTML转换为可用的网站。
它首先在屏幕上渲染所谓的"关键路径":即能够向用户展示的最小且最重要的内容。
究竟哪些内容应纳入关键路径是个复杂问题。理想状态下应包含所有内容,以便用户立即获得完整体验;但另一方面又不能包含任何内容,因为作为"关键"路径必须追求极致速度。二者无法兼得,因此需要折中方案。
折衷方案如下:浏览器构建"关键路径"时,至少需要以下资源类型:
- 从服务器接收的初始HTML——用于构建实际DOM元素,以此呈现用户体验。
- 关键CSS文件(用于初始元素样式化)——否则若不等待这些文件加载就继续渲染,用户将在页面初始阶段看到未样式化的内容闪烁。
- 关键JavaScript文件(用于同步修改布局)。
浏览器在初始请求中首先获取HTML文件。它开始解析HTML,同时提取完成"关键路径"所需的CSS和JS文件链接。随后向服务器发送请求获取这些资源,等待下载完成后进行处理,将所有内容整合,最终在某个时刻将"关键路径"的像素绘制到屏幕上。
由于浏览器无法在缺少这些关键资源的情况下完成初始渲染,它们被称为"阻塞渲染资源"。当然并非所有CSS和JS资源都具有阻塞性,通常仅包括:
- 大部分CSS资源(无论内联还是通过
<link>标签引入) - 位于
<head>标签内且未采用async或deferred的JavaScript资源
渲染"关键路径"的整体流程大致如下:
- 浏览器开始解析初始HTML
- 在此过程中,它从
<head>标签中提取CSS和JS资源的链接。 - 随后启动下载流程,并等待阻塞资源完成下载。
- 等待期间,若条件允许则继续处理HTML。
- 所有关键资源接收完毕后,浏览器同步处理这些资源。
- 最终完成所有必要操作,渲染出界面的实际像素内容。
这个时间点被称为首次绘制(First Paint, FP)。这是用户首次有机会在屏幕上看到内容的时刻。该事件能否发生取决于服务器发送的HTML内容。若其中包含有意义的内容(如文本或图像),则该时刻同时也是首次内容绘制(First Contentful Paint, FCP)发生的时刻。若HTML仅为空div标签,则FCP将延迟发生。
首次内容绘制(FCP)是最重要的性能指标之一,因为它衡量的是用户感知到的初始加载速度。简而言之,这是用户对网站速度的第一印象。
在此之前,用户只能盯着空白屏幕焦急等待。谷歌指出,理想的FCP值应低于1.8秒。超过这个时限,用户便会逐渐失去对网站内容的兴趣,甚至开始离开。
然而FCP并非完美指标。若网站以旋转图标或加载界面启动,该指标将如实呈现。但用户访问网站绝非为欣赏炫酷加载界面,他们真正追求的是内容访问体验。
为此,浏览器需要完成已启动的工作。它等待剩余的非阻塞 JavaScript 执行完毕,将其应用于屏幕上的 DOM 结构,下载图片,并进一步优化用户体验。
在这一过程中某个节点会产生最大内容绘制(LCP)时间。与首次可视内容(FCP)关注首个元素不同,LCP衡量的是页面主体内容区域——即视口中可见的最大文本、图片或视频。谷歌指出该指标理想值应低于2.5秒,超过此限用户将认为网站加载缓慢。
所有这些指标都属于谷歌的网页核心指标体系——该体系通过一组指标来衡量用户在页面上的体验。LCP是三大核心网页指标之一,这三项指标分别代表用户体验的不同维度。其中LCP负责评估加载性能。
这些指标可通过Lighthouse进行测量。Lighthouse是谷歌的性能分析工具,既集成于Chrome开发者工具,也可通过shell脚本、网页界面或Node模块运行。您可将其作为Node模块在构建流程中运行,在代码进入生产环境前检测性能退化问题;使用集成版开发者工具进行本地调试和测试;通过网页版本查看竞争对手的性能表现。
性能开发工具概述
以上内容是对该过程的极简化说明。但其中充斥着大量缩写和理论知识,足以令人眼花缭乱。对我个人而言,阅读这类内容毫无用处——除非能亲眼见证实际效果并亲手操作,否则转眼就会忘得一干二净。
针对这个特定主题,我发现最易于理解概念的方式,就是在半真实页面上模拟不同场景,观察它们如何改变结果。因此在深入理论之前(而理论内容还远不止这些!),让我们直接动手实践。
项目设置
若您愿意,可在自己的项目中完成以下所有模拟——结果应大致相同。但若需更受控且简化的环境,建议使用我为本文准备的示例项目。访问地址如下:github.com/developerwa…
首先安装所有依赖项:
npm install
构建项目:
npm run build
启动服务:
npm run start
您应该能在 "http://localhost:3000" 看到一个漂亮的仪表板页面。
探索必备开发工具
在Chrome中打开待分析的网站,并启动Chrome开发者工具。找到其中的"性能"和"Lighthouse"面板,将它们并排放置以便同时使用。这两项工具都将派上用场。
此外,在执行本文后续操作前,请确保已勾选"禁用缓存"复选框。该选项位于网络面板最顶端区域。
这样做是为了模拟首次访问者——那些从未访问过我们网站、浏览器尚未缓存任何资源的人。
探索Lighthouse面板
现在打开灯塔面板。您应该会看到几个设置选项和"分析页面加载"按钮。
"导航"模式正是本节关注的重点——它将对页面初始加载过程进行详细分析。报告将提供如下评分:
本地性能完美,这不足为奇——毕竟在我的机器上一切总是"运行正常"。
还将包含以下指标:
本文所需的FCP和LCP值就在最上方。
下方列出了若干建议,可助您提升评分。
每条建议都可展开查看,其中包含更详细的信息,有时还会提供解释该主题的链接。虽然并非所有建议都能立即实施,但这确实是提升性能的绝佳入门工具,能帮助你深入了解各种优化方案。光是阅读这些报告和相关链接就足以让人沉浸数小时。
然而Lighthouse仅提供表面层面的信息,无法模拟网络延迟或CPU负载等复杂场景。它虽是绝佳的入门工具,能出色追踪性能随时间的变化趋势,但若要深入探究具体问题根源,我们需要借助"性能"面板。
探索性能面板
初次加载时,性能面板应呈现如下所示的界面:
它展示了三个核心网络指标,其中之一是我们的LCP指标,可模拟网络和CPU延迟,并能记录随时间变化的性能细节。
在面板顶部找到并勾选"截图"复选框,点击"记录并重新加载"按钮,待网站自动刷新后停止录制。这将生成页面初始加载过程的详细报告。
该报告包含多个部分:
最顶端为概览性的"时间线概览"区域。
您将在此处看到网站正在发生某些变化,但信息有限。当您将鼠标悬停其上时,系统会显示该变化的截图,您可选取特定范围进行放大查看。
下方设有"网络"板块。展开后,您将看到所有正在下载的外部资源及其在时间轴上的精确时间点。悬停于特定资源上时,可查看各下载阶段所耗费的详细时间信息。带红色边角标记的资源即为阻塞资源。
如果你正在研究这个项目,你会看到完全相同的画面,而这幅画面与我们上一节的内容完全吻合:
- 起初,有一个蓝色方块——这是获取网站HTML的请求
- 加载完成后,经过短暂停顿(用于解析HTML),又发出两个请求以获取更多资源。
- 其中黄色请求是加载JavaScript,属于非阻塞请求。
- 紫色请求则是加载CSS,属于阻塞请求。
若您现在打开学习项目的代码并查看dist文件夹,源代码与该行为相符:
assets文件夹内将包含index.html文件以及.css和.js文件index.html文件的<head>部分会存在指向CSS文件的<link>标签。众所周知,<head>中的CSS资源会阻塞渲染,因此这符合预期。- 此外,
<head>内还有指向assets文件夹中JavaScript文件的<script>标签。该标签既非deferred也非async,但带有type="module"属性。此类标签会自动延迟加载,因此同样符合预期——面板中的JavaScript文件属于非阻塞加载。
额外练习
如果你正在处理某个项目,请记录其初始加载性能并查看网络面板。你可能会发现下载的资源数量远超预期。
- 你有多少个阻塞渲染的资源?它们是否都必不可少?
- 你是否清楚项目的"入口"点,以及阻塞资源如何出现在
<head />部分?尝试使用自定义的npm build命令构建项目并搜索这些资源。提示:
- 纯 webpack 项目:查找
webpack.config.js文件,HTML 入口路径应位于其中- Vite 项目:查看
dist文件夹(与学习项目相同)- Next.js App 路由项目:查看
.next/server/app文件夹
在“网络”部分下,您可以找到“帧”和“时序”两个子部分。
这些指标非常酷。在"时序"部分,你可以看到我们之前讨论过的所有指标(首次呈现、首次内容呈现、最大内容呈现),还有几个尚未提及的新指标。将鼠标悬停在指标上时,会显示其精确耗时。点击指标会更新最下方的"摘要"标签页,其中包含该指标的说明及深入了解的链接。如今开发者工具的核心功能就是教育用户。
最后是"主线程"部分。这里展示了在记录时间线期间主线程的运行状况。
我们可以在这里看到诸如"解析HTML"或"布局"等项目及其耗时情况。黄色部分与JavaScript相关,由于我们使用的是压缩了JavaScript的生产环境构建版本,这些数据价值有限。但即便如此,它仍能让我们大致了解JavaScript执行耗时相对于HTML解析和布局渲染等环节的时间占比。
当"网络"和"主线程"两个面板同时展开并放大至全屏时,这种分析方式对性能优化尤为有效。
由此可见,我的服务器速度极快,且资源包小巧高效。所有网络任务均未形成瓶颈,耗时微乎其微,浏览器在任务间隙完全处于闲置状态。因此若要提升初始加载速度,关键在于排查HTML解析为何如此缓慢——图表中耗时最长的正是该任务。
或者从绝对数值来看——从性能角度而言我无需在此做任何优化。整个初始加载耗时不足200毫秒,远低于谷歌推荐的阈值🙂 但这仅因测试在本地环境进行(无实际网络开销),且使用了高性能笔记本和基础服务器。
是时候模拟真实场景了。
探索不同网络状况
服务器极度缓慢
首先,让我们让服务器更贴近现实。目前,最开始的"蓝色"步骤耗时约50毫秒,其中40毫秒纯属等待。
在实际运行中,服务器会执行各种操作:检查权限、生成内容、再检查两次权限(因为存在大量遗留代码导致三重检查机制缺失),其余时间则处于繁忙状态。
在你的学习项目中导航至 backend/index.ts 文件(github.com/developerwa… // await sleep(500) 行,取消注释。这将使服务器在返回 HTML 前延迟 500 毫秒——对于老旧复杂的服务器而言,这个延迟似乎相当合理。
重新构建项目npm run build,重启服务npm run start,并再次运行性能记录。
时间轴上除初始蓝线外未见变化——但此刻它已变得异常冗长,与其余数据形成鲜明对比。
这种情况凸显了在进行任何性能优化前,全面审视整体状况并找出瓶颈的重要性。LCP值约为650毫秒,其中约560毫秒耗费在等待初始HTML上,React部分仅占50毫秒左右。即便我设法将其减半至25毫秒,在整体占比中也仅占4%。而要实现减半需要付出巨大努力。更有效的策略或许是聚焦服务器端,找出其运行缓慢的根本原因。
模拟不同带宽和延迟
并非所有人都生活在千兆网络的世界里。以澳大利亚为例,50兆每秒已是高速网络的范畴,每月费用约90澳元。当然这并非3G网络——全球仍有大量用户困于此境。但每当听到欧洲人炫耀1千兆网速或10欧元套餐时,我仍忍不住心酸。
言归正传。让我们模拟这种不太理想的澳大利亚网络环境,观察性能指标的变化。为此请清除性能选项卡中的现有记录(位于刷新和记录按钮附近)。此时应显示网络设置面板:
如果您的Chrome版本中未显示该选项,可在"网络"标签页中找到相同设置。
在"网络"下拉菜单中添加新配置文件,填写以下数值:
- 配置文件名称:"平均网络带宽"
- 下载速度:50000(50 Mbps)
- 上传速度:15000(15 Mbps)
- 延迟:40(普通网络连接的平均值)
现在在下拉菜单中选择该配置文件,重新运行性能记录。
你看到什么?我的结果如下所示:
LCP值几乎未变——仅从640毫秒微升至700毫秒。初始蓝色"服务器"部分毫无变化,这很合理:它仅发送最基础的HTML,下载耗时本就不长。
但可下载资源与主线程之间的关联发生了剧变。
现在我能清楚地看到阻塞渲染的CSS文件的影响。解析HTML的任务已经完成,但浏览器仍在等待CSS文件——在它下载完成前,任何内容都无法渲染。对比之前的画面:当时浏览器解析HTML的同时,资源几乎瞬间就下载完毕了。
技术上讲,浏览器本可在此后渲染内容——但实际并无内容可渲染,因为HTML文件中仅发送了空div标签。因此浏览器继续等待,直至JavaScript文件下载完毕并可执行。
这段约60毫秒的等待间隔,正是我观察到的LCP指标增长值。
为观察影响,进一步降低网络速度。创建新网络配置文件:下载/上传速率设为10Mbps/1Mbps,保持40毫秒延迟,命名为"低带宽网络"。
然后重新运行测试。
LCP值现已升至近500毫秒。JavaScript下载耗时近300毫秒。相对而言,解析HTML任务和执行JavaScript任务的重要性正在降低。
附加练习
如果你有自己的项目,请尝试在项目中运行此测试。
- 下载所有关键路径资源需要多长时间?
- 下载所有 JavaScript 文件需要多长时间?
- 这会导致解析 HTML 任务之后出现多长时间的间隔?
- 主线程中解析 HTML 和 JavaScript 的执行任务相对于资源下载而言占用了多少时间?
- 这对 LCP 指标有何影响?
资源栏内部的运作也颇为有趣。将鼠标悬停在黄色JavaScript栏上,你应该会看到类似以下内容:
这里最有趣的部分是"请求发送并等待",耗时约40毫秒。将鼠标悬停在其他网络资源上——它们都会显示这个数值。这就是我们设定的40毫秒延迟,即网络延迟。许多因素都会影响延迟数值,网络连接类型便是其中之一。例如,普通3G连接的带宽约为10/1 Mbps,延迟在100至300毫秒之间。
要模拟此场景,请创建名为"普通3G"的新网络配置文件,从"低带宽网络"配置中复制下载/上传数值,并将延迟设为300毫秒。
重新运行性能分析。此时所有网络资源的"请求发送并等待"时间应增加至约300毫秒。这将使LCP数值进一步延长:我测试中达到1.2秒。 现在来点有趣的:如果我把带宽恢复到超高速,但保持低延迟会怎样?试试这个设置:
- 下载:1000 Mbps
- 上传:100 Mbps
- 延迟:300 毫秒
如果你的服务器位于挪威某处,而客户是富裕的澳大利亚人,这种情况就很容易发生。
结果如下:
LCP数值约为960毫秒。这比我们之前测试过的最慢网速还要糟糕!在此情境下,资源包大小影响甚微,CSS体积则完全无关紧要。即便将两者都减半,LCP指标也几乎不会变化。高延迟才是压倒一切的关键因素。
这让我想到一个所有人都应优先实施的性能优化措施(若尚未采用):确保静态资源始终通过CDN分发。
CDN的重要性
在任何前端性能优化中,CDN都是基础中的基础,甚至比代码拆分或服务器组件这类更高级的技术更早需要考虑。
内容分发网络(CDN)的核心目标在于降低延迟,尽可能快速地将内容交付给终端用户。为此它们采用了多种策略,本文重点探讨其中最重要的两项:"分布式服务器"与"缓存机制"。
CDN服务商会在不同地理区域部署多台服务器。这些服务器可存储静态资源副本,并在浏览器请求时直接发送给用户。CDN本质上是围绕源服务器的软性保护层,既能隔绝外部干扰,又能最大限度减少源服务器与外部世界的交互。它就像为内向者配备的人工智能助手,能处理常规对话而无需真人参与。
以上述挪威服务器与澳大利亚客户端的场景为例,其架构示意图如下:
引入CDN后,情况将发生变化。CDN会在用户附近部署服务器,例如同样位于澳大利亚某处。CDN会定期从源服务器获取静态资源的副本。此后,澳大利亚及周边地区的用户将直接获取这些副本,而非从挪威的服务器获取原始资源。
这实现了两个重要目标:首先,由于用户不再直接访问源服务器,其负载得到显著减轻;其次,用户获取资源的速度大幅提升——他们无需再跨越海洋下载几个JavaScript文件。
而在我们上述的模拟中,LCP值从960毫秒降回640毫秒🎉。
重复访问性能
迄今为止,我们只讨论了首次访问性能——即从未访问过您网站的用户体验。但理想情况下,网站体验应足够出色,使多数初访者转化为常客。至少他们不会在首次加载后立即离开,而是浏览多个页面甚至完成购买。此时浏览器通常会缓存CSS和JS等静态资源——即本地保存副本而非每次重新下载。
让我们观察这种场景下性能图表和数据的变化。
重新打开研究项目。在开发工具中,将网络设置切换为先前创建的"平均3G环境"——该环境具有高延迟和低带宽特性,以便我们能立即看到差异。同时确保"禁用网络缓存"复选框处于未勾选状态。
首先,刷新浏览器以确保排除首次访问者的情况。然后刷新并测量性能。
若使用研究项目,最终结果可能会略显意外,因为它将呈现如下状态:
CSS和JavaScript文件在网络选项卡中依然非常突出,我看到它们在"请求发送并等待"状态下都耗时约300毫秒——这正是我们在"平均3G"配置文件中设定的延迟值。因此LCP指标未能达到最佳水平,当浏览器仅等待阻塞性CSS时,就出现了300毫秒的延迟。
问题出在哪里?浏览器不应该缓存这些资源吗?
通过Cache-Control头部控制浏览器缓存
现在我们需要使用网络面板来了解具体情况。打开它并找到其中的CSS文件,其内容应类似如下所示:
这里最值得注意的是"状态"列和"大小"。在"大小"栏中显示的绝对不是整个CSS文件的大小——数值太小了。而在"状态"栏里,我们看到的不是常规的200"一切正常"状态码,而是不同的304状态码。
由此产生两个疑问:为何返回304而非200?为何会发送请求?缓存机制为何失效?
首先解释304响应。这是配置完善的服务器针对条件请求返回的响应——响应内容会根据特定规则变化。此类请求常用于控制浏览器缓存。
例如,当服务器收到CSS文件请求时,可检查文件最后修改时间。若该时间与浏览器缓存文件一致,则返回空正文的304响应(故大小仅223字节)。这告知浏览器可安全复用现有文件。无需浪费带宽重新下载文件。
这就是为什么我们在性能图中看到庞大的"请求发送并等待"数字——浏览器正询问服务器确认CSS文件是否仍为最新版本。而"内容下载"耗时0.33毫秒的原因也在于此——服务器返回了"304未修改"状态码,浏览器直接复用了先前下载的文件。
附加练习
- 在学习项目中,进入 dist/assets 文件夹并重命名 CSS 文件。
- 打开 dist/index.html 文件,更新重命名后 CSS 文件的路径。
- 刷新已打开的页面(保持网络选项卡开启状态),此时应能看到 CSS 文件以新名称显示,状态码为 200,且大小正确——这表明文件已被重新下载。此操作称为"清除缓存"——强制浏览器重新下载可能已缓存的资源。
- 再次刷新页面——状态码将恢复为304,并重新使用缓存文件。
现在,让我们来探讨第二个问题——为何会发送此请求?
这种行为由服务器在响应中设置的Cache-Control头部控制。点击网络面板中的CSS文件,即可查看请求/响应的详细信息。在"响应头部"块的"头部"选项卡中,找到"Cache-Control"的值:
此标头内可包含多种指令的不同组合,指令间以逗号分隔。本例中有两项指令:
- max-age 带数字值 - 控制该响应被存储的时间长度(以秒为单位)
- must-revalidate - 指示浏览器在响应过期时始终向服务器发送请求以获取最新版本。当响应在缓存中的存活时间超过 max-age 值时,该响应即视为过期。
因此该标头向浏览器传达的核心信息是:
- "允许将此响应存储在缓存中,但请定期与我重新验证以确保有效性。"
- 顺便提一句,缓存的有效期恰好为零秒。祝你好运。
最终结果是浏览器始终会向服务器验证,绝不会直接使用缓存内容。
不过我们很容易就能改变这个设置——只需将max-age的数值改为0到31536000之间(即一年,允许的最大秒数)。具体操作如下:在你的学习项目中,打开backend/index.ts文件,找到设置max-age=0的位置,将其改为31536000(一年)。刷新页面几次后,您应能在"网络"选项卡中看到CSS文件的更新状态:
请注意状态列现在已变灰,而大小栏显示为"(内存缓存)"。该CSS文件现由浏览器缓存提供,且此状态将持续至今年年底。刷新页面数次即可验证其稳定性。
现在进入缓存头设置的核心环节:让我们重新测量页面性能。请务必设置"平均3G"配置文件选项,并保持"禁用缓存"设置未勾选。
结果应类似如下:
尽管存在高延迟,"请求发送并等待"部分已降至近乎为零,"解析HTML"与JavaScript评估之间的间隔几乎消失,LCP值也恢复到约650毫秒。
附加练习
- 现在将max-age值改为10(10秒)。
- 勾选"禁用缓存"复选框刷新页面以清除缓存。
- 取消勾选复选框后再次刷新页面——此时应从内存缓存中获取资源。
- 等待10秒后再次刷新页面。由于max-age仅为10秒,浏览器将重新验证资源,服务器将再次返回304状态码。
- 立即刷新页面——此时应再次从内存中获取资源。
缓存控制与现代打包工具
上述信息是否意味着缓存是提升性能的万能解药,我们应当尽可能激进地缓存所有内容?绝非如此!抛开其他因素不谈,当"不懂技术的客户"与"需要电话指导清除浏览器缓存"这两种情况同时出现时,即便是最资深的开发者也会陷入恐慌。
优化缓存的方法千千万,Cache-Control 标头指令与其他标头的组合方式更是数不胜数——这些组合可能影响缓存时长,也可能不影响,更取决于服务器的具体实现。仅此主题就足以写成几本书的篇幅。若想成为缓存大师,请从web.dev/和MDN资源 中的文章入手,再循着线索深入探索。
遗憾的是,没有人能告诉你"这是适用于所有场景的五大最佳缓存策略"。最理想的答案是:"若你的用例结合了这些要素,那么这种缓存设置组合是不错的选择,但需警惕那些潜在问题"。归根结底,关键在于了解你的资源特性、构建系统、资源变更频率、缓存的安全性,以及操作失误可能引发的后果。
然而,这里存在一个例外。这种例外在某种程度上形成了一种明确的"最佳实践":使用现代工具构建的网站所使用的JavaScript和CSS文件。现代打包工具如Vite、Rollup、Webpack等能够生成"不可变"的JS和CSS文件。当然,它们并非真正意义上的"不可变"。但这些工具会根据文件内容生成包含哈希字符串的文件名。若文件内容变更,哈希值随之改变,文件名亦随之更新。因此当网站部署时,浏览器将无视缓存设置重新获取完全新鲜的文件副本——这正是前文手动重命名CSS文件时实现的缓存"破坏"效果。
以学习项目中的 dist/assets 文件夹为例。其js和CSS文件均采用 index-[hash] 的命名规则。请记住这些文件名,并多次运行 npm run build 命令。由于文件内容未发生变化,这些文件名将保持完全一致。
现在打开src/App.tsx文件,在任意位置添加类似console.log('bla')的代码。再次运行npm run build并检查生成的文件。你会发现CSS文件名保持不变,而JS文件名已更新。当网站部署后,当重复访问的用户下次访问时,浏览器将请求一个从未出现在缓存中的全新JS文件——缓存被清除了。
附加练习 找到项目中与
dist文件夹对应的位置,并运行构建命令。
- 生成的文件名呈现何种形态?是否包含哈希值,还是仅为
index.js、index.css等纯文本文件名?- 当重新运行构建命令时,文件名是否发生变化?
- 若在代码中进行简单修改,会有多少个文件名随之改变?
若您的构建系统采用此配置方式——您很幸运。可安全地将服务器配置为为生成的资源设置最大max-age头值。若您同样为所有图片添加版本号——效果更佳,此时也可将图片纳入配置列表。
根据网站特性及其用户行为,此配置可能为您带来显著的初始加载性能提升,且无需额外成本。
我这种简单用例真的需要了解这些吗?
此时你可能在想:"你疯了吧。我周末用Next.js搭建了个简单网站,两分钟就部署到Vercel/Netlify/最火新平台了。这些现代工具肯定都帮我搞定了这些吧?" 说得有道理。我当初也这么想。但实际检查后,天啊,真是大吃一惊😅
我两个项目的CSS和JS文件竟设置了max-age=0和must-revalidate。原来这是CDN服务商的默认配置🤷🏻♀️。当然,他们这么设置自有道理。所幸覆盖设置很简单,倒也不算大问题。但话说回来。这年头谁都靠不住啊 😅。
你的托管/CDN服务商情况如何?你对他们的缓存头配置有多确定?
希望这次探索充满乐趣,让你学到新知识,甚至解决了项目中的几个问题。我这就去处理剩余的指标了,而你正忙着研究这个项目(希望如此)。很快再见!