Last active
July 3, 2023 06:31
Static Next.js serve on s3 with CloudFront
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3' | |
const TTL = 10000 | |
const S3_REGION = '' // Update this with your s3 region | |
const S3_BUCKET_NAME = '' // Update this with your s3 bucket name | |
const S3_FILE_PATH = 'routes-manifest.json' | |
const s3 = new S3Client({ region: S3_REGION }) | |
const s3Params = { | |
Bucket: S3_BUCKET_NAME, | |
Key: S3_FILE_PATH | |
} | |
let jsonFile | |
const pullStream = async body => { | |
const buffers = [] | |
for await (const chunk of body) { | |
buffers.push(Buffer.from(chunk)) | |
} | |
return Buffer.concat(buffers) | |
} | |
const getRoutes = async () => { | |
if (jsonFile) return jsonFile | |
const response = await s3.send(new GetObjectCommand(s3Params)) | |
jsonFile = JSON.parse(await pullStream(response.Body)) | |
setTimeout(() => (jsonFile = undefined), TTL) | |
return jsonFile | |
} | |
const getOriginPath = async clientPath => { | |
const { staticRoutes, dynamicRoutes } = await getRoutes() | |
const staticUserRoute = staticRoutes.find(obj => clientPath.match(obj['regex'])) | |
const dynamicUserRoute = dynamicRoutes.find(obj => clientPath.match(obj['regex'])) | |
let redirectPage | |
let routeParams | |
if (staticUserRoute) { | |
redirectPage = staticUserRoute['page'] | |
} else if (dynamicUserRoute) { | |
routeParams = {} | |
const regex = new RegExp(dynamicUserRoute.namedRegex) | |
const matches = regex.exec(clientPath) | |
for (const key in dynamicUserRoute.routeKeys) { | |
const newKey = key.replace('nxtP', '') | |
routeParams[newKey] = matches.groups[key] | |
} | |
redirectPage = dynamicUserRoute.page | |
for (const param in routeParams) { | |
redirectPage = redirectPage.replace(`[${param}]`, routeParams[param]) | |
} | |
} else { | |
return '/404.html' | |
} | |
return redirectPage.endsWith('/') ? `${redirectPage}index.html` : `${redirectPage}/index.html` | |
} | |
export const handler = async (event, context, callback) => { | |
context.callbackWaitsForEmptyEventLoop = false | |
const request = event.Records[0].cf.request | |
const { uri } = request | |
console.log(`URI: ${uri}`) | |
if (uri.indexOf('.') >= 0 || uri === '/') { | |
request.uri = uri === '/' ? '/index.html' : uri | |
return callback(null, request) | |
} | |
try { | |
request.uri = await getOriginPath(uri) | |
console.log(request.uri) | |
callback(null, request) | |
} catch (err) { | |
console.log(err) | |
callback(null, request) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment