Skip to content

Commit

Permalink
Sync
Browse files Browse the repository at this point in the history
  • Loading branch information
fwang committed Dec 22, 2023
1 parent 0c57b71 commit 361d867
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 99 deletions.
10 changes: 9 additions & 1 deletion examples/nextjs/sst.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ export default $config({
};
},
async run() {
const site = new sst.Nextjs("Web");
const site = new sst.Nextjs("Web", {
//domain: "ion-next.sst.sh",
// domain: {
// domainName: "ion-next.sst.sh",
// aliases: ["ion-nextjs.sst.sh"],
// redirects: ["www.ion-next.sst.sh"],
// hostedZone: "sst.sh",
// },
});

return {
siteURL: site.url,
Expand Down
1 change: 1 addition & 0 deletions internal/components/src/components/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class Component extends ComponentResource {
case "aws:iam/role:Role":
case "aws:cloudwatch/eventRule:EventRule":
case "aws:lambda/function:Function":
case "aws:dynamodb/table:Table":
overrides = { name: prefixName(args.name) };
break;
case "aws:sqs/queue:Queue":
Expand Down
243 changes: 145 additions & 98 deletions internal/components/src/components/nextjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,13 @@ export class Nextjs extends Component {
const outputPath = buildApp(name, args || {}, sitePath, buildCommand);
const { access, bucket } = createBucket(parent, name);
const revalidationQueue = createRevalidationQueue();
const revalidationTable = createRevalidationTable();

const plan = buildPlan(bucket);
// TODO set dependency
// TODO ensure sourcemaps are removed in function code
removeSourcemaps();

//if (!experimental.disableDynamoDBCache) {
// createRevalidationTable();
//}

const { distribution, ssrFunctions, edgeFunctions } =
createServersAndDistribution(
parent,
Expand Down Expand Up @@ -254,26 +252,24 @@ export class Nextjs extends Component {
}

function buildPlan(bucket: Bucket) {
return all([outputPath]).apply(([outputPath]) =>
return all([
outputPath,
$app.providers?.aws?.region!,
args?.edge,
args?.experimental,
args?.imageOptimization,
]).apply(([outputPath, region, edge, experimental, imageOptimization]) =>
all([
$app.providers?.aws?.region!,
args?.edge,
args?.experimental,
args?.imageOptimization,
bucket.name,
useRoutes(),
revalidationQueue.apply((queue) => queue?.url),
revalidationQueue.apply((queue) => queue?.arn),
revalidationQueue.apply((q) => ({ url: q?.url, arn: q?.arn })),
revalidationTable.apply((t) => ({ name: t?.name, arn: t?.arn })),
]).apply(
([
region,
edge,
experimental,
imageOptimization,
bucketName,
routes,
revalidationQueueUrl,
revalidationQueueArn,
{ url: revalidationQueueUrl, arn: revalidationQueueArn },
{ name: revalidationTableName, arn: revalidationTableArn },
]) => {
const serverConfig = {
description: "Next.js server",
Expand All @@ -287,9 +283,12 @@ export class Nextjs extends Component {
REVALIDATION_QUEUE_URL: revalidationQueueUrl,
REVALIDATION_QUEUE_REGION: region,
}),
...(revalidationTableName && {
CACHE_DYNAMO_TABLE: revalidationTableName,
}),
},
policies: [
...(revalidationQueue
...(revalidationQueueArn
? [
{
name: "revalidation-queue",
Expand All @@ -308,6 +307,37 @@ export class Nextjs extends Component {
},
]
: []),
...(revalidationTableArn
? [
{
name: "revalidation-table",
policy: JSON.stringify({
statements: [
{
actions: [
"dynamodb:BatchGetItem",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator",
"dynamodb:Query",
"dynamodb:GetItem",
"dynamodb:Scan",
"dynamodb:ConditionCheckItem",
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:DescribeTable",
],
resources: [
revalidationTableArn,
`${revalidationTableArn}/*`,
],
},
],
}),
},
]
: []),
],
layers: isPerRouteLoggingEnabled()
? [
Expand Down Expand Up @@ -547,86 +577,103 @@ if (event.rawPath) {
}

function createRevalidationTable() {
//if (!this.serverFunction) return;
//const { path: sitePath } = this.args;
//const table = new aws.dynamodb.Table(`${name}RevalidationTable`, {
// attributes: [
// { name: "tag", type: "S" },
// { name: "path", type: "S" },
// { name: "revalidatedAt", type: "N" },
// ],
// hashKey: "tag",
// rangeKey: "path",
// pointInTimeRecovery: {
// enabled: true,
// },
// billingMode: "PAY_PER_REQUEST",
// globalSecondaryIndexes: [
// {
// name: "revalidate",
// hashKey: "path",
// rangeKey: "revalidatedAt",
// projectionType: "ALL",
// },
// ],
//}, {parent});
//serverFunction?.addEnvironment("CACHE_DYNAMO_TABLE", table.tableName);
//table.grantReadWriteData(serverFunction.role!);
//const dynamodbProviderPath = path.join(
// sitePath,
// ".open-next",
// "dynamodb-provider"
//);
//if (fs.existsSync(dynamodbProviderPath)) {
// // Provision 128MB of memory for every 4,000 prerendered routes,
// // 1GB per 40,000, up to 10GB. This tends to use ~70% of the memory
// // provisioned when testing.
// const prerenderedRouteCount = Object.keys(
// usePrerenderManifest()?.routes ?? {}
// ).length;
// const insertFn = new Function(`${name}RevalidationTableSeeder`, {
// description: "Next.js revalidation data insert",
// handler: "index.handler",
// bundle: dynamodbProviderPath,
// runtime: "nodejs18.x",
// timeout: 900,
// memorySize: Math.min(
// 10240,
// Math.max(128, Math.ceil(prerenderedRouteCount / 4000) * 128)
// ),
// policies: [
// {
// name: "dynamodb",
// policy: table.arn.apply((arn) =>
// aws.iam
// .getPolicyDocument({
// statements: [
// {
// actions: [
// "dynamodb:BatchWriteItem",
// "dynamodb:PutItem",
// "dynamodb:DescribeTable",
// ],
// resources: [arn],
// },
// ],
// })
// .then((doc) => doc.json)
// ),
// },
// ],
// environment: {
// CACHE_DYNAMO_TABLE: table.name,
// },
// }, {parent});
// new aws.lambda.Invocation(`${name}RevalidationTableSeed`, {
// functionName: insertFn.aws.function.name,
// triggers: {
// version: Date.now().toString(),
// },
// input: JSON.stringify({}),
// }, {parent});
//}
return all([experimental, outputPath]).apply(
([experimental, outputPath]) => {
if (!serverFunction) return;
if (experimental.disableDynamoDBCache) return;

const table = new aws.dynamodb.Table(
`${name}RevalidationTable`,
{
attributes: [
{ name: "tag", type: "S" },
{ name: "path", type: "S" },
{ name: "revalidatedAt", type: "N" },
],
hashKey: "tag",
rangeKey: "path",
pointInTimeRecovery: {
enabled: true,
},
billingMode: "PAY_PER_REQUEST",
globalSecondaryIndexes: [
{
name: "revalidate",
hashKey: "path",
rangeKey: "revalidatedAt",
projectionType: "ALL",
},
],
},
{ parent }
);

const dynamodbProviderPath = path.join(
outputPath,
".open-next",
"dynamodb-provider"
);
if (fs.existsSync(dynamodbProviderPath)) {
// Provision 128MB of memory for every 4,000 prerendered routes,
// 1GB per 40,000, up to 10GB. This tends to use ~70% of the memory
// provisioned when testing.
const prerenderedRouteCount = Object.keys(
usePrerenderManifest()?.routes ?? {}
).length;
const seedFn = new Function(
`${name}RevalidationSeeder`,
{
description: "Next.js revalidation data seeder",
handler: "index.handler",
bundle: dynamodbProviderPath,
runtime: "nodejs18.x",
timeout: "900 seconds",
memory: `${Math.min(
10240,
Math.max(128, Math.ceil(prerenderedRouteCount / 4000) * 128)
)} MB`,
policies: [
{
name: "dynamodb",
policy: table.arn.apply((arn) =>
aws.iam
.getPolicyDocument({
statements: [
{
actions: [
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:DescribeTable",
],
resources: [arn],
},
],
})
.then((doc) => doc.json)
),
},
],
environment: {
CACHE_DYNAMO_TABLE: table.name,
},
},
{ parent }
);
new aws.lambda.Invocation(
`${name}RevalidationSeed`,
{
functionName: seedFn.nodes.function.name,
triggers: {
version: Date.now().toString(),
},
input: JSON.stringify({}),
},
{ parent }
);
}
return table;
}
);
}

function removeSourcemaps() {
Expand Down

0 comments on commit 361d867

Please sign in to comment.