DEV Community

Cover image for Remix com serverless
Rafael Franco
Rafael Franco

Posted on

1

Remix com serverless

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!
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

Agora vamos instalar as dependências do serverless pra nossa configuração.

npm install serverless esbuild serverless-esbuild serverless-s3-sync -D
Enter fullscreen mode Exit fullscreen mode

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/",
}
Enter fullscreen mode Exit fullscreen mode

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 {}
  },
})
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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.

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (1)

Collapse
 
gabrielbioinfo profile image
Gabriel Espindola

Boa Franco! Ficou maneiro demais esse tutorial cara... bora fazer mais :D

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay