813 字
4 分钟

在 Astro 中实现全自动响应式图像:结合 Rehype 与 astro:assets

在 Astro 中实现全自动响应式图像处理的优雅方案。通过编写一个自定义 Rehype 插件,在构建时拦截 Markdown 图片,并利用 astro:assets 的强大功能将其替换为高性能的响应式组件
2025-08-01
Views: ...

背景#

70c1a207a437b3a7ca74faf16563f7a8abf2dcfe 这次提交中,博客的图像处理能力得到了质的飞跃。其核心目标是:在不改变 Markdown 写作习惯(即仍然使用 ![alt](src) 语法)的前提下,自动将标准图片转换为功能强大的响应式图像。

这解决了传统 <img> 标签的几个痛点:无法根据设备尺寸提供不同大小的图片、无法自动转换为 WebP 等现代格式、以及需要手动添加懒加载等。

实现方案#

该方案巧妙地结合了 Astro 的构建时转换能力和组件化能力,主要分为两步:

1. 使用 Rehype 插件拦截图像#

第一步是在内容处理流程中,找到所有的 <img> 标签并将其替换为一个自定义的 Astro 组件。这通过一个自定义的 Rehype 插件 rehype-figure.mjs 来实现。

它的工作流程如下:

  • 遍历 AST:插件遍历由 Markdown 生成的 HTML 抽象语法树(AST)。
  • 定位 <img>:找到所有标签名为 img 的节点。
  • 创建新节点:提取出原 <img> 标签的 srcalt 属性。
  • 替换节点:使用这些属性创建一个新的 <markdown-image> 组件节点,并用它替换掉原来的 <img> 节点。
src/plugins/rehype-figure.mjs
import { visit } from 'unist-util-visit';
import { h } from 'hastscript';
export default function rehypeFigure() {
return (tree) => {
visit(tree, 'element', (node, index, parent) => {
if (node.tagName !== 'img') return;
const src = node.properties?.src;
const alt = node.properties?.alt;
if (!src) return;
// 创建 <markdown-image> 组件节点
const markdownImageNode = h('markdown-image', { src, alt: alt || '' });
// 替换
if (parent && typeof index === 'number') {
parent.children[index] = markdownImageNode;
}
});
};
}

2. 创建强大的响应式图像组件#

第二步是实现 <markdown-image> 标签对应的 Astro 组件——MarkdownImage.astro。这个组件是所有响应式魔法发生的地方,它利用了 Astro 内置的 astro:assets 功能。

src/components/misc/MarkdownImage.astro
---
import { Image } from "astro:assets";
interface Props { src: string; alt: string; }
const { src, alt } = Astro.props;
const isRemote = src.startsWith("http");
---
<figure class="flex flex-col items-center">
{
isRemote ? (
<img {src} {alt} class="rounded-lg" />
) : (
<Image
src={/* ...动态导入本地图片的逻辑... */}
{alt}
class="rounded-lg"
widths={[400, 800, 1200]}
sizes="(max-width: 800px) 100vw, 800px"
format="webp"
/>
)
}
{alt && <figcaption class="mt-2 text-center text-sm">{alt}</figcaption>}
</figure>

这个组件的核心逻辑是:

  • 区分来源:判断图片是远程链接还是本地文件。
  • 处理本地图片:对于本地图片,使用 Astro 的 <Image> 组件。
    • widthssizes 属性让 Astro 自动生成不同尺寸的图片,并告诉浏览器如何根据屏幕大小选择最合适的版本。
    • format="webp" 会自动将图片转换为高效的 WebP 格式。
    • Astro 的 <Image> 组件还内置了懒加载 (loading="lazy") 和其他性能优化。
  • 处理远程图片:对于远程图片,则回退到使用标准的 <img> 标签,不进行优化处理。
  • 语义化包裹:最后,使用 <figure><figcaption> 为图片提供正确的 HTML 语义。

结论#

通过“Rehype 插件拦截替换” + “Astro Assets 组件实现优化”的组合拳,博客实现了一套全自动、高性能且对内容创作者完全透明的响应式图像解决方案。这不仅极大地提升了网站的加载速度和用户体验,也展示了 Astro 在内容处理和性能优化方面的强大灵活性。

在 Astro 中实现全自动响应式图像:结合 Rehype 与 astro:assets
https://www.497995.xyz/posts/responsive-images/
作者
或许是一只龙
发布于
2025-08-01
许可协议
CC BY-NC-SA 4.0