使用 Alchemy 将 Vite React SPA 部署到 AWS:AWS.Website.Vite 与 S3 + CloudFront 实战

发布时间:2026/9/13 23:54:07
使用 Alchemy 将 Vite React SPA 部署到 AWS:AWS.Website.Vite 与 S3 + CloudFront 实战 使用 Alchemy 将 Vite React SPA 部署到 AWSAWS.Website.Vite 与 S3 CloudFront 实战【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code本篇技术指南以 Alchemy 仓库中的官方示例 aws-website-vite 为骨架完整讲解如何用AWS.Website.Vite把纯客户端 Vite React 应用一键部署到 AWS静态资源存放于 S3、经由 CloudFront 分发不创建任何服务端函数。读完本文你将掌握 Alchemy 中 Vite 站点的堆栈编写、增量构建跳过、SPA 路由回退、本地开发与销毁全流程并能读懂其底层框架集成源码与集成测试的验证方式。方案概览一个纯静态的云部署AWS.Website.Vite是 Alchemy 为纯客户端 Vite 项目提供的复合资源composite resourcevite build的输出——即dist目录下的所有静态资产——被上传到 S3 Bucket并通过一个 CloudFront 分发对外提供服务。整个过程中不会生成任何 Lambda 或服务端函数页面完全在浏览器端渲染CSR因此它的适用对象是React / Vue / Solid 等 SPA以index.html为入口的多页应用multi-page app任何部署产物全是静态文件的 Vite 项目。这一点在资源源码中体现得非常直接AWS/Website/Vite.ts 的文档注释明确写道never creates a server function并且其ViteProps类型刻意Omit掉了env、memorySize、timeout、architecture、runtime这些只对服务端函数才有意义的字段。示例工程的结构如下完整文件可查看 示例目录aws-website-vite/ ├── alchemy.run.ts # 堆栈定义部署的总入口 ├── package.json # 脚本与依赖 ├── vite.config.ts # 项目自己的 Vite 配置含插件 ├── index.html # SPA 的 HTML 入口 ├── src/ │ ├── main.tsx # React 挂载入口 │ ├── components/Card.tsx # 示例组件Tailwind 样式 │ └── styles/global.css # import tailwindcss; └── test/ └── integ.test.ts # 真实部署的集成测试前置依赖安装框架集成包AWS.Website.Vite在部署时才动态加载构建驱动包alchemy.run/frontend-frameworks它负责以编程方式调用项目自身安装的 Vite 完成构建因此它必须被显式安装到项目里bun add -d alchemy.run/frontend-frameworks示例工程的 package.json 中它以workspace:*形式声明在仓库内作为工作区包使用并同时声明了alchemy、effect、distilled.cloud/aws等运行时依赖以及vitejs/plugin-react、tailwindcss/vite、tailwindcss、vite、typescript等构建期依赖。示例要求 Node.js 版本不低于 22engines: { node: 22 }。编写堆栈逐行解析 alchemy.run.tsalchemy.run.ts 是部署的核心全文如下import * as Alchemy from alchemy; import * as AWS from alchemy/AWS; import * as Effect from effect/Effect; export default Alchemy.Stack( AwsWebsiteViteExample, { providers: AWS.providers(), state: AWS.state(), }, Effect.gen(function* () { // A plain Vite SPA: static assets in S3 behind CloudFront. spa // defaults on, so unmatched paths answer with the index page (200). const site yield* AWS.Website.Vite(Website, { // Only hash the files that affect the build, so unchanged sources // skip the Vite build (and the deploy) entirely. memo: { include: [src/**, index.html, package.json, vite.config.ts], }, forceDestroy: true, }); return { url: site.url, }; }), );各要素的职责如下要素作用Alchemy.Stack(AwsWebsiteViteExample, ...)声明一个命名堆栈名字全局唯一providers: AWS.providers()注入 AWS 云提供商凭证解析、资源创建的执行环境state: AWS.state()配置堆栈状态的持久化后端用于跟踪已创建的资源AWS.Website.Vite(Website, {...})创建 Vite 静态站点资源返回的site.url即 CloudFront 分发地址memo.include声明影响构建结果的文件集用于内容哈希与增量跳过forceDestroy: true销毁时允许删除受保护/非空的资源如 S3 Bucketreturn { url: site.url }将站点地址作为堆栈输出暴露memo.include增量构建的关键开关memo.include决定了哪些输入文件参与内容哈希。只有当这些文件的哈希发生变化时Alchemy 才会重新执行vite build并重新部署否则后续部署会完全跳过构建与上传详见 README 原文Unchanged sources skip the Vite build entirely on subsequent deploys。示例只哈希src/**、index.html、package.json、vite.config.ts——这些都是真正影响产物内容的文件。反过来如果把临时文件、构建缓存等纳入 include会破坏增量机制、导致每次部署都全量重建值得注意。Vite 配置如何被原生加载插件照常生效AWS.Website.Vite的一个关键设计是构建时原生加载项目自己的vite.config.*包括其中的插件。示例的 vite.config.ts 就是一个标准 Vite 配置import tailwindcss from tailwindcss/vite; import react from vitejs/plugin-react; import { defineConfig } from vite; // Alchemy loads this config natively — plugins included — when it runs // the Vite build for AWS.Website.Vite. export default defineConfig({ plugins: [react(), tailwindcss()], });Tailwind CSS v4 正是通过tailwindcss/vite插件接进来的global.css 只有一行import tailwindcss;vitejs/plugin-react负责 JSX 编译与 React Fast Refresh。这意味着你现有的 Vite 生态插件、别名、代理、环境变量展开等无需任何迁移即可直接用于云端构建。从源码看这个原生加载是刻意为之的。在 Vite.ts 中Alchemy 只构造了一个极小的inlineConfigconst inlineConfig (root: string): Recordstring, unknown ({ root, logLevel: warn, ...(options?.vite?.configFile ! undefined ? { configFile: path.resolve(root, options.vite.configFile) } : undefined), ...(options?.vite?.base ! undefined ? { base: options.vite.base } : undefined), ...(options?.vite?.outDir ! undefined ? { build: { outDir: options.vite.outDir } } : undefined), });即只注入root、logLevel以及可选的configFile/base/outDir覆盖其余全部交给项目自身的vite.config.*自动发现与加载。构建完成后readViteOutput 把整个输出目录映射为assets-only的BuildOutputclientDirectory 解析出的build.outDirserverModules: undefined无外部工作区并明确验证输出目录必须存在否则抛出可操作的FrameworkErrorThe Vite build produced no output directory at ...。outDir 的解析优先级build.outDir的解析遵循如下顺序见 Vite.ts若显式传入vite.outDir直接以项目根为基准解析该相对路径否则调用 Vite 的resolveConfig读取项目配置中解析后的build.outDir保证配置读取与实际构建永远一致若 Vite 版本过老不支持resolveConfig回退到默认值dist。部署流程与增量跳过部署只需两步README 原文命令bun install bun run deploybun run deploy实际执行的是 package.json 中定义的alchemy deploy。首次部署会运行一次完整的vite build项目自身的配置与插件→ 把产物上传到 S3 → 创建/更新 CloudFront 分发。由于 CloudFront 全局边缘节点首次冷启动分发需要一段时间首次部署耗时通常为 510 分钟这是示例集成测试为beforeAll设置 120 万毫秒20 分钟超时的原因。之后只要memo.include覆盖的输入文件哈希未变后续部署会直接跳过 Vite 构建甚至跳过上传。值得一提的是AWS 目标的构建是在一次性子进程中执行的见 vite/aws.ts 的注释——因为vite.config.*会执行用户插件插件可能读取 cwd、修改process.env、甚至调用process.chdir()这些副作用绝不能污染引擎主进程。本地开发alchemy dev 就是 Vite 开发服务器bun run devalchemy dev并不会创建任何云资源而是以编程方式启动项目自己的 Vite dev server天然带 HMR并把site.url指向本地地址。其实现细节见 Vite.ts端口解析Vite ≥ 8.2.1 使用port: 0系统分配旧版本探测一个临时空闲端口生命周期通过Effect.acquireRelease管理 dev server关闭 Scope 即关闭服务器含httpServer.closeAllConnections()释放超时 3 秒、best-effort 兜底就绪探测启动后以 250ms 间隔重试至多 40 次对本地地址发起 HTTP 请求确保 listener 真正可响应后才认为就绪。开发环境与生产部署互不影响——除非你显式调用Alchemy.remote()选择完整部署否则alchemy dev永远走本地 dev server 路径。SPA 路由回退spa 默认开启纯 Vite 应用几乎都是单页应用因此AWS.Website.Vite的spa选项默认开启任何未匹配的路径都会返回index.html并以200状态应答从而保证/some/client/route这类前端路由可以深度链接deep-link成功。这在 README 与资源源码中都有明确说明README 原文spadefaults on, so unmatched paths answer with the index pageAWS/Website/Vite.tsdefault true unless errorPage is set。spa与errorPage互斥// 多页项目关闭 SPA 回退并为 404 提供真实错误页 const site yield* AWS.Website.Vite(Docs, { spa: false, errorPage: 404.html, });常用进阶配置AWS.Website.Vite的完整属性ViteProps见 AWS/Website/Vite.ts可归纳为以下几类构建覆盖vitebag——用于部署时决定的值会覆盖vite.config.*配置文件无法消费 AlchemyOutput这类动态值必须走这里// 部署期覆盖 base 路径 const site yield* AWS.Website.Vite(Docs, { vite: { base: /docs/ }, }); // 覆盖构建输出目录 const site yield* AWS.Website.Vite(Web, { vite: { outDir: build }, });替代配置文件config——指定另一份 Vite 配置代替自动发现的vite.config.*const site yield* AWS.Website.Vite(Web, { config: vite.deploy.config.ts, });项目子目录rootDir——当 Vite 项目不在堆栈文件同级时const site yield* AWS.Website.Vite(Web, { rootDir: ./app, });自定义域名domainconst site yield* AWS.Website.Vite(Web, { domain: { name: app.example.com, hostedZoneId: zone.hostedZoneId, }, });复用现有 Routerdomain.router——让多个站点共享同一个 CloudFront/Route53 路由const router yield* AWS.Website.Router(Router, {}); const site yield* AWS.Website.Vite(Web, { domain: { router }, });销毁bun run destroy执行alchemy destroy会按依赖逆序清理 CloudFront 分发与 S3 Bucket。示例堆栈开启了forceDestroy: true允许删除非空/受保护资源否则带内容的 S3 Bucket 可能因保护策略而无法删除。与部署一样CloudFront 分发的删除也需要数分钟集成测试在afterAll中同样给出了 120 万毫秒的超时。集成测试真实部署的自动化验证test/integ.test.ts 展示了如何用alchemy/Test/Bun对真实 AWS 部署做端到端验证。几个值得学习的细节冷启动容忍新 CloudFront 分发传播期间可能短暂返回 404/5xxTest.getWhenReady会在该窗口内失败并重试同时 CDN 边缘缓存未就绪时200 响应体也可能是旧内容因此测试用getBodyWhenReady校验状态码 200 响应体包含预期字符串双重条件。重试策略Effect.retry配合Schedule——指数退避500ms 起步与固定间隔3s取最小最多重试 20 次。生命周期钩子beforeAll(deploy(Stack))做首次部署因此也验证了完整构建链路afterAll.skipIf(!!process.env.NO_DESTROY)(destroy(Stack))销毁堆栈——设置NO_DESTROY环境变量可保留资源以便人工排查。五项核心断言与本文内容一一对应部署成功且暴露urlexpect(url).toBeString()首页 HTML 可访问且包含titleVite on AWS/title客户端 JS bundle 包含Hello from Vite!与Styled with Tailwind CSS证明 React 应用被打进产物编译后的 CSS 包含.text-3xl证明tailwindcss/vite插件真实执行了未匹配路径/some/client/route返回首页证明spa默认开启生效。对应的单元测试位于 Vite.test.ts它验证readViteOutput把资产目录映射为 assets-only 的BuildOutput、输出目录缺失时报错以及在进程内无子进程驱动vite build得到正确clientDirectory/distDirectory的完整流程。小结通过AWS.Website.Vite一个标准的 Vite React SPA 可以用不到 30 行堆栈代码完成构建 → 上传 S3 → 挂载 CloudFront → 输出 URL的全部部署且天然具备增量跳过、SPA 路由回退、本地 HMR 开发等能力。理解memo.include的哈希边界、spa/errorPage的路由语义以及配置原生加载、部署时覆盖的分层原则是把它用好、用对的关键。若你的站点还需要服务端渲染仓库中另有基于同一 Vite 管线的 Astro、SvelteKit、Octane 等复合资源见 AWS/Website 目录可在此基础上继续探索。【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询