Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >我们从Vue到Alpine.js的旅程

我们从Vue到Alpine.js的旅程

作者头像
深度学习与Python
发布于 2023-05-09 09:10:07
发布于 2023-05-09 09:10:07
1.3K0
举报

作者 | Tim Kleyersburg

译者 | 马可薇

策划 | Tina

问   题

在 2019 年底,我们为一位客户重发布了电子商务网站。这次重新发布的变动很大,不仅影响了整体设计和模板,还涉及了前端的架构。唯一没什么改动的就是后端。

        客户的主要需求是:

  • 优化 PageSpeed 指标
  • 提高可用性,从而提高转化率

在数月的实施之后,客户和我们都对最终成果感到满意。我们在 Lighthouse 的全部四个类别中都达到了绿色评级,转化率也有了显著的提升。直到谷歌在 Lighthouse 6.0 更新中更改了性能评分的计算模式,让我们的评分从绿色降级为红色。

顺带一提,Lighthouse 在新标准中将重点转移到了前端内容上,在首字节时间(TTFB)以及如文件大小、CSS 优化、网页字体等会对总体网页性能有影响的内容之外,还囊括了“可交互时间(TTI)”以及“最大内容绘制(LCP)”指标。随着网页可交互性越来越强,其对性能的感知也越发重要。理论上来说,我们是支持谷歌将这些新指标纳入评分标准的,尽管谷歌在展示“优秀范例”时用的是几乎没有任何交互性的博客站点,这完全是在拿苹果和橘子在作比较。

在与客户的一次会议后,我们延后了针对 Lighthouse 新指标的优化工作。在分析了网站访客的常用设备后,我们很难再说服自己将大量时间花费在我们和所有竞争对手都要面临的问题上。

然而,随着在 2020 年底、2021 年初谷歌公布部分新指标将对搜索结果排名有影响后(是时候将页面体验引入谷歌搜索了),显然我们并不能再继续将这个问题推延了。在与客户的又一次商讨后,我们确定了我们所能提供显著竞争优势,并让最终用户感受到速度的提升。

分析过程

我们需要更多的数据。坦白来说,在这之前我们从来没怎么重视过更深层次的性能指标,而现在我们要开始赶进度了。我们通过谷歌 Chrome 浏览器和其内置的 Lighthouse 应用,外加开发者工具中的性能标签,三管齐下分析网站性能。

我们当前的设置

在重发布后,我们将前端架构完全推翻重写,用 Vue 2 作为 JavaScript 框架,TailwindCSS 为 CSS 框架。所有内容都由 Symfony Encore(Webpack)进行打包。

我们的站点没有用 SPA,而是将根实例捆绑到一个 div 元素 #app 上。借助无渲染组件(Vue.js 中的无渲染组件)让我们可以使用服务器端变量或是用 Twig 轻松编写大部分模板,而不需要编写任何 API

代码语言:javascript
AI代码解释
复制
<notepad-star  :product-id="{{ product_id }}"  :initial-star="{{ is_stared(product_id) ? 'true' : 'false' }}">  <div>    <button @click.prevent="toggle">Toggle</button>  </div></notepad-star>

product_id是服务器端变量,is_stared(product_id)是Twig函数,二者都是作为props传入Vue组件的。

问题分析

目前我们的流程大致是这样子的:

  1. 在 chrome 里生成性能报告
  2. 研究报告结果
  3. 改点东西
  4. 重新生成新报告以确定或者推翻我们假设

性能报告中最有用的部分是“评估脚本”,似乎浏览器在评估我们 JavaScript 包的时候要做不少事。

生产环境

我们的第一步是注释掉脚本标签,看看对指标会有什么影响。结果发现,效果相当显著。

注:这份报告是我们在开发环境中生成的,与实际生产环境大约有 10%-15% 的差异。

需要做什么

我们确定了以下几点亟需关注:

  1. 优化关键资源的预加载
  2. 最大限度地缩减阻断时间
  3. 优化交互时间
  4. 最大限度地减少主线程工作

Part 1:优化预加载

为追求简单快速简单的部署,我们没有对谷歌标签管理和我们的 CCM 进行完善的性能测试,这也导致了一些渲染阻塞。我们测试了预加载和预连接的各种不同组合,并最终得出了以下结果:

  • 预加载关键资源,如 CCM 脚本
  • 预连接 GTM
  • 预加载我们自己的关键资源,如网页字体或我们自己的主要 css、js 文件

这些是我们用到的工具:

  • Lighthouse:直观展示哪些资源应该被预加载
  • Firefox:通过开发者工具可以找到被预加载,但在最初几秒内未被使用的字体

Part 2-4:优化其余部分

在优化预加载后,剩下可能对我们关键指标有影响的就只有我们 JavaScript 包中自己的资源了,其余指标也都或多或少跟这些资源挂钩。

找到问题

在开始优化之前,我们需要先从更深层次分析问题。如前文所述,我们对所有的 Vue 组件都应用了无渲染组件,并用 Vue 实例打包了整个网站。这种方式让我们可以很方便地进行全局状态管理,我们还可以通过添加额外的混合器来为网站增加交互性,比如:

代码语言:javascript
AI代码解释
复制
export const searchOverlay = {  data() {    return {      showSearchOverlay: false,    }  },}

全局状态示例 / 混合器提供功能性

Vue 的不同版本

Vue 有两个不同的版本:运行时构建,以及包含模板编译器的版本。运行时构建的文件大小相比来说要小很多,但只能用于单一文件的组件,因为这类组件会被包含在捆绑包中,因此不需要模板编译器。另一方面,模板编译器让我们可以从模板引擎(Twig)中生成模板,并插入到无渲染组件的默认槽中。

另外,由于我们需要将网站整体打包,Vue 需要对所有可见的 DOM 节点进行评估,而光是在主页上就有大约 4500 个节点。这也是为什么我们的脚本评估时间会是如此的长。

既然对根因有了更好的理解,我们可以开始着手评估问题缓解的方法了。

很可惜我们最终并没有找到能显著提升当前架构性能的方法,我们的模板架构和后端结构并不允许我们优雅地切换到运行时构建。

评估需求

下一步,我们开始整理当前网页上所提供的组件和交互功能,以从我们全新的解决方案中获得新的视角。

这些是我们目前已有组件的例子:

  • 实时搜索
  • 动态侧边栏导航
  • 弹出框菜单
  • 模态框

我们还有一些之前由混合器提供的小型函数。这些函数因为没有状态且可以简单直接地在任何地方触发,主要用于不需要单独组件即可实现的功能,如:

  • 动态更新产品类别
  • 打开发货模式
  • 展示或隐藏全局信息轮播图

这些功能都有一个共同点:需要组件间的交流。这些组件都不算复杂,主要用于提供互动性或防止网页重新加载。

    我们希望且需要从新框架中获得的有:

  • 反应性,在数据发生变化后模板会重新渲染
  • 事件系统以方便组件间交流
  • 占用空间小

引入 Alpine.js

我们曾在其他项目中用 Alpine.js 来提供交互性,最终效果也很好。既然我们已经在项目中使用 TailwindCSS 了,Alpine.js 所声称的“类似 JavaScript 中的 TailwindCSS”说法很得我们心。我们并不确定 Alpine.js 是否能胜任如此大型的电子商务站点,因此我们需要建立一个概念验证,以测试它是否最难处理的部分。我们重新构建了如滑动导航、动态购物车以及主菜单等包含前文所提到需求的重要组件,如果我们能重新整合这些组件,那我们可以肯定地认为其他组件都没问题。在经过了大约一天左右的工作,我们收获了满意的成果。虽然重构过程并不是一帆风顺,但既然我们的大部分逻辑都是用 JavaScript 写的,从 Vue 到 Alpine.js 的转换都是很直接的。我们最终确定了以下的架构形式:

代码语言:javascript
AI代码解释
复制
js/├── components/│   ├── cart.js│   ├── mobileMenu.js│   └── ...├── enums/│   ├── events.js│   └── ...├── helper/│   └── customEvent.js├── providers/│   ├── cart.js│   ├── googleTagManager.js│   └── ...└── stores/    ├── cart.js    ├── global.js    └── ...

组件

组件是以窗口范围的函数所定义的,可以返回用于在 Alpines 的 x-data 属性中用于初始化组件的对象。

下面是一个简化的模态组件示例,请注意我们是怎么使用 customEvent 函数和“枚举(enums )”的。

代码语言:javascript
AI代码解释
复制
import customEvent from '@/helper/customEvent'import { MODAL_OPEN, MODAL_OPENED, MODAL_CLOSE } from '@/enums/events'
window.modal = () => ({  open: false,  init() {    if (this.instantDisplay !== undefined) {      this.open = true    }  },  close() {    this.open = false    customEvent(MODAL_CLOSE, this.name)  },  wrapper: {    async [`@${MODAL_OPEN}.window`](e) {      if (modalToOpen !== e.payload.name) {        return      }
      customEvent(MODAL_OPENED, this.name)      this.open = true    },  },})

enum

并不是指实际意义上的枚举,只是个用来保存常量的辅助文件,方便我们在整体代码库中使用这些常量,而不用担心事件在重命名时会连锁搞崩掉别的东西。

代码语言:javascript
AI代码解释
复制
const MODAL_OPEN = 'modal-open'const MODAL_OPENED = 'modal-opened'const MODAL_CLOSE = 'modal-close'

helper

我们可以在任何地方导入 helper 函数且不会保留任何状态。这个是我们的 customEvent helper 函数:

代码语言:javascript
AI代码解释
复制
export default function (name, payload = null, originalEvent = null) {  // 入参对象应包含以下:  // name: 'string',  // payload: 'object'  // originalEvent: 'this',或者其他你需要点击的目标
  const customEvent = new CustomEvent(name, {    detail: {      payload: payload,      originalEvent: originalEvent,    },  })
  window.dispatchEvent(customEvent)}

这个简单的 helper 给我们带来极大的灵活性,让我们摆脱了定义无数个 Alpine 组件的烦恼,在包括 HTML 中等任何地方直接调用。其本质也不过是标准 CustomEvent API 的一部分,改造成可在窗口范围内使用的函数且能接收 onclick 属性入参。

代码语言:javascript
AI代码解释
复制
<button type="button" onclick="customEvent('name', 'payload')"></button>

内容提供器

内容提供器通过可复用功能提供数据,可以把它看作是客户端的 API 层。和 helper 函数一样,这些函数不应包含任何状态,且可被组件消耗的。

下面是实时搜索的内容提供器大致代码:

代码语言:javascript
AI代码解释
复制
import customEvent from '@/helper/customEvent'import { SEARCH_GET } from '@/enums/events'
async function getResultFor(searchTerm) {  let result = undefined
  await fetch(`/search?q=${searchTerm}`)    .then((response) => response.json())    .then((data) => {      result = data    })
  customEvent(SEARCH_GET, result)
  return result}
export { getResultFor }

store

既然我们 JavaScript 框架选择依赖 Alpine.js 2.8,那么选择 Spruce 做全局状态管理也很合理。网站的每个部分都有一个 store,以下几行代码是我们用于管理大型菜单状态的:

代码语言:javascript
AI代码解释
复制
Spruce.store('megamenu', {  activeId: null,  toggle(id) {    if (id === this.activeId) {      this.activeId = null      return    }    this.activeId = id  },})

新旧指标的对比

在确定架构并顺利实施最复杂的组件后,我们很自信我们前进的道路一定是正确的。性能标准测试结果也很好,大部分的性能分类都有了 15-20 百分点的提升。

我们迫不及待地想实现所有组件以获得完整的指标结果,每次点击 Lighthouse 标签中“生成报告”按钮,都会让我们的心跳加速。如果不包含脚本的话,预计我们的网站是不可能达到 56 的评分,但这是我们现在的结果:

再次声明,这只是我们的开发环境,因此很多图中的“机会”并不适用于实际生产环境。

这次的结果让我们颇为满意,在最后的几项测试,并对代码进行清理后,我们开始准备下周一的版本发布。

上午 8 点 24 分,我们点下了“合并”按钮。在这之前我们进行了发布前的最后一次 Lighthouse 测试,性能评分当时下降到了 28,具体是什么原因造成的这次 10 分左右的下降我们并不清楚。部署工作顺利进行,网站运行正常,于是我们又进行了一次 Lighthouse 测试。这是测试结果:

在上线之后我们发现了一些小问题,在及时修复后我们成功将评分打上 62 分,真是太刺激了!当然,这并不会是我们旅途的终点,我们仅仅是为后续进一步改善用户界面体验打下了良好的基础。

荣誉提名:Debugbear

在这次重新部署中,我们需要一个能对指标进行监控的工具。在研究通过 CI/CD 管道、手动测试或是通过 Lighthouse 节点 CLI 运行脚本时,我们偶然发现了 Debugbear。

Debugbear 的服务可以检测网站的核心状态、运行 Lighthouse 测试并将测试结果与竞争对手或历史结果进行对比,从而提供对两次测试结果的深层次解读。它不仅帮我们更好地了解问题根因,还提升了我们对优化工作的信心。

可以说,Debugbear 的性价比非常高,再加上 Matt 人真的很好,当时我们的信用卡除了问题,他非常慷慨地延长了我们的试用期,让我们安心测试而不用担心最后期限。

写在最后

以上基本就是我们旅程的第一阶段了。

最终的成果让我们对自己的决策充满了信心。Vue 并不适合我们的项目,老实说,当初选择 Vue 或许是因为它看起来不错,但它从来不是我们最好的选择。错处不在 Vue,Vue 是个很强的框架,我们也还在继续使用它,但现在我们有了另一个比 Vue 更合适的工具。

希望这篇文章能帮上你!如果有任何问题,欢迎在推特(https://twitter.com/timkley)上联系我😊。

原文链接:

https://www.tim-kleyersburg.de/articles/from-vue-to-alpinejs by Tim Kleyersburg

声明:本文为InfoQ翻译,未经许可禁止转载。

今日好文推荐

后Kubernetes时代的未来?Wasmer 3.0 发布,可在浏览器外运行 WebAssembly

马斯克要求推特程序员写周报,具体到代码行数;刘强东称将末位淘汰部分京东高管;闰秒终于要被取消了!| Q资讯

阿里云李飞飞:用5年让PolarDB成为“国货之光”| 开源人说

谷歌计划裁员上万人:利用刚上线半年的新绩效系统解雇6%“排名垫底”员工

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 InfoQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
解锁全栈能力:java程序员的全栈自我革新与ChatGPT的智能协助
之前开发 Chat.GPTMIni.ai 的时候为了快速上线,找朋友做了前端,上线以来每个月有几百块的微薄收入,但是已经好几个月没有更新过了。感觉对那些付费用户蛮愧疚的。
一个程序猿的异常
2024/03/18
9040
解锁全栈能力:java程序员的全栈自我革新与ChatGPT的智能协助
面试官:如何提升应用的Lighthouse 分数
Lighthouse 是用于测试网页性能工具最有用的技术之一。它具备了自动化,并可以测量网站的可访问性和 SEO。更重要的是,它目前是开源的并且可以免费使用。同时,它可以用来测试渐进式 Web 应用程序。
前端修罗场
2022/07/29
2.3K0
面试官:如何提升应用的Lighthouse 分数
《首屏加载优化手册:Vue3+Element Plus项目提速的技术细节》
接手公司内部管理系统的前端优化需求时,首先面临的是用户集中反馈的“首屏加载慢”问题—测试环境用Lighthouse检测,首屏加载时间长达6秒,TTI(可交互时间)更是超过8秒,不少异地办公的同事因为网络波动(比如偏远地区的4G信号),甚至要等10秒才能操作界面,有客户在反馈中明确表示“每次打开系统都要等半天,赶报表时急得冒火,严重影响工作效率”。这套系统基于Vue 3+Element Plus开发,上线两年间经过5任开发迭代,既没有统一的资源管理规范,也没做过针对性的性能优化:第三方组件库全量引入,不仅vendor.js体积高达2.3MB,还包含了从未使用的“树形表格”“颜色选择器”等组件,冗余代码占比超60%;首页渲染的15张功能图标全是未压缩的PNG格式,单张大小超过100KB,其中最大的“数据看板”图标甚至达到180KB;更关键的是,3个非首屏必需的“月度数据统计”“操作历史记录”“部门权限列表”接口,在页面初始化时就与核心的“用户信息”“菜单列表”接口同步调用,导致带宽占用集中,核心接口响应延迟从正常的300ms延长到800ms,进而阻塞了菜单渲染。这些问题叠加在一起,让首屏加载成了用户体验的“重灾区”,更棘手的是,系统用户多为企业员工,使用的设备差异极大,从配置老旧的办公电脑(CPU为i5-6500,内存4GB)到新款笔记本都有,老旧设备运行浏览器时,还会因资源加载过多出现页面卡顿甚至浏览器崩溃,优化需求迫在眉睫。
程序员阿伟
2025/10/26
2340
《首屏加载优化手册:Vue3+Element Plus项目提速的技术细节》
前端工程师必知的 MCP 秘籍 包含渲染优化与性能提升等长尾知识要点
MCP即渲染优化三要素(Measure - Compute - Paint),是前端性能优化的核心方法论:
小焱
2025/05/28
7270
前端工程师必知的 MCP 秘籍 包含渲染优化与性能提升等长尾知识要点
Nuxt.js实战:Vue.js的服务器端渲染框架
首先,确保你已经安装了Node.js和yarn或npm。然后,通过命令行创建一个新的Nuxt.js项目:
天涯学馆
2024/06/06
2.6K0
Vue.js 首次屈居第二,JavaScript 2020 年度“新起之秀”都有谁?谁是第一呢?
不平凡的 2020 年体现在了方方面面,就连 JavaScript 的年度“新秀”也出现了 5 年来首次的变化,这次都有哪些项目上榜呢?
前端达人
2021/01/29
2.6K0
Vue.js 首次屈居第二,JavaScript 2020 年度“新起之秀”都有谁?谁是第一呢?
写给 vue2.0 开发者的 vue3.0 教程
Vue 3还没有正式发布,但是维护者已经发布了beta版本,以供我们的用户尝试并提供反馈
公众号---人生代码
2020/05/26
3.1K0
写给 vue2.0 开发者的 vue3.0 教程
Vue.js如何写一个简单的原生js模块,浏览器中的表现如何?
浏览器正在逐步的支持原生JavaScript模块。Safari和Chrome的最新版本已经支持它们了,Firefox和Edge也将很快推出。
笔阁
2018/09/04
3.5K0
Vue.js如何写一个简单的原生js模块,浏览器中的表现如何?
vue项目你一定会用到的性能优化!
而本渣最近维护的项目恰巧在这个方向下了很大功夫,一些经验之谈奉上,希望对大家有些许帮助!
用户7413032
2022/04/24
1.5K0
vue项目你一定会用到的性能优化!
从龟速 11s 到闪电 1s,详解前端性能优化之首屏加载
全文共6511字/词,阅读大概需要13分钟,太长不看党请直接移步👉「开始优化」部分直接查看优化手段 背景 前段时间公司服务器网络波动,网站访问变慢,一些性能问题也随之暴露了出来。纷纷反馈在这样的弱网条件下,访问新项目时,加载了近1分钟都没加载出来,而访问其他页面顶多也就30-40s。 在网络恢复后,尝试访问了下页面,无缓存首次打开需要等待近11s的时间,最大的资源达到了3.7M... 在对项目做了一些优化处理后,再次无缓存打开可以发现网页几乎是秒开,平均耗时在1s以内 在这里总结记录一下,基本上都是一些
@超人
2021/12/17
3.9K0
从龟速 11s 到闪电 1s,详解前端性能优化之首屏加载
值得关注的 Vue.js开源项目[每日前端夜话0xFF]
Vue.js 框架是由经验丰富的开发人员创建的,具有可靠的社区支持,丰富的功能,而且是轻量级的。
疯狂的技术宅
2019/12/23
2.5K0
值得关注的 Vue.js开源项目[每日前端夜话0xFF]
提升 Web 核心性能指标的 9 个建议
今天继续来为大家解读今年的 Google I/O ,我会重点为大家解读前端开发者应该关注的信息
ConardLi
2023/08/23
1.1K0
提升 Web 核心性能指标的 9 个建议
前端系列第6集-Vue3系列
Vue 3.0 的设计目标是在保持 Vue.js 核心框架的易用性和灵活性的同时,对性能进行大幅度提升、提高可维护性、并引入更多的新特性。主要的优化和新特性如下:
达达前端
2023/10/08
3720
金九银十,带你复盘大厂常问的项目难点
作为面试官,我经常听到很多候选人说在公司做的项目很简单,平常就是堆页面,写管理端,写H5,没有任何亮点,我以我一次面试候选人的经历分享给大家
linwu
2023/09/07
1.6K0
金九银十,带你复盘大厂常问的项目难点
选择最适合你的框架,看这份详细的Web框架性能分析报告!
本报告的目的是通过真实的数据来更好地了解框架选择、性能和实际用户体验之间的关系。我们将试图回答以下几个关键问题:
前端小智@大迁世界
2023/03/15
1.3K0
选择最适合你的框架,看这份详细的Web框架性能分析报告!
怎样为你的 Vue.js 单页应用提速
我有一个项目用了 Vue.js 来构建单页应用程序。随着上线日期的临近,性能优化的工作变得越来越重要。在本文中,我收集了有关在加载时间和渲染性能方面提高 Vue.js 应用性能的所有知识。
疯狂的技术宅
2020/05/11
3.3K0
怎样为你的 Vue.js 单页应用提速
前后端通吃,vue大全Mark一下
仓库地址:https://github.com/opendigg/awesome-github-vue
BUG弄潮儿
2020/06/15
6.9K0
JavaScript在移动端网站运行慢?咋办?
随着移动互联网快速发展,移动端网站的页面效果也越来越绚,但是交互体验或多或少有些“迟钝”?这是为啥呢?
前端达人
2019/01/10
2.6K0
JavaScript在移动端网站运行慢?咋办?
取代 Vue 和 React?25 年码龄程序员不满 Web 现状创建新框架 Nue JS,能将代码量减少 10 倍!
近日,前端开发者 Tero Piirajinen 推出了一个名为 Nue.js 的极简化前端开发工具,并迅速引发社区讨论。Piirajinen 在 Hacker News 上表示,它是 React、Vue、Next.js、Vite、Svelte 和 Astro 的替代品。
深度学习与Python
2023/09/24
9570
取代 Vue 和 React?25 年码龄程序员不满 Web 现状创建新框架 Nue JS,能将代码量减少 10 倍!
为什么我们喜爱,使用和支持Vue.js
让我告诉你一个关于Vue的故事,不仅仅是从Vue开发者的角度,我也会尝试着解释在Monterail中使用它的很多原因,你将会发现采用它对开发者和产品所有者来说都是一个很棒的决定。我将会告诉你我们如何拥抱Vue社区以及如何通过组织第一次国际Vue大会对其历史作出重大贡献。
疯狂的技术宅
2019/03/27
1.3K0
推荐阅读
相关推荐
解锁全栈能力:java程序员的全栈自我革新与ChatGPT的智能协助
更多 >
领券
社区新版编辑器体验调研
诚挚邀请您参与本次调研,分享您的真实使用感受与建议。您的反馈至关重要,感谢您的支持与参与!
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场