Building A Robust Web Platform on AWS: Using Remix in AWS Lambda
Tags: webdev, aws, remix, lambda
Published: 2023-12-15 14:09:08

In today's deep dive, I'll be unpacking my journey of deploying [Remix](https://remix.run) on AWS, specifically as a Lambda function. 

> For the tech aficionados, dive into the code details in our web platform's repository here: https://github.com/pagemosaic/pagemosaic-web-platform

## Remix Handler

Let's cut through the jargon: Remix is versatile enough to run on various JavaScript runtimes, making it a perfect candidate for AWS Lambda functions.

Here’s the catch: Remix typically nestles within an HTTP server to handle requests. This requires a specialized adapter to interface with various HTTP servers. So, in a Lambda environment (essentially a JavaScript runtime container), we leverage an HTTP server to fetch web pages as responses.

In a turn away from conventional servers like Express, I opted for Remix's native solution – the Remix App Server. However, Lambda's distinct request handling interface necessitated a custom adapter for effective Remix integration.

## Remix Adapter

The Remix library does offer an AWS Lambda adapter. Yet, it's tied to a framework I sidestepped: [AWS Architect](https://www.npmjs.com/package/aws-architect), known for orchestrating Lambda microservices and S3-backed websites. 

So, I extracted the crucial elements from the adapter’s code, creating a bespoke module – the `web-adapter` – in my project.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ml0nfw0w8t383yh704u7.png)

## Remix Web Application

What's next? Developing the web application module itself using Remix. Given my preference for Vite or Rollup for module compilation, Vite was my go-to for bundling the web application.

Here's a twist for Remix web applications: they require dual bundles. One for the client side (sans server-executable code) and another for the server side. 

Thus, the build command for the web application module aligns as `vite build && vite build --ssr`. Peek into the `web-app` module's code in our GitHub repository.

## Bundle All

Now, deploying the server-side bundle on AWS as a Lambda function means integrating it with the custom `web-adapter` module. 

This led to introducing Rollup with a configuration merging dependencies from both modules, resulting in a Lambda-ready JS runtime bundle.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rzmlxxlruk00o99inqu1.png)

The final build command for my web application stands as `vite build && vite build --ssr && NODE_ENV='production' rollup -c rollup.config.mjs`.

But it’s not just about code. I tweaked the Remix directory structure for a streamlined deployment process – separating the server part as a Lambda function and the client part as static files in an S3 bucket.

## Deployment

The next phase involved crafting CDK constructs for Lambda function creation and HTTP endpoint setup for the web application, alongside another construct for deploying the client's static files.

You can unearth these construct codes in the infra module files: `web-app-api.ts`, `system-bucket.ts`, `system-bucket-deployment.ts`. Strategically, these are split into distinct constructs for tailored resource initialization sequences on AWS.

## Entry Point

Finally, I assembled a construct for creating a CloudFront distribution with varied access points for both the web application and static resources. Find this code in `enty-point.ts` in the `infra` module.

That wraps up my Remix utilization saga for our web platform. Keen on taking it for a spin? The launchpad awaits in the readme of our source code repository: https://github.com/pagemosaic/pagemosaic-web-platform.

---

Follow [Alex Pust](https://twitter.com/alex_pustovalov) on Twitter for updates on the Page Mosaic Web Platform development.

---