@aws-amplify/东道主
使用 CloudFront + S3 + Lambda 向 AWS 部署静态站点,SPA 和 SSR 应用(Next.js, Nuxt, Astro, SvelteKit).
QQ 重要: 需要单独的文件
托管 必须 定义 amplify/hosting.ts ——从 amplify/backend.ts。这是因为主机作为独立的 CloudFormation 堆栈部署,允许您独立部署前端和后端.
amplify/
├── backend.ts ← defineBackend() — auth, data, storage
├── hosting.ts ← defineHosting() — CloudFront, S3, Lambda
└── ...
快速启动
SPA (反应, Vue等)
// amplify/hosting.ts
import { defineHosting } from '@aws-amplify/hosting';
defineHosting({
framework: 'spa',
buildCommand: 'npm run build',
});
说明:
defineHosting()被设计为可扩展的CLI(ampx deploy) (中文(简体) ). 它只有在收到内部的 Cloud Formation 模板时才能合成'amplifySynth'IPC电文来自CLI. 运行amplify/hosting.ts直接与npx cdk synth或者说node将 没有 生成 CloudFormation 模板。 如果您需要在独立的 CDK 应用程序中使用主机构造, 请使用AmplifyHostingConstruct从@aws-amplify/hosting/constructs相反——见 独立的 CDK 使用 见下文.
Next.js (瑞典语)
// amplify/hosting.ts
import { defineHosting } from '@aws-amplify/hosting';
defineHosting({
framework: 'nextjs',
buildCommand: 'npm run build',
});
说明: 没错 没有 需要配置
output: 'standalone'内next.config.js。适配器使用 @ opennextjs/ aws (帮助) 内部,它自动处理构建转换.
部署
# Deploy everything (backend + frontend)
npx ampx deploy --identifier prod
# Deploy only backend (auth, data, storage)
npx ampx deploy --identifier prod --backend
# Deploy only frontend (hosting) — requires backend deployed first
npx ampx deploy --identifier prod --frontend
常见错误
❌ 错误——不要添加主机定义备份 :
// amplify/backend.ts — THIS IS WRONG
import { defineBackend } from '@aws-amplify/backend';
import { hosting } from './hosting/resource';
defineBackend({ hosting }); // ❌ Will not work
✅ CORRECT - 使用单独的扩展/主机文件 :
// amplify/hosting.ts — THIS IS CORRECT
import { defineHosting } from '@aws-amplify/hosting';
defineHosting({
framework: 'spa',
buildCommand: 'npm run build',
});
主机是一个独立的CDK入站点. CLI 发现 amplify/hosting.ts 并将其自动部署为单独的 Cloud Formation 堆栈.
建筑
主机包采用双层架构:
- 框架适配器 - 将特定框架的建设产出转变为通用产出
DeployManifest - L3 CDK 构造 ——解读AWS资源(S3,CloudFront,Lambda等)的明细表和规定
这种构造是完全框架不可知的。 它永远不知道是来自Next.js,Astro,还是自定义适配器.
执行情况说明: 框架适配器和 L3 CDK 构造由
@aws-blocks/hosting。 。 。 .@aws-amplify/hosting重新出口这些物项(在《京都议定书》之下AmplifyHostingConstruct添加可放大特有胶水——defineHosting(), (中文(简体) ),definePipeline(),以及后端-输出集成.
适配管道
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ Framework │ │ Deploy Manifest │ │ AWS Resources │
│ Build Output │ ──► │ (generic JSON) │ ──► │ (CDK L3 Construct) │
└─────────────────┘ └──────────────────┘ └─────────────────────┘
adapter() AmplifyHostingConstruct
内建适应器
| 适配器 | 说明 |
|---|---|
| 下一个.js | 用途 @ opennextjs/ aws (帮助) 用于处理 Next.js 构建输出。 支持 App 路由器, Pages 路由器, ISR, 中间软件, 图像优化, 以及响应流. |
| 硝基 | 硝基安全部门改革产出(.output/) (中文(简体) ). Nuxt和Astro的节点/Lambda目标背后的引擎. |
| 坚果 | Nuxt 3应用程序(由硝基适配器所建). |
| 天体 | 使用节点/Lambda适配器(由硝基适配器所建)的Astro SSR应用. |
| 斯维尔特基特 | SvelteKit 应用程序通过 @sveltejs/adapter-node (SSR)加上静态/前置输出. |
| 最高人民会议 | 静态单页应用(React,Vue,Angular等). 所有路线都服务 index.html 有客户端的路由. |
以上全部出口自 @aws-amplify/hosting/adapters (单位:千美元)nextjsAdapter, (中文(简体) ), nitroAdapter, (中文(简体) ), nuxtAdapter, (中文(简体) ), astroAdapter, (中文(简体) ), sveltekitAdapter, (中文(简体) ), spaAdapter)和通过框架检测自动选择;您只需要一个不在此列出的框架的自定义适配器.
基础设施
- 第3条: 带有OAC(Origin访问控制)的私人桶. 所有公众访问被封锁.
- 云纹:HTTP/2 + HTTP/3,TLS 1.2+,gzip/brotli压缩,安全头(HSTS,CSP,X-Frame-options).
- 兰布达 (SSR):有响应流的原生Lambda处理器,IAM认证函数URL,最小优先的IAM角色.
- 兰布达@ Edge (Middleware):用于请求/响应转换的边缘函数.
- 图像优化: 分离出 Lambda, 并有尖锐的按需图像再大小和格式转换.
- ISR 缓存: S3缓存桶 + DynamoDB (基于tag的再验证) + SQS (同步再验证队列). 当适配器宣布缓存配置时自动提供 .
- 原子部署:每个部署在 S3. CloudFront 函数重写 URL 中创建一个新建的 ID 前缀. 零下断时.
特征
ISR(递增静态再生)
Next.js 互联网档案馆的存檔,存档日期2013-12-02 revalidateTag() 财务报告和审定财务报表 revalidatePath() 获得充分支持。 适配器自动提供:
- S3 缓存桶 ——存储预发页
- 迪纳摩DB 表格 —— 地图缓存标记为路径
revalidateTag() - SQS 队列 ——处理合成再验证请求
不需要配置——如果您的 Next.js app 使用 ISR, 则基础设施会自动提供 .
图像优化
下一个.js <Image> 构成部分和 next/image 优化出框的工作。 专用的 Lambda 函数控件 :
- 按需调整大小到已配置大小
- 格式转换 (WebP, AVIF)
- 在 S3 中缓存优化图像
中间软件
Next.js 中间软件作为 Lambda@Edge 函数运行,支持:
- 请求/答复页眉操作
- 重定向和重写
- 边缘验证检查
- 基于地理位置的路由
反应
SSR响应使用Lambda响应流化(通过函数 URL)进行流化,将时间减少为服务器发送页面的第一个字节(TTFB).
部署期间发生了什么?
- 构建 ——您的构建命令运行(例如,
npm run build(中文(简体) ) - 适配器 ——框架适配器将产出构建为
DeployManifest(下一步js在内部使用 OpenNext) - CDK 合成器 —— CDK 合成基于表单的 Cloud Formation 模板
- 云阵部署 - AWS规定/更新所有资源
时间线 :
- 第一次部署: ~15-20分(云花分发提供为瓶颈)
- 其后部署: ~5分钟(资产上传+缓存无效)
- 堆叠删除 : ~20-40分(云花在取出前必须完全禁用)
配置
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
framework | 'nextjs' | 'nitro' | 'nuxt' | 'astro' | 'sveltekit' | 'spa' | 'static' | string | 自动检测 | 框架类型。 自动从包裹. json. |
buildCommand | string | - 说吧 | 在部署前建立运行命令 . |
buildOutputDir | string | 自动检测 | 预建输出路径( SPA/ static) 。 已忽略 Next.js( OpenNext 构建) . |
environment | Record<string, string | ByoValue> | - 说吧 | Env vars被注射到SSR计算. 使用 secret()编号 :config()编号 :byoSecret()编号 :byoConfig() 敏感值或可旋转值——见 密钥环境变量( E)。 。 。 . |
secretStore 编号 : configStore | { prefix?, stage? } | 每个项目的默认 | 覆盖存储路径/名称空间 secret() 编号 : config() 数值. |
monitoring | { enabled?, snsTopicArn? } | { enabled: true } | Cloud Watch 提醒 (5xx, Lambda errors/throttles, revalidation DLQ). 星洲网. 默认;每个警报每月几分钱。 设定 { enabled: false } 选择退出. |
skewProtection | { enabled, maxAge? } | { enabled: true } | 滚动部署时基于 Cookie 的版本 skew 保护. 默认的. |
domain | { domainName, hostedZone } | - 说吧 | 自定义 SSL 域 。 需要53号公路托管区. |
waf | { enabled, rateLimit? } | - 说吧 | 启用 AWS WAF 有管理规则 + 速率限制 。 加上~$5个月. |
customAdapter | FrameworkAdapterFn | - 说吧 | 不支持的框架自定义框架适配器 . |
compute | { memorySize?, timeout?, logRetention?, reservedConcurrency? } | 1024MB, 30s | SSR的Lambda配置. |
cdn.priceClass | PriceClass | PRICE_CLASS_100 | 云花价类. 使用 PRICE_CLASS_ALL 全球分布. |
cdn.contentSecurityPolicy | string | 限制性违约 | 自定义 CSP 头值 . |
cdn.geoRestriction | { type, countries } | - 说吧 | 云龙分布的地理限制. |
storage.retainOnDelete | boolean | false | 在堆栈删除时保留 S3 桶 . |
storage.encryption | 'S3_MANAGED' | 'KMS' | 'S3_MANAGED' | 主机桶的加密类型 . |
logging.enabled | boolean | false | 启用 CloudFront 访问日志到 S3 . |
logging.retentionDays | number | 90 | 保存访问日志的天数 . |
生产警告: 默认
storage.retainOnDelete实值false,这意味着S3桶和 所有主机资产被永久删除 当云形堆栈被摧毁时。 这是方便的 dev/测试,但 生产风险用于生产堆栈,设置storage: { retainOnDelete: true }用于保存堆栈删除中的桶。 在独立的 CDK 使用中,您也可以设置removalPolicy: RemovalPolicy.RETAIN在建筑桶上直接.
自定义域
需要同一 AWS 账户中的 Route53 主机区 。 通过DNS自动创建并验证ACM证书.
// amplify/hosting.ts
import { defineHosting } from '@aws-amplify/hosting';
defineHosting({
domain: {
domainName: 'app.example.com',
hostedZone: 'example.com',
},
});
第一次使用自定义域需要更长的时间 (2–5多分与Route53相接,与外接DNS可能更长)因为ACM证书验证屏蔽了CloudFormation堆栈直到证书签发.
外部 DNS 用户 : 您必须手动创建 CNAME 记录用于ACM 验证 。 CloudFormation将等待长达72小时的证书验证后,时间才会出来并滚回.
建议: 保持您所在的路由53区在同一 AWS 中最平滑的经验。 DNS验证记录是自动创建的.
更改您的自定义域
变化 domainName 初始部署原因后 5-30分钟停机时间 ,同时替换证书并重新配置 CloudFront 。 对于零下行域迁移:
- 创建一个带有新域的新堆栈
- 核查新站点工程
- 更新 DNS 以指向新的 CloudFront 分布
- 删除旧堆栈
WAF (Web 应用程序防火墙)
启用 AWS 管理规则(Common Rules set + Known Bad Introductions)和基于IP的费率限制(1000 req/5min/IP默认).
// amplify/hosting.ts
import { defineHosting } from '@aws-amplify/hosting';
defineHosting({
waf: { enabled: true, rateLimit: 1000 },
});
费用: ~5美元/月基数+100万美元/次请求。 用于具有安全要求的生产应用.
WAF 区域要求
具有CloudFront射程的WAF需要部署到 us-east-1. 在其他区域部署允许的WAF将因明确错误信息而失败.
第二阶段部署
ampx deploy 采用两相部署模式:
- 后端阶段 (单位:千美元)
ampx deploy --backend: 部署认证、数据和存储资源。 生成amplify_outputs.json。 。 。 . - 前端阶段 (单位:千美元)
ampx deploy --frontend: 运行您的构建命令( 与amplify_outputs.json然后部署托管资源.
运行 ampx deploy 没有旗帜 相继部署两个阶段.
旗帜
| 旗帜 | 行为 |
|---|---|
| (无) | 部署后端 + 前端 |
--backend | 只部署后端( skip 主机) |
--frontend | 只部署前端( 需要先部署后端) |
说明: --backend 财务报告和审定财务报表 --frontend 两者相互排斥。 指定两者都是错误.
密钥环境变量( E)
这个 environment prop在您的 SSR 计算中注入值 。 支持三种类型:
-
平地环境 vars ——非敏感字,被烤入"云形"模板(从不在此放出秘密):
defineHosting({ environment: { APP_REGION: 'us-east-1' } }); // read at runtime with process.env.APP_REGION -
秘诀 (单位:千美元)
secret())——存储在AWS保密管理器中的敏感值. 只有商店定位器被注入;该值从未输入模板. -
配置 (单位:千美元)
config()) ——储存在SSM参数存储器中的非敏感但可旋转值.
// amplify/hosting.ts
import { defineHosting, secret, config } from '@aws-amplify/hosting';
defineHosting({
environment: {
STRIPE_SECRET_KEY: secret('STRIPE_SECRET_KEY'), // → AWS Secrets Manager
FEATURE_FLAGS: config('FEATURE_FLAGS'), // → SSM Parameter Store
},
});
用 CLI 设置带外值( 两者都支持) set 编号 : get 编号 : list 编号 : remove:
npx ampx secret set STRIPE_SECRET_KEY sk_live_xxx
npx ampx config set FEATURE_FLAGS '{"newCheckout":true}'
在运行时间从 无 CDK 运行时间条目( e)@aws-amplify/hosting/runtime - 远离你的CDK/建设代码:
import { getSecret, getConfig } from '@aws-amplify/hosting/runtime';
const key = await getSecret('STRIPE_SECRET_KEY');
const flags = JSON.parse(await getConfig('FEATURE_FLAGS'));
参考现有资源 指向您已经管理的秘密/参数( 无 CLI) set 页:1 byoSecret() (名称或ARN)和 byoConfig() (SSM 参数名):
import { defineHosting, byoSecret, byoConfig } from '@aws-amplify/hosting';
defineHosting({
environment: {
DB_PASSWORD: byoSecret(
'arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/db-AbCdEf',
),
LD_ENV: byoConfig('/my-org/launchdarkly/prod'),
},
});
默认情况下,每个工程的商店都会被命名为空格: 机密 : /amplify/hosting/<project>/secrets/<KEY>配置时 /amplify/hosting/<project>/config/<KEY>,通过 secretStore 编号 : configStore。 。 。 .
计算机/光盘 definePipeline()
definePipeline() 提供自动AWS代码Pipeline(V2)——每个分支一个管线——在每次推力上都部署你的应用,并有多阶段的推出,批准门,烘烤时间,以及每个阶段的配置打入. 定义它 amplify/pipeline.ts 并使用 npx ampx deploy --pipeline (此旗帜不能与 --identifier) (中文(简体) ).
// amplify/pipeline.ts
import { definePipeline } from '@aws-amplify/hosting/pipeline';
import { Duration } from 'aws-cdk-lib';
export const pipeline = definePipeline({
source: {
repo: 'my-org/my-app',
connectionArn:
'arn:aws:codeconnections:us-east-1:123456789012:connection/abc-123',
triggerOnPush: true,
// triggerFilters: ['src/**', 'amplify/**'], // optional monorepo path filters
},
crossAccountKeys: true, // needed for cross-account stage targets
branches: [
{
branch: 'main',
stages: [
{
name: 'staging',
config: { domain: 'staging.example.com' },
},
{
name: 'prod',
requireApproval: true,
bakeTime: Duration.minutes(30),
env: { account: '222222222222', region: 'us-west-2' },
config: { domain: 'app.example.com' },
},
],
},
],
});
source—— 说repo(单位:千美元)owner/repo),代码连接connectionArn(平面字符串),可选triggerOnPush编号 :triggerFilters。 。 。 .branches[].stages[]—— 说name选项env(单位:千美元){ account, region }, (中文(简体) ),requireApproval, (中文(简体) ),bakeTime联合国Duration),并按阶段输入config。 。 。 .synth- 覆盖该建筑:commands, (中文(简体) ),installCommands, (中文(简体) ),computeType(单位:千美元)ComputeType(注),env, (中文(简体) ),primaryOutputDirectory。 。 。 .crossAccountKeys编号 :selfMutation——交叉账户文物钥匙,管线是否更新amplify/pipeline.ts更改( 默认)true) (中文(简体) ).
读取当前舞台内部的配置 amplify/hosting.ts 与 getStageConfig()数字 :
import { defineHosting } from '@aws-amplify/hosting';
import { getStageConfig } from '@aws-amplify/hosting/pipeline';
const stage = getStageConfig<{ domain: string }>();
defineHosting({
domain: stage?.config?.domain
? { domainName: stage.config.domain, hostedZone: 'example.com' }
: undefined,
});
getStageConfig() 返回时 undefined 管道之外(例如当地 ampx deploy)),因此守住进入.
限制
沙盒
defineHosting 不支持在 ampx sandbox。主机资源在沙盒开发过程中默默跳出。 使用 ampx deploy --identifier <name> 完全托管部署.
管理 ampx pipeline-deploy
defineHosting 不支持管理 ampx pipeline-deploy (放大托管分支部署). 对于CI/CD, 运行 ampx deploy 或使用内置的自管理代码Pipeline通过 definePipeline()。 。 。 .
HEAD 请求 Content-Length 均等
A 类 HEAD 请求 SSR Lambda 返回 Content-Length: 0 而不是未来 GET 身体长度。 这是一个 Nitro / Lambda 函数 URL 上游限制: 框架的 HTTP 服务器不会预先计算一个 HEAD 并且AWS的响应-流式包装器通过任何框架集.
受影响:下载管理器,CDN Head预飞,RFC 9110§9.3.2严格客户端.
绕行:需要准确长度的客户应发行 GET 与 Range: bytes=0-0 (返回第一个字节+) Content-Range改为 HEAD。 。 。 .
多区跨区导航缓存
当两个扩展主机部署在同一个域前(例如: / + 有关博客 /blog/* 通过跨区重写,在目前发射的区域之间进行导航 Cache-Control: private, no-cache 并在每次航行中回转两只蓝巴达.
工作:设定明确 s-maxage=N 通过您框架的跨区路径头 headers() 相会. 未来版本会浮出一出每道适配器的取号.
Range 流出端点上的请求
流出安全部门改革路线(尼特罗) nitro.awsLambda.streaming: true, Astro 5, Next.js RSC)默默地忽略 Range 头- Lambda 函数 URL 流出前会缓冲整个正文. 使用非流端点或倒回静态 Range- 能力来源(S3直接,单独的文件服务器Lambda).
自定义框架适配器
对于未在(Remix等——注 Nuxt、Astro和SvelteKit已建入)中构建的框架,提供自定义适配器,以返回 a DeployManifest数字 :
// amplify/hosting.ts
import { defineHosting } from '@aws-amplify/hosting';
import type { FrameworkAdapterFn } from '@aws-amplify/hosting/adapters';
import type { DeployManifest } from '@aws-amplify/hosting';
import * as path from 'path';
const myAdapter: FrameworkAdapterFn = (projectDir): DeployManifest => ({
version: 1,
compute: {},
staticAssets: { directory: path.join(projectDir, 'dist') },
routes: [{ pattern: '/*', target: 'static' }],
});
defineHosting({
customAdapter: myAdapter,
buildCommand: 'npm run build',
});
SSR 自定义适配器示例
import type { DeployManifest } from '@aws-amplify/hosting';
import type { FrameworkAdapterFn } from '@aws-amplify/hosting/adapters';
import * as path from 'path';
const astroSSRAdapter: FrameworkAdapterFn = (projectDir): DeployManifest => ({
version: 1,
compute: {
server: {
type: 'handler',
bundle: path.join(projectDir, 'dist/server'),
handler: 'entry.handler',
placement: 'regional',
streaming: true,
runtime: 'nodejs20.x',
memorySize: 1024,
timeout: 30,
},
},
staticAssets: {
directory: path.join(projectDir, 'dist/client'),
cacheControl: 'public, max-age=31536000, immutable',
},
routes: [
{ pattern: '/_astro/*', target: 'static' },
{ pattern: '/favicon.ico', target: 'static' },
{ pattern: '/*', target: 'server' },
],
});
部署宣言司马
这个 DeployManifest 是框架适配器与 L3 构造之间的合同。 自定义适配器必须返回此形状 :
type DeployManifest = {
version: 1;
/** Named compute resources */
compute: Record<string, ComputeResource>;
/** Static asset configuration */
staticAssets: {
directory: string;
cacheControl?: string;
};
/** Route behaviors — maps URL patterns to compute or static */
routes: RouteBehavior[];
/** Cache infrastructure (auto-provisions S3 + DynamoDB + SQS) */
cache?: CacheConfig;
/** Image optimization (auto-provisions a separate Lambda) */
imageOptimization?: ImageConfig;
/** Middleware (deploys to Lambda@Edge) */
middleware?: MiddlewareConfig;
/** Redirects, rewrites, custom headers */
redirects?: Redirect[];
rewrites?: Rewrite[];
headers?: CustomHeader[];
/** Build ID for atomic deployments (auto-generated if omitted) */
buildId?: string;
};
type ComputeResource = {
type: 'handler' | 'http-server' | 'edge';
bundle: string;
handler?: string; // for type: 'handler'
entrypoint?: string; // for type: 'http-server'
port?: number; // for type: 'http-server'
placement: 'regional' | 'global';
streaming?: boolean;
runtime?: string;
memorySize?: number;
timeout?: number;
environment?: Record<string, string>;
};
type RouteBehavior = {
pattern: string; // URL pattern (glob only — CloudFront wildcards * and ?)
target: string; // compute resource name, or 'static'
fallback?: string; // fallback target on error
};
type CacheConfig = {
computeResource: string;
tagRevalidation: boolean; // provisions DynamoDB
revalidationQueue: boolean; // provisions SQS
};
type ImageConfig = {
bundle: string;
handler: string;
formats: string[];
sizes: number[];
};
type MiddlewareConfig = {
bundle: string;
handler: string;
matchers: string[];
};
计算类型
| 类型 | 说明 | AWS 资源 |
|---|---|---|
handler | 本地Lambda 处理器( 最快冷起步) | 有函数 URL 的 Lambda |
http-server | 用 Lambda Web 适配器包裹的 HTTP 服务器 | Lambda + 网络适应器层 |
edge | 低相关性全局执行的边缘函数 | 兰布达@ Edge |
Lambda 配置
自定义 SSR Lambda 设置 :
// amplify/hosting.ts
import { defineHosting } from '@aws-amplify/hosting';
defineHosting({
framework: 'nextjs',
compute: {
memorySize: 1024, // MB (default: 1024)
timeout: 60, // seconds (default: 30)
reservedConcurrency: 50, // concurrent executions (default: none)
},
});
内容安全政策
默认的CSP是有意限制的:
default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; media-src 'self'; object-src 'none'; frame-ancestors 'self'
unsafe-eval 未包含 在默认政策中。 这是一个蓄意的安全决定—— eval() 财务报告和审定财务报表 new Function() 是常见的 XSS 向量。 多数现代框架(包括Next.js)没有 unsafe-eval。 。 。 .
然而,一些库(例如某些模板引擎,更古老的图表库)要求 eval() 在运行时间。 如果你的应用程序需要它,使用 cdn.contentSecurityPolicy 要覆盖的道具 :
// amplify/hosting.ts
import { defineHosting } from '@aws-amplify/hosting';
defineHosting({
cdn: {
contentSecurityPolicy:
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; media-src 'self'; object-src 'none'; frame-ancestors 'self'",
},
});
独立的 CDK 用法( 无扩展 CLI)
AmplifyHostingConstruct 在任何 CDK 项目中作为标准的 CDK L3 构造工作 —— 不 放大 CLI, 不 defineHosting(),没有 amplify/ 需要目录 .
子路径导入
使用子路径导入来吸引您需要的 :
// The construct itself
import { AmplifyHostingConstruct } from '@aws-amplify/hosting/constructs';
// Adapters for framework detection and build output transformation
import {
spaAdapter,
nextjsAdapter,
detectFramework,
getAdapter,
} from '@aws-amplify/hosting/adapters';
// Error type for catch clauses
import { HostingError } from '@aws-amplify/hosting/error';
// Manifest types for custom adapters
import type {
DeployManifest,
RouteBehavior,
ComputeResource,
} from '@aws-amplify/hosting';
依赖说明 : 子路径导入( :
/constructs, (中文(简体) ),/adapters, (中文(简体) ),/error这样做 没有 导入任意@aws-amplify/*运行时的软件包。 只有主要切入点(@aws-amplify/hosting(b) 将defineHosting()工厂,取决于@aws-amplify/plugin-types和其他放大包。 如果您只使用子路径导入, 您的工程不需要安装任何扩展包 .
SPA 示例( Vanilla CDK)
import { App, Stack } from 'aws-cdk-lib';
import { AmplifyHostingConstruct } from '@aws-amplify/hosting/constructs';
import type { DeployManifest } from '@aws-amplify/hosting';
import * as path from 'path';
const app = new App();
const stack = new Stack(app, 'MySpaStack', {
env: { account: '123456789012', region: 'us-east-1' },
});
const manifest: DeployManifest = {
version: 1,
compute: {},
staticAssets: { directory: './dist' },
routes: [{ pattern: '/*', target: 'static' }],
};
const hosting = new AmplifyHostingConstruct(stack, 'Hosting', {
manifest,
});
// Access created resources for composition with other constructs
console.log(hosting.distributionUrl); // https://d111111abcdef8.cloudfront.net
console.log(hosting.bucket.bucketName); // auto-generated bucket name
Next.js SSR 实例(万尼拉 CDK)
import { App, Stack } from 'aws-cdk-lib';
import { AmplifyHostingConstruct } from '@aws-amplify/hosting/constructs';
import { nextjsAdapter } from '@aws-amplify/hosting/adapters';
const app = new App();
const stack = new Stack(app, 'MyNextjsStack', {
env: { account: '123456789012', region: 'us-east-1' },
});
// Run the OpenNext adapter to produce a DeployManifest
const manifest = nextjsAdapter({ projectDir: process.cwd() });
new AmplifyHostingConstruct(stack, 'Hosting', {
manifest,
compute: {
memorySize: 1024,
timeout: 60,
},
});
Next.js 适配器使用 @opennextjs/aws 内部处理构建输出,并用:
- 本地 Lambda 处理器(不需要网络适应器包装)
- ISR 缓存配置(S3 + DynamoDB + SQS)
- 图像优化 Lambda
- 中间软件边缘功能( 如果适用)
使用 BYO 证书自定义域
import { Certificate } from 'aws-cdk-lib/aws-certificatemanager';
import { AmplifyHostingConstruct } from '@aws-amplify/hosting/constructs';
// Certificate MUST be in us-east-1 — CloudFront requirement
const cert = Certificate.fromCertificateArn(
stack,
'MyCert',
'arn:aws:acm:us-east-1:123456789012:certificate/abc-123',
);
new AmplifyHostingConstruct(stack, 'Hosting', {
manifest,
domain: {
domainName: 'app.example.com',
hostedZone: 'example.com',
certificate: cert, // BYO cert — skips deprecated DnsValidatedCertificate
},
});
重要内容: CloudFront 需要ACM 证书
us-east-1。如果您提供了来自另一个区域的证书,则构造将丢入InvalidCertificateRegionError合成时间(混凝土ARN)。 对于跨存储符号ARN,CloudFront会在部署时拒绝证书.
写入自定义适配器
该建筑由 DeployManifest. 内置适配器(spaAdapter, (中文(简体) ), nextjsAdapter, (中文(简体) ), nitroAdapter, (中文(简体) ), nuxtAdapter, (中文(简体) ), astroAdapter, (中文(简体) ), sveltekitAdapter) 过程框架建立产出并制作此表。 您可以为上面没有覆盖的任何框架(Remix等)编写自己的适配器.
自定义框架的 Skeleton 适配器 :
import * as fs from 'fs';
import * as path from 'path';
import type { DeployManifest, RouteBehavior } from '@aws-amplify/hosting';
/**
* Custom adapter for Astro (example).
* Scans Astro's build output and returns a DeployManifest.
*/
export const astroAdapter = (projectDir: string): DeployManifest => {
const buildOutputDir = path.join(projectDir, 'dist');
if (!fs.existsSync(buildOutputDir)) {
throw new Error(`Build output not found at ${buildOutputDir}`);
}
const hasServerDir = fs.existsSync(path.join(buildOutputDir, 'server'));
const routes: RouteBehavior[] = [];
// Static assets with aggressive caching
routes.push({
pattern: '/_astro/*',
target: 'static',
});
if (hasServerDir) {
// SSR: catch-all goes to compute
routes.push({ pattern: '/*', target: 'server' });
return {
version: 1,
compute: {
server: {
type: 'handler',
bundle: path.join(buildOutputDir, 'server'),
handler: 'entry.handler',
placement: 'regional',
streaming: true,
runtime: 'nodejs20.x',
},
},
staticAssets: {
directory: path.join(buildOutputDir, 'client'),
cacheControl: 'public, max-age=31536000, immutable',
},
routes,
};
}
// Static-only: all routes from S3
routes.push({ pattern: '/*', target: 'static' });
return {
version: 1,
compute: {},
staticAssets: { directory: path.join(buildOutputDir, 'client') },
routes,
};
};
使用带有构造的自定义适配器:
import { AmplifyHostingConstruct } from '@aws-amplify/hosting/constructs';
import { astroAdapter } from './astro-adapter';
const manifest = astroAdapter(process.cwd());
new AmplifyHostingConstruct(stack, 'Hosting', {
manifest,
});
关键是 可支持任何框架 通过写入返回 a 的适配器 DeployManifest. 构造处理所有 AWS 资源创建(S3, CloudFront, Lambda, OAC等) 基于运算表.
解决问题
构建失败, 但错误消息不明
本地运行您的构建命令( R)npm run build),以查看全输出. 部署显示第一个1000+最后一个1000个字符.
CloudFront 返回 403
这不应该发生在OAC桶政策上。 如果有,请检查S3桶政策是否包括CloudFront发行ARN.
部署时间很长
第一次部署会创建云纹分布(~15-20分). 随后的部署更快(~5分).
ISR 页面没有重新验证
确保您的 Next.js 应用程序使用 App 路由器 revalidateTag() 或者说 revalidatePath()页: 1revalidate: N 内 getStaticProps)也通过基于时间的再验证支持.
图像优化返回 500
请检查access-date=中的日期值 (帮助) 图像优化 Lambda 有足够的内存(默认:1024MB). 大图像可能需要1024MB+. 通过 compute 配置 .