懒加载与 AVIF/WebP 自适应,把 Codex 的 Base URL 改到 TaoToken 后让它查 Next.js 配置
把 Codex 的 Base URL 换成 TaoToken 的统一入口之后Next.js 图片优化里那堆 AVIF/WebP 自适应、懒加载开关就好查多了。先打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建一把 Key再把 Codex 的 base_url 填成 https://taotoken.net/api它就能对着你的 next.config.ts 和 Image 组件逐段读配置。之所以需要这种「逐段读」是因为这条链路上的开关实在太散formats 的数组顺序决定 AVIF 能不能协商成功deviceSizes 和 sizes 共同决定 srcset 里到底有哪几档宽度priority、loading、decoding 分别管 LCP 预加载、视口懒加载和解码时机一旦接上自定义 loader前面那些内置优化又会整体让位给 CDN 的实时转换参数。人工核对这些漏一个就够线上慢半拍而且通常要等 LCP 报表出来才被发现。下面按原文那条「图片优化全链路」的顺序走先把 next.config.ts 的 formats 与断点捋顺再看 Image 组件上三个开关怎么分工然后把 Codex 接上 TaoToken 做一遍体检最后是验证与排障。配置部分都是可以直接复制进项目的写的时候对照你自己的目录改路径即可。1. next.config.ts 的 formats 顺序决定 AVIF 能不能被协商出来1.1 formats 是协商列表不是「写了就一定会用」Next.js 的图片优化器在收到请求时会拿浏览器的 Accept 头去跟 images.formats 里的顺序做匹配。写成[image/avif, image/webp]的含义是优先给 AVIF浏览器不接受就退到 WebP两者都不接受才吐原图。很多人把 formats 改成只留 webp然后在报表里看到 AVIF 数量是零第一反应是「浏览器支持度不行」其实是从候选名单里自己划掉的。再隐蔽一点的坑是 loaderFile。项目一旦指定了自定义 loaderNext 内置的 optimizer 就整体退出formats、deviceSizes、minimumCacheTTL 这些参数统统不再参与决策真正决定输出格式的是 CDN 那一段实时转换逻辑。所以遇到「配置里明明写了 AVIF线上就是不生效」第一步先分清是走内置优化还是走 loader再往下一层查。1.2 deviceSizes 与 sizes 配合决定 srcset 里到底有几档deviceSizes 是生成 srcset 时用的宽度池sizes 则告诉浏览器「这张图在当前视口下大概会渲染多宽」。两个都写对浏览器才会挑一个档位接近的文件只写 deviceSizes 不写 sizes浏览器会按 100vw 估算窄屏手机上很可能拉一张 1920 宽的图回来。断点数量也不宜拉开太大。每个宽度都会触发一次优化并占用一份缓存档位从 5 个扩到 12 个缓存条目和首次命中成本都会上去反过来只留 640/1080/1920 三档窄屏就会在 640 和 1080 之间跳出现肉眼可见的清晰度台阶。比较稳的做法是把项目里实际会用到的卡片宽度、内容区最大宽度收进来多余的一律删掉。1.3 自定义 loader 拼出的宽度必须和 CDN 参数一一对上loader 的职责很纯粹输入 src、width、quality返回一个最终 URL。它的返回值会直接进 srcset 的 w 描述符所以 loader 里写w360CDN 就必须认 360 这个值。常见错法是 loader 把宽度四舍五入到最近的 100而 Next 生成的 srcset 仍然是 360/640/750两边对不齐CDN 索性回源原图前面省下来的带宽全吐回去。配置项作用范围容易写错的地方formats内置 optimizer 的格式协商顺序颠倒、只留 webp、被 loaderFile 架空deviceSizessrcset 的宽度池档位过密或过疏与实际布局脱节sizes浏览器挑档依据一律写 100vw导致大图被小屏拉走minimumCacheTTL优化产物缓存时长设太短重复优化拖慢首字节loaderFile接管优化与 URL 生成与 CDN 参数约定不一致// next.config.ts import type { NextConfig } from next; const nextConfig: NextConfig { images: { // AVIF 在前浏览器拒绝时自动退 WebP再退原图 formats: [image/avif, image/webp], deviceSizes: [360, 640, 750, 828, 1080, 1200, 1920], imageSizes: [96, 128, 256, 384], minimumCacheTTL: 60 * 60 * 24 * 30, // 只有走自建 CDN 时才打开这一行打开后上面的 formats 不再生效 // loaderFile: ./image-loader.ts, }, }; export default nextConfig;2. Image 组件上的 priority、loading、decoding 各管一段2.1 首屏 LCP 图才配得上 prioritypriority 会让 Next 给这张图插一条 preload同时把 loading 设为 eager、fetchPriority 设为 high。它是有代价的一个页面挂三张 priority等于三条 preload 一起挤在早期网络窗口里抢带宽反而把真正的主视觉拖慢。判断标准可以简化成一句——首屏内、且首屏渲染时就可见的图才加 priority轮播第二张之后、折叠区域里的图全部交给默认懒加载。2.2 其余图交给浏览器原生懒加载别自己再包一层Image 组件默认就是loadinglazy等于把这件事委托给浏览器原生实现。除非有非常具体的需求比如首屏之下但用户很容易快速滑到的那一屏否则不需要自己再套一层 IntersectionObserver多一层监听反而容易在快速滚动时出现空窗图先空一块再补上。decoding 建议保持 async。设成 sync 会让解码占用主线程对 LCP 只有坏处尤其是在低端机上现象就是文字先出来、图片卡一下才补上。2.3 placeholder 与 sizes 一起用才压得住 CLS模糊占位解决的是「图还没到时那块区域长什么样」。要让它真正起作用必须给 Image 明确的 width/height或者用 fill 加一个有尺寸的父容器否则布局该跳还是跳。sizes 最好贴着实际 CSS 写卡片列表用(max-width: 768px) 50vw, 320px比笼统的 100vw 准得多浏览器挑档时也更容易命中缓存里已有的那份。// app/components/Hero.tsx import Image from next/image; export function Hero() { return ( Image src/hero.jpg alt首页首屏主视觉 width{1600} height{900} sizes(max-width: 768px) 100vw, 1200px priority fetchPriorityhigh placeholderblur blurDataURLdata:image/svgxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciLz4 / ); }// image-loader.ts只有启用 loaderFile 时才需要 export default function imageLoader({ src, width, quality, }: { src: string; width: number; quality?: number; }) { const url new URL(src, https://your-cdn.example.com); url.searchParams.set(w, String(width)); // 必须与 srcset 的 w 完全一致 url.searchParams.set(q, String(quality ?? 75)); url.searchParams.set(fm, auto); // 让 CDN 按 Accept 头决定 avif / webp return url.toString(); }3. 让 Codex 逐段核对配置前先把 Base URL 填成 TaoToken3.1 模型 ID 以模型广场为准Key 在控制台创建打开 TaoToken 注册登录后先去模型广场确认这次要用的模型 ID——别直接抄别人文章里的模型名列表会更新抄错了会得到「模型不存在」而不是配置错误。确认好型号再进控制台创建 API Key拿到占位符YOUR_API_KEY。这把 Key 后面既用来问 next.config.ts也能继续追问模糊占位图、CDN 参数不用来回换。3.2 ~/.codex/config.toml 里写 model_provider 和 base_urlCodex 的配置走 TOML和 Claude Code 那套环境变量不是一回事别把 ANTHROPIC_* 变量往这里塞。编辑用户目录下的 config.toml# ~/.codex/config.toml model YOUR_MODEL_ID # 以模型广场当时列表为准 model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api # 末尾不要加 /v1 env_key TAOTOKEN_API_KEY wire_api chat # 按所选模型标注的接口类型填写Key 不要写进配置文件放进环境变量里更省事export TAOTOKEN_API_KEYYOUR_API_KEYPowerShell 里则是$env:TAOTOKEN_API_KEYYOUR_API_KEY或者干脆写进系统环境变量省得每次开新终端都要重来一遍。提示base_url 只写到 https://taotoken.net/api 就够。多写一个 /v1 会得到 404这是最常见的一类「明明配了却连不上」。3.3 一条测试消息确认通道通了重启终端之后再跑 Codex问一句和项目相关的问题比如「读一下 next.config.ts 里 images 这一段告诉我 formats 的匹配顺序以及 loaderFile 被打开后哪些配置会失效」。能正常返回说明 Base URL、Key、模型 ID 三件套都对上了。接着去 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 的控制台看这次调用的记录确认请求确实被记上账也顺便排除了「读到的是本地缓存」这种假成功。4. 用 Codex 对着项目做一次图片优化体检4.1 第一轮只查 formats 回退链把 next.config.ts 的 images 段落连同 loader 文件如果启用了一起贴进对话要求它只输出三件事当前 formats 是从哪一档开始匹配、哪些情况下会退到原图、loaderFile 是否让内置协商整个失效。限定输出范围很重要一次只问一条链路比让它「整体评估一下图片性能」有用得多后者通常会得到一堆正确但没法执行的建议。请只分析 next.config.ts 里 images 配置的格式协商链路 1) formats 数组按顺序会怎样匹配浏览器 Accept 头 2) 在什么条件下会回落到原图 3) 如果 loaderFile 已启用上述哪些配置会失效。 先给结论再逐行指出对应的配置项不要给优化建议。4.2 第二轮把 priority/loading/decoding 列成对照表让 Codex 扫描所有用到 Image 的页面组件输出一张表文件路径、是不是首屏可见、有没有 priority、loading 当前值、decoding 当前值最后标出可疑项。这一步的价值不在它比你聪明而在它不会因为「这块上周刚改过」就默认这里是对的全量扫一遍往往能翻出两三个漏改的页面。4.3 第三轮做 loader 与 CDN 参数对照把 loader 文件和 CDN 的转换参数说明一起给它让它逐个宽度核对 w、q、fm 有没有断层尤其是 srcset 里出现过但 CDN 不认的那些值。这里要注意边界Codex 只负责静态比对和解释真正的构建、上传、线上抓包还是要你在本地完成让对话里的模型直接去连 CDN 或线上环境测试既不是它擅长的也不在正常用法里。5. 验证与排障srcset、AVIF 与那几个报错5.1 在 DevTools 里确认最终下发了什么Network 面板筛 Img看 content-type 到底是 image/avif 还是 image/webp再切到 Elements看 img 的 srcset 与 currentSrc判断浏览器实际挑的是哪一档。如果 currentSrc 总是落在最大宽度上八成是 sizes 写得太宽或者 CSS 里图片被容器拉满浏览器只能按最坏情况估。5.2 图片侧的两个高频现象AVIF 没生效按顺序排查 formats 数组、loaderFile 是否接管了内置优化、CDN 有没有把 content-type 改回 jpeg 或 png。LCP 图仍然懒加载检查 priority 是不是加错了位置比如加在轮播容器而不是第一张图上或者外层套了一个自研的懒加载组件把 Next 的默认行为整个覆盖掉了。5.3 Codex 侧的报错对照现象常见原因处理方式401 未授权Key 没进环境变量或占位符没替换重新 export确认用的是真 Key404base_url 末尾多了 /v1改回 https://taotoken.net/api模型不存在模型 ID 抄错或已下架回模型广场按当时列表重新复制有响应但控制台没有记录对照的是另一把 Key核对 Key 前缀与当前配置是否一致注意改完 config.toml 记得开一个新终端老会话里的环境变量不会自动刷新这类「改了没反应」的情况十有八九是这里。6. 同一把 Key 继续问占位图和 CDN 参数图片优化不是一次配完就结束的事新页面加上来要重新判断谁是首屏图CDN 侧改了转换规则要回头对一遍 srcset模糊占位图的 base64 通常也是跑完一轮才补上去的。这些零碎问题不需要换工具用同一把 Key 接着问就行上下文还能延续上一个项目的判断标准。配完这轮之后建议先去 TaoToken 模型对话 用同一把 Key 发一条测试消息确认模型 ID 和 Base URL 都对得上如果打算长期在 Codex 里做这类配置审查可以看下 Coding Plan 的额度是否够用Key 随时可以在 控制台 API Keys 里新建或轮换。下一次再遇到「配置写了但线上不生效」把 next.config.ts 和 loader 一起丢进对话比在四五个文件之间来回翻要快得多。