But when people switch to a custom domain, that folder diappears:
https://domain.com/ → "/".
https://domain.com/some-post → "/some-post".
It should also work on other services that also use the AWS Lambdas, like Netlify Functions.
We should avoid the need for external tools, like the serverless framework. It should work by default.
Nice to have:
It would be really nice if we could provide some easy instructions to upload the Lambda after the deployment, maybe using a simple npm CLI like this or this.
The server.js file generated by npx frontity build should be ready to be uploaded to AWS without requiring any extra modification.
@luisherranz that means that the current server handler, what app.callback() returns, needs to stay the same and we need ti provide an extra export, named handler. Am I presuming correctly? Is that handler export what the serverless providers are using?
Exactly. The default export should be a “req/res” function for NodeJS and other serverless services like Google Cloud or Vercel, and the handler export should be an “event/context” function for serverless services like AWS or Netlify.
I have a question: what is more efficient, having two server instance, calling server() with different options or add the serverless context middleware for the req/res handler as well?
I’m pondering which one it’s more suitable as I think the middleware it’s more straight forward, but adds implicit code, and I am not sure if adding it will pollute the context with data that do not exist.
In order to support the serverless method we need to adjust our server entry point and also define a new method to retrieve the needed default handler and proxy one, just like Netlify and the bunch, expect.
Install aws-serverless-express as part of the core package.
Import the main package and import it inside core/src/server/index.ts
// Make sure the porxy headers are forwarded
app.proxy = true;
// This middleware is from this discussion: https://community.frontity.org/t/deploy-to-aws-lambda/814/19?u=cristian.bote
app.use((ctx, next) => {
ctx.lambdaEvent =
(ctx.headers["x-apigateway-event"] &&
JSON.parse(decodeURIComponent(ctx.headers["x-apigateway-event"]))) ||
{};
ctx.lambdaContext =
(ctx.headers["x-apigateway-context"] &&
JSON.parse(decodeURIComponent(ctx.headers["x-apigateway-context"]))) ||
{};
ctx.env = (ctx.lambdaEvent && ctx.lambdaEvent.stageVariables) || process.env;
// Workaround an inconsistency in APIG. For custom domains, it puts the
// mapping prefix on the url, but non-custom domain requests do not. Fix it by
// changing the path to the proxy param which has the correct value always.
if (ctx.lambdaEvent.pathParameters && ctx.lambdaEvent.pathParameters.proxy) {
const dummyBase = "zz://zz";
const url = new URL(ctx.url, dummyBase);
url.pathname = "/" + ctx.lambdaEvent.pathParameters.proxy;
ctx.url = url.href.replace(dummyBase, "");
}
return next();
});
Define a new method inside core/src/server/index.ts to return the serverless handler and the req/res one as well.
const createServerlessHandlers = (args: ServerOptions) => {
const defaultHandler = server(args);
// This will be the current `server` callback
const serverless = awsServerlessExpress.createServer(defaultHandler);
// This is gonna be the proxy handler for serverless
const handler = (event, context) =>
awsServerlessExpress.proxy(serverless, event, context);
return {
defaultHandler,
handler,
};
};
export default createServerlessHandlers;
Modify the generateImportsTemplate function to handle the special server case in core/src/scripts/utils/entry-points.ts. In order to keep the same functionality for the current
With the above changes made, there aren’t gonna be breaking changes for the regular req/res handler, except the .proxy mode which will forward the proxy headers. Other than that, this should be pretty transparent and not break the current way of working.
Let me know your thoughts on the above. Thank you!
We haven’t done any official Frontity package yet. It is unclear at this time when we will have time to do so, so if you want you can create a package following Cristian’s implementation proposal and publish it in npm to share it with the rest of the community
If you want to go ahead, you can use this thread to share your progress and questions, and we will try to help as much as we can.