Ember + Vite 部署响应式图片:告别 LCP 性能坑
很多人在用 Ember v2 (Vite) 构建项目时,习惯性地把图片直接扔在
下一篇
从“凭感觉写代码”到项目崩溃,中间只隔了一个功能迭代。 →
public/assets 里,然后用 <img> 标签直接引用。这种做法在项目初期没问题,但一旦图片多了,尤其是高分辨率的原图,在移动端加载简直是灾难,Largest Contentful Paint (LCP) 指标直接爆表,而且很容易触发 Layout Shift 导致页面跳动。其实处理响应式图片不需要自己造轮子,responsive-image 这个库已经很成熟了,但尴尬的是它的文档更新太慢,很多还是针对旧版 Webpack 的。我最近在给自己的个人站做优化时踩了坑,总结了一套在现代 Ember 环境下的实操方案。
一、 基础资产结构
首先,你的图片存放路径得清晰。建议统一放在 public/assets 的子目录下,这样方便管理和后续可能的自动化处理。
my-app
├── app
│ ├── templates
│ │ └── projects.gts
│ └── utils
│ └── projects.ts
└── public
└── assets
└── projects
├── project-1.jpg
├── project-2.png
└── demo.webp
二、 避坑指南:从静态引用到响应式
以前我们写模板可能是这样,直接遍历数据渲染 <img>:
{{#each datum.items as |item|}}
{{#each item.imageUrls as |imageUrl|}}
<img src={{imageUrl}} alt="project screenshot" />
{{/each}}
{{/each}}这种写法在手机端会加载 4K 大图,太浪费流量了。要实现真正的响应式,得结合 responsive-image 插件,通过配置 srcset 让浏览器根据屏幕密度自动选择图片。
三、 核心实战配置
在现代 Ember 架构中,如果你想通过数据驱动图片加载并保持性能,建议在 utils 层定义好图片的元数据,而不是简单的路径字符串。
/* app/utils/projects.ts */
type WorkItem = {
activities: string[];
duration: string;
imageUrls?: string[]; // 这里建议改为对象数组,包含不同分辨率路径
organization: string;
position: string;
};
export const data = [
{
items: [
{
activities: ['...', '...'],
duration: '2023 - Present',
imageUrls: ['/assets/projects/file-2.jpg'],
organization: 'Ember Workshop',
position: 'Developer',
},
],
title: 'Work',
type: 'work-item',
},
];对于 Vite 构建的项目,确保你的 ember-cli-vite 配置正确,这样在生产环境下,这些静态资源能被正确处理。如果需要更精细的控制,可以使用 srcset 属性手动指定不同宽度的图片路径,或者利用插件自动生成。
最关键的一点:一定要给图片预设 width 和 height,或者使用 CSS 的 aspect-ratio。不然在图片加载出来之前,页面高度是 0,加载完瞬间撑开,用户体验极差。
