Remix com serverless
Rafael Franco
Posted on November 12, 2022
Nessa postagem vamos aprender como fazer o deploy de uma aplicação Remix no serverless. Caso só queria ver o código, acesse esse link.
Ao criar uma nova aplicação Remix temos a possibilidade de escolher onde iremos subir nossa aplicação como Remix App Server, Express Server, Architect (AWS Lambda), Fly.io, Netlify, Vercel e Cloudflare Pages. Alguns desses não dão tanta margem pra escolha como Netlify e Vercel e outros requerem uma infraestrutura um pouco mais robusta para rodar como o Express Server. Pessoalmente eu prefiro ter controle total da minha aplicação ao invés de depender do dashboard do Vercel ou Netlify e das restrições que essas plataformas impõe, e mesmo que o Architect seja extremamente parecido com o que vamos aprender aqui, ele também tem suas próprias restrições e uma documentação não tão boa para iniciantes.
Por isso, ao conhecer o framework Remix eu fiquei curioso para saber se funcionaria em um ambiente serverless como o AWS Lambda, tendo total controle no deploy e sobre como a aplicação funciona. Procurando soluções já prontas me deparei com o repositório shamsup/remix-starter-serverless, que possui um README muito bem detalhado do processo e é basicamente isso que vamos resumir nessa postagem.
Para iniciar, podemos criar uma nova aplicação Remix usando o template do Architect (AWS Lambda), que possui uma configuração similar ao que vamos usar aqui.
npx create-remix@latest
? Where would you like to create your app? remix-serverless
? What type of app do you want to create? Just the basics
? Where do you want to deploy? Architect (AWS Lambda)
? TypeScript or JavaScript? TypeScript
? Do you want me to run `npm install`? Yes
💿 That's it! `cd` into "/Users/rafael/Developer/remix-serverless" and check the README for development and deploy instructions!
Logo de cara podemos apagar alguns arquivos que não vamos utilizar como server.js
, app.arc
e server/config.arc
. Também podemos apagar os scripts dev:arc
e start
do nosso package.json
.
"scripts": {
"build": "remix build",
"dev:remix": "remix watch",
"dev:arc": "cross-env NODE_ENV=development arc sandbox",
"dev": "remix build && run-p \"dev:*\"",
"start": "cross-env NODE_ENV=production arc sandbox"
}
Agora vamos instalar as dependências do serverless pra nossa configuração.
npm install serverless esbuild serverless-esbuild serverless-s3-sync -D
No arquivo remix.config.js
, vamos apagar o campo server
e adicionar um novo chamado serverBuildDirectory
.
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
serverBuildTarget: 'arc',
ignoredRouteFiles: ['**/.*'],
server: 'server.js',
serverBuildDirectory: 'server/build',
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "server/index.js",
// publicPath: "/_static/build/",
}
Com as dependências instaladas e o arquivo de configuração atualizado, podemos criar dois novos arquivo chamados serverless.yml
onde ficará a configuração da nossa aplicação e server/remix.ts
onde ficará o nosso Lambda handler do Remix.
import { createRequestHandler } from '@remix-run/architect'
import type { ServerBuild } from '@remix-run/node'
const build = require('./build') as ServerBuild
export const handler = createRequestHandler({
build,
getLoadContext() {
return {}
},
})
Esse arquivo será o handler da nossa Lambda e receberá todas as requisições do cliente.
Agora vamos ver o arquivo de configuração do serverless.
service: remix-serverless
frameworkVersion: '3'
plugins:
- serverless-esbuild
- serverless-s3-sync
provider:
name: aws
runtime: nodejs16.x
stage: ${opt:stage, 'dev'}
region: ${opt:region, 'us-east-1'}
custom:
esbuild:
bundle: true
minify: false
sourcemap: true
sourcesContent: false
exclude: ['aws-sdk']
target: 'node16'
platform: 'node'
s3Sync:
buckets:
- bucketNameKey: WebsiteBucketName
bucketPrefix: website/
localDir: public
functions:
remix:
handler: server/remix.handler
events:
- httpApi:
method: any
path: '/{proxy+}'
resources:
Resources:
HttpApi:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: HttpApi-${self:service}
ProtocolType: HTTP
WebsiteBucket:
Type: AWS::S3::Bucket
Properties: {}
WebsiteOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: Origin Access Identity to Access ${self:service} Website Bucket
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref WebsiteBucket
PolicyDocument:
Statement:
- Effect: Allow
Action:
- s3:GetObject
Resource:
Fn::Join:
- /
- - Fn::GetAtt:
- WebsiteBucket
- Arn
- '*'
Principal:
CanonicalUser:
Fn::GetAtt:
- WebsiteOriginAccessIdentity
- S3CanonicalUserId
CDN:
Type: AWS::CloudFront::Distribution
DependsOn:
- WebsiteBucket
- HttpApi
Properties:
DistributionConfig:
Enabled: true
Origins:
- DomainName:
Fn::GetAtt:
- WebsiteBucket
- RegionalDomainName
Id: StaticOrigin
S3OriginConfig:
OriginAccessIdentity:
Fn::Join:
- /
- - origin-access-identity
- cloudfront
- !Ref WebsiteOriginAccessIdentity
OriginPath: '/website'
- DomainName:
Fn::Join:
- ''
- - Ref: HttpApi
- '.execute-api.${self:provider.region}.amazonaws.com'
Id: RemixOrigin
CustomOriginConfig:
OriginProtocolPolicy: https-only
OriginSSLProtocols: [TLSv1.2]
DefaultCacheBehavior:
AllowedMethods: [GET, HEAD, OPTIONS, PUT, PATCH, POST, DELETE]
CachedMethods: [GET, HEAD, OPTIONS]
Compress: true
TargetOriginId: RemixOrigin
ViewerProtocolPolicy: redirect-to-https
ForwardedValues:
QueryString: true
Cookies:
Forward: none
Outputs:
WebsiteBucketName:
Value:
Ref: WebsiteBucket
DistributionID:
Value:
Ref: CDN
WebsiteDomain:
Value:
Fn::GetAtt: [CDN, DomainName]
Esse é o arquivo de configuração padrão do serverless. Com isso, você terá o mínimo necessário para conseguir subir sua aplicação na AWS.
Alguns pontos interessantes dessa configuração é que além de um Lambda que recebe as requisições, também estamos usando o CloudFront como CDN e o S3 para armazenar nossos arquivos estáticos. Sobre esse último, usamos o plugin serverless-s3-sync
para subir esses arquivos diretamente no bucket em todo deploy.
Posted on November 12, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.