Creating the Perfect Tourist Welcome Kit: A Local Business Guide
[Note: Pierre provided the initial framework, Emma expanded with practical examples and real business case studies from our valley.]
The Challenge: First Impressions Matter
Our Alpine Connect community website recently added a digital welcome kit feature for tourists. The goal was simple: help visitors discover local businesses while supporting our community economy.
The results exceeded our expectations:
- Local Business Directory

- Interactive Valley Map

Creating an effective tourist welcome system isn’t complicated if you follow our valley’s proven approach:
- Identify tourist pain points - What do they need first?
- Highlight local businesses - Not just the obvious tourist traps
- Create community connections - Bridge the gap between locals and visitors
The biggest challenge was making sure tourists find authentic local experiences rather than just the same commercial spots every guidebook mentions. We needed a way to showcase the businesses that locals actually use and love.
解决其实也很简单,当时在用的 Claude Code 也随即给出快糙猛的方案:在构建时将图片复制到 public/ 目录下,然后替换 Markdown 中的图片路径。它甚至还优雅地写了一个 Vite 插件来实现这个功能。
这个方案的好处在于:
- slides 作者可以无需关心图片路径问题。
- 图片和 Markdown 可以放在一起,方便管理。
就这样第一个版本上线了,虽然不完美,但是可以用够了。
尝鲜 Codex CLI,让它来优化
作为有一定技术品味的团队,我们当然不会止于一时的权宜之策。
由于 Astro 本身就有成熟的图片优化处理( cache busting 、转换 webp 等),并在 blog 中得到了很好的应用,我们当然希望 Slides 中的图片也能享受到 Astro 的图片优化方案。使得 Slides 中的图片也能享受到 Astro 的图片优化方案,即:更加的 Astro Native!
必要的知识背景
先说一下 Blog 中图片处理的过程,比如下面 Markdown 中引用的图片:

在 Astro 构建过程中,会将图片优化成类似于 /_astro/imgs/example.abc123.webp 这样的路径,直接使用原有的路径显然就无法正常显示图片了。
这个问题在 Astro 自己渲染 Markdown 为 HTML 是不会遇到的,因为 Astro render markdown 的过程中会自动进行图片路径的替换。但是在使用 Reveal.js 渲染的时候,由于无法使用 Astro 内置的 Render API 处理,自然就有问题。
使用 Codex CLI 分析问题
恰好其时 Codex CLI 有了新发布且新版口碑不错,而 Claude Code 又有降智和限制国内开发者使用的风波,所以我决定尝试一下 Codex CLI,看看它能否帮我分析并解决这个问题。
之前我们已经小范围尝试过 Codex CLI,我认为它在社区广受好评的原因是它生成的代码质量确实不错,幻觉较少,因为我发现它在思考的过程中会主动搜索相关资料,甚至直接去源码仓库寻找要调用的类库的源码,比如我发现它会主动读取 node_modules/ 目录下的包目录中的 *.d.ts 文件,以及相关的源码文件,来理解某个类库的用法,这点非常棒。这个行为是我在其他 AI 工具中鲜有见到的,它会让结果更准确。如果在提示词中明确指示它必须这么做,那么它更会遵循这个要求,其他的 AI 往往并不会这么做,导致幻觉率比较高,生成的代码几乎没法用。
所以我在提示词中要求它主动从源码和互联网中寻找解决方案,让方案更有可信度,大致的提示词如下:
... (省略大段描述代码现状的内容,以及遇到的问题) ...
你需要仔细理解我的问题,并详细分析可能解决方案。包括但不限于以下手段:
- 源码级别分析,找到 Astro 的源码,看看它怎么处理这种图片的?是否有暴露获取图片真实路径的方法或接口
- 查询官方文档,是否有蛛丝马迹?
- 直接互联网搜索,看看别人是否遇到过这个问题,是否已经解决?
于是 Codex 真的进行了大量的搜索,并返回了以下结果 (节选):
核心结论
slide.body在src/pages/slides/[...slug].astro中被当作纯字符串塞进SlideViewer,而这个 React 组件带有client:only="react",意味着 Markdown 永远只在浏览器里解析,Astro/Vite 无法介入去解析![]()、也无法替换资源路径,导致相对路径仍指向./imgs/_。(来源网站)- 目前的
slideImagesPlugin只是把图片额外复制到public/slides/**/imgs以维持旧路径,但绕过了 Astro 的图片优化与缓存;这就是“临时方案不够优雅”的根源(config/vite-plugin-slide-images.ts:1)。 - 博客页在
src/pages/blogs/[...slug].astro:27里调用了const { Content } = await render(post);,也就是利用 Astro 的编译链获取<Content />,因此 Markdown 内的图片会被编译期改写成/_astro/_.png并交给图片服务托管。(来源网站)
并给出了 3 种解决方案 (节选)
- 方案 A(保持 Astro 处理链):切换到
import.meta.glob以eager: true方式载入 slide Markdown,拿到 MarkdownInstance,直接调用compiledContent()得到 Astro 已经处理好的 HTML(包含正确的/_astro/…路径),再把 HTML 拆成 Reveal 所需的<section>或在 React 里用 dangerouslySetInnerHTML 渲染。优点是完全复用 Astro 的优化与域名白名单;缺点是需要在服务器侧追加一次 HTML→Section 的切分逻辑。 - 方案 B(生成图片映射清单):利用
import.meta.glob('/src/content/slides/*_/imgs/_', { import: 'default', query: '?url', eager: true })在构建期生成 “原始相对路径 → 产物 URL” 的映射;在把 Markdown 传给 SlideViewer 前,用正则或 remark 插件把./imgs/foo.png替换成映射后的/_astro/...。这样 Reveal 仍吃 Markdown,但路径已经安全。复杂度相对低,且尊重 Astro 对资源的指纹化处理。 - 方案 C(真正定制 markdown pipeline):在 Astro markdown.remarkPlugins 中注入自定义 remark plugin,遇到 image 节点时调用 Vite 的
this.load({ id, query: '?url' })或new URL(relativePath, import.meta.url).href获取最终 URL 并替换。这是最贴近 Astro 原生做法,但实现量最大,且要注意在 SSR 环境中处理异步。
分析还是非常准确的,确实也指出了之前“不够优雅”的解决方法。但是我不会照单全收,作为 AI 的使用者,必须要有自己的判断力,不能完全依赖 AI 的分析与结论。
我的思考与实践
其实这三种方案我都不太满意。因为我想要一个“简单”的解决方案,这三种方案不是太重就是偏离了原本的需求,感觉都难以落地。
于是我在评估这三种方案之后,又提出我的方案,就是是否能改用 Astro 组件代替 React 组件(SlideViewer),这样应该可以调用 Astro 内部的处理管线。跟 Codex 讨论后,觉得这个方案不可行,这个迁移会特别复杂,而且不能完全解决我们的问题。
于是我决定自己先向前走一步,看看能否找到更好的解决方案。在日志中加入一些打印语句后,我发现 Astro 会将解析过的 content 内容封装在 getEntry() 方法中返回的对象里,而这个对象会包含一些元数据和 rendered 对象,其中,里面的元数据中包含了 markdown 中引用的图片地址。类似于这样:
{
headings: [
...
],
localImagePaths: [ './imgs/agents-md-ecosystem.png' ],
remoteImagePaths: [],
frontmatter: {
...
},
imagePaths: [ './imgs/agents-md-ecosystem.png' ]
}
我将打印出来的结果交给 Codex 进一步分析,看看能否从这里做文章,这次 Codex 给出了新的方案,并且我觉得非常可行:
… (前后几个我觉得不太合适的方案省略) …
方案二:在服务器端先把 Markdown 里的相对路径替换成哈希 URL
在这个方案中,Codex 认为可以利用 Vite 的 eager import 功能,将所有的图片路径提前导入,获取所有本地图片的编译后路径,然后将 Markdown 中的相对路径替换成哈希 URL,这样图片就可以正常加载了。
这样处理后的 Markdown 在客户端解析时就会使用 /_astro/… 资源了。
这个方案明显就靠谱了非常多,在尝试之后,发现确实可行。再经过几轮提示词的调整,让 Codex 生成了可以直接获取经过 Astro 优化过的图片路径的代码,可以完美的将 Markdown 中的图片路径替换为经过 Astro 优化后的 webp 图片地址,而其他保持不变。
这次终于比较完美的解决了问题,大约一共花费了 2 小时左右的时间。Codex 的联网搜索功能真的太棒了,节省了大量自己研究的实现,防止踩坑,及时拉回正规上。
总结
回顾整个过程,虽然 Codex 本身功能出众,但是若非作为操控者的人在一旁指导,恐怕也难以得到一个让人满意的结果,很可能不是过于简单就是过于复杂,而非现在这种“刚刚好”的结果。