The AWS Amplify team recently announced the Amplify Hosting deployment specification. This is a way to deploy applications to AWS Amplify with server side rendering (SSR) support. While there are guides or support for many frameworks including Astro, NextJS and Nuxt I couldn't find one for Remix.
As I'm about to start working on a Shopify app (Shopify provides templates for Remix) and I didn't want to switch infrastructure providers I decided to investigate using how difficult it would be to use Amplify to host a Remix app with SSR.
The first step is to create a build file named amplify.yml which Amplify uses to build the project. I was deploying a new project and Amplify detected the file automatically during the initial deployment. Our build script handles four important tasks:
Runs
npm run buildto build the application. Remix puts the output in into thebuildfolder.Moves and restuctures the
buildfolder output to meet the Amplify hosting specification byReduce the size of our
node-modulesfolder by runningnpm ci --omit devto create anode-modulesthat only includes production dependencies. This is important for larger project as there is a limit on the maximum size of this folder. It also helps reduce cold start times. The folder is moved into thecompute/defaultfolder so the modules are available at runtime.Finally there are two files that we will create shortly that need to be copied into place.
The complete amplify.yml is below:
version: 1baseDirectory: .amplify-hostingfrontend: phases: preBuild: commands: - npm ci build: commands: - npm run build - mv build .amplify-hosting - mv .amplify-hosting/client .amplify-hosting/static - mkdir -p .amplify-hosting/compute - mv .amplify-hosting/server .amplify-hosting/compute/default - npm ci --omit dev - cp package.json .amplify-hosting/compute/default - cp -r node_modules .amplify-hosting/compute/default - cp server.js .amplify-hosting/compute/default - cp deploy-manifest.json .amplify-hosting/deploy-manifest.json artifacts: files: - "**/*" baseDirectory: .amplify-hosting
AWS Amplify will now package and deploy our .amplify-hosting folder.
The deploy-mainfest.json has two main tasks:
Tell Amplify how to route traffic
Tell Amplify how to configure and start the compute resources
This routing should not be confused with rewriting and redirecting traffic. It's purpose is to indicate if traffic should be handled as static or compute. Here I'm using the less than perfect approach that files with a . should be treated as static first and fall back to compute if they don't exist. Everything else should be treated as compute. This means that static files must have a . in the filename.
For the compute configuration I've set the runtime to Node 20 and the project should be started by using node server.js
The full deploly-mainfest.json is:
{ "version": 1, "framework": { "name": "remix", "version": "2.8.1" }, "routes": [{ "path": "/*.*", "target": { "kind": "Static", "cacheControl": "public, max-age=2" }, "fallback": { "kind": "Compute", "src": "default" } }, { "path": "/*", "target": { "kind": "Compute", "src": "default" } }], "computeResources": [{ "name": "default", "runtime": "nodejs20.x", "entrypoint": "server.js" }]}
Finally I need to create a small Javascript file called server.js. This file launches an Express server on port 3000 which listens for requests and passes them to Remix. Remember to add express as a production dependency so this will work.
npm i express --save
The complete server.js is:
import remix from "@remix-run/express";import express from "express";import * as build from "./index.js";const app = express();const port = 3000;app.all( "*", remix.createRequestHandler({ build, }));app.listen(port, () => { console.log(`Example app listening on port ${port}`)})
That's it! You should be able to deploy the project to AWS Amplify and when you go to the URL provided your request will be execute on the server.
Top comments (0)