From 254c1d93700b23733391baf49f3a0049ceeb38bb Mon Sep 17 00:00:00 2001 From: QIU SHENGMING Date: Thu, 9 Jul 2026 05:35:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20rehype-image-optimization.?= =?UTF-8?q?mjs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使用新的转换源,cf Images --- rehype-image-optimization.mjs | 61 ++++++++++------------------------- 1 file changed, 17 insertions(+), 44 deletions(-) diff --git a/rehype-image-optimization.mjs b/rehype-image-optimization.mjs index 128e02a..e377199 100644 --- a/rehype-image-optimization.mjs +++ b/rehype-image-optimization.mjs @@ -3,77 +3,50 @@ import { visit } from 'unist-util-visit'; export function rehypeImageOptimization() { return (tree) => { visit(tree, 'element', (node) => { - + // 1. 基础防御:只处理 img 标签且有属性的 if (node.tagName !== 'img' || !node.properties) return; - + const src = node.properties.src; - // 没有 src 或者是相对路径导致解析失败的,直接跳过 if (!src) return; let urlObj; try { urlObj = new URL(src); } catch (e) { - // 相对路径兜底优化 node.properties.loading = 'lazy'; node.properties.decoding = 'async'; - return; + return; } - // 2. 业务逻辑:只处理 img.mckero.com (你的橱窗) + // 2. 业务逻辑:只处理 img.mckero.com if (urlObj.hostname !== 'img.mckero.com') { node.properties.loading = 'lazy'; node.properties.decoding = 'async'; return; } - // 3. 业务逻辑:跳过 WebP/AVIF (Worker 处理不了) - const pathname = urlObj.pathname.toLowerCase(); - if (pathname.endsWith('.webp') || pathname.endsWith('.avif')) { - node.properties.loading = 'lazy'; - node.properties.decoding = 'async'; - return; - } + // 3. 不再跳过 WebP/AVIF —— Cloudflare 可以对任意源格式做尺寸缩放, + // 并通过 format=auto 自动为浏览器输出最优格式,所以全部走转换 // ============================================================ - // 🚨 核心修正:适配 Photon 的 action 参数 🚨 - // 格式:action=resize!宽,高,模式 - // 高度设为 0 代表自适应,模式 2 代表缩放 + // ✅ 使用 Cloudflare Image Transformations(/cdn-cgi/image/) + // 直接在 img.mckero.com 上生效,不再依赖 opt.mckero.com Worker // ============================================================ - const generateWorkerUrl = (originalSrc, targetWidth) => { - const workerUrl = new URL('https://opt.mckero.com/'); - - // 1. 设置 url 参数 (原图地址) - workerUrl.searchParams.set('url', originalSrc); - - // 2. 设置 action 参数 (这才是 Worker 能看懂的指令!) - if (targetWidth) { - // 例如:resize!800,0,2 - workerUrl.searchParams.set('action', `resize!${targetWidth},0,2`); - } - - return workerUrl.toString(); + const generateCdnUrl = (targetWidth) => { + const options = `width=${targetWidth},format=auto,quality=80`; + return `https://img.mckero.com/cdn-cgi/image/${options}${urlObj.pathname}`; }; - // ============================================================ - // 生成四档 srcset (500, 800, 1200, 1600) - // ============================================================ + // 生成四档 srcset + node.properties.src = generateCdnUrl(800); + const s500 = generateCdnUrl(500); + const s800 = generateCdnUrl(800); + const s1200 = generateCdnUrl(1200); + const s1600 = generateCdnUrl(1600); - // 默认 src: 给 800w (兼容性兜底) - node.properties.src = generateWorkerUrl(src, 800); - - const s500 = generateWorkerUrl(src, 500); - const s800 = generateWorkerUrl(src, 800); - const s1200 = generateWorkerUrl(src, 1200); - const s1600 = generateWorkerUrl(src, 1600); - node.properties.srcset = `${s500} 500w, ${s800} 800w, ${s1200} 1200w, ${s1600} 1600w`; - - // sizes 逻辑 (手机满屏,电脑最大800) node.properties.sizes = '(max-width: 600px) 100vw, 800px'; - - // 标准优化属性 node.properties.loading = 'lazy'; node.properties.decoding = 'async'; });