<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rafael Franco</title>
    <description>The latest articles on DEV Community by Rafael Franco (@rfoel).</description>
    <link>https://dev.to/rfoel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F234470%2Fced17585-4ade-4543-9c1d-231c4f10bbee.jpeg</url>
      <title>DEV Community: Rafael Franco</title>
      <link>https://dev.to/rfoel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rfoel"/>
    <language>en</language>
    <item>
      <title>Fully vector QR codes with an SVG logo in React (download as scalable SVG)</title>
      <dc:creator>Rafael Franco</dc:creator>
      <pubDate>Mon, 08 Jun 2026 13:22:00 +0000</pubDate>
      <link>https://dev.to/rfoel/fully-vector-qr-codes-with-an-svg-logo-in-react-download-as-scalable-svg-5h1b</link>
      <guid>https://dev.to/rfoel/fully-vector-qr-codes-with-an-svg-logo-in-react-download-as-scalable-svg-5h1b</guid>
      <description>&lt;p&gt;I needed a QR code with a logo in the middle that I could put on a &lt;strong&gt;printed&lt;/strong&gt; poster — which meant it had to stay sharp at any size. That ruled out almost every option I tried:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Canvas-based QR libraries hand you a &lt;strong&gt;raster&lt;/strong&gt; image. Scale it up for print and it blurs.&lt;/li&gt;
&lt;li&gt;The ones that &lt;em&gt;do&lt;/em&gt; output SVG usually treat the logo as a separate raster &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; pasted on top — so even if the code is vector, the logo isn't.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I actually wanted was &lt;strong&gt;one SVG&lt;/strong&gt; where &lt;em&gt;both&lt;/em&gt; the QR modules &lt;strong&gt;and&lt;/strong&gt; the logo are vector paths — so I can drop it in a poster, a PDF, or a print job and it's crisp at any resolution.&lt;/p&gt;

&lt;p&gt;That's what &lt;a href="https://www.npmjs.com/package/react-quick-response" rel="noopener noreferrer"&gt;&lt;strong&gt;react-quick-response&lt;/strong&gt;&lt;/a&gt; does. It renders the QR code as SVG (the encoding is handled by &lt;a href="https://www.nayuki.io/page/qr-code-generator-library" rel="noopener noreferrer"&gt;Project Nayuki's well-known QR Code generator library&lt;/a&gt;, bundled in — no extra runtime dependency), and it lets you pass an &lt;strong&gt;SVG logo as a child&lt;/strong&gt; that stays vector too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fun fact, and the reason for the package name: &lt;strong&gt;QR actually stands for "Quick Response."&lt;/strong&gt; It was invented in 1994 by Denso Wave to track car parts faster than a regular barcode could be scanned — most people never realize the "QR" is a real abbreviation.&lt;/p&gt;

&lt;p&gt;Full disclosure: I'm the author. Here's the part I care about most — keeping everything vector.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-quick-response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  An SVG logo that stays an SVG
&lt;/h2&gt;

&lt;p&gt;Pass any SVG element as a child. It isn't rasterized or pasted on as an image — it's &lt;strong&gt;inlined into the same &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;&lt;/strong&gt; as the QR modules. The component scales it to the largest size that's still scannable for your error-correction level, centers it, and knocks out the modules behind it automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReactQR&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-quick-response&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Logo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./logo.svg?react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// an inline SVG component&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactQR&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://react.dev"&lt;/span&gt; &lt;span class="na"&gt;errorCorrectionLevel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"H"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Logo&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ReactQR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the logo lives in the SVG tree as real paths, there's no resolution to "max out" — it's resolution-independent, exactly like the code around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download it as one scalable SVG
&lt;/h2&gt;

&lt;p&gt;Here's the payoff. The whole thing — modules &lt;em&gt;and&lt;/em&gt; logo — is a single &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; node, so "exporting" is just serializing the DOM. No canvas, no rasterization, no quality loss:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ReactQR&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-quick-response&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Logo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./logo.svg?react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DownloadableQR&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SVGSVGElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;downloadSvg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// The serialized markup includes the QR paths AND the inlined logo —&lt;/span&gt;
    &lt;span class="c1"&gt;// all vectors, infinitely scalable.&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;XMLSerializer&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;serializeToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image/svg+xml;charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;qr-code.svg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactQR&lt;/span&gt;
        &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt;
        &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;errorCorrectionLevel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"H"&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Logo&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;ReactQR&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;downloadSvg&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Download SVG&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open that file in a browser or a vector editor (Figma, Illustrator, Inkscape) and zoom in forever — both the code and the logo are paths. Perfect for print, large-format, or anywhere you don't control the final size.&lt;/p&gt;

&lt;p&gt;Need a PNG too? Draw the same SVG onto a &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; at whatever resolution you want and call &lt;code&gt;toDataURL("image/png")&lt;/code&gt; — but for anything that gets scaled or printed, ship the SVG.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "keep it vector" matters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Print &amp;amp; large format&lt;/strong&gt; — posters, stickers, packaging: a raster QR with a logo gets soft; a vector one doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One file, no compositing&lt;/strong&gt; — the logo isn't a second asset you have to align and embed; it's already part of the SVG.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tiny &amp;amp; editable&lt;/strong&gt; — SVG paths are small and you can restyle colors in the file afterward.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A couple of extras
&lt;/h2&gt;

&lt;p&gt;You also get module shapes (purely visual — same encoded data):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactQR&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt; &lt;span class="na"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"dots"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReactQR&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com"&lt;/span&gt; &lt;span class="na"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"rounded"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…plus the usual &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;margin&lt;/code&gt;, &lt;code&gt;foregroundColor&lt;/code&gt;, &lt;code&gt;backgroundColor&lt;/code&gt;, and error-correction controls. It's TypeScript-typed and SSR-friendly (it's just SVG markup, so it works in Next.js / Remix server rendering).&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;A live playground to tweak size, colors, error correction, shape, and logo — then download the SVG:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎮 &lt;strong&gt;Demo:&lt;/strong&gt; &lt;a href="https://react-quick-response.rfoel.dev" rel="noopener noreferrer"&gt;https://react-quick-response.rfoel.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📦 &lt;strong&gt;npm:&lt;/strong&gt; &lt;a href="https://www.npmjs.com/package/react-quick-response" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/react-quick-response&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/rfoel/react-quick-response" rel="noopener noreferrer"&gt;https://github.com/rfoel/react-quick-response&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you put a vector QR + logo into a real print job with it, I'd love to see it. ⭐ and issues welcome.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Remix com serverless</title>
      <dc:creator>Rafael Franco</dc:creator>
      <pubDate>Sat, 12 Nov 2022 14:26:12 +0000</pubDate>
      <link>https://dev.to/rfoel/remix-com-serverless-3iao</link>
      <guid>https://dev.to/rfoel/remix-com-serverless-3iao</guid>
      <description>&lt;p&gt;Nessa postagem vamos aprender como fazer o deploy de uma aplicação Remix no serverless. Caso só queria ver o código, acesse esse &lt;a href="https://github.com/rfoel/remix-serverless"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://github.com/shamsup/remix-starter-serverless"&gt;shamsup/remix-starter-serverless&lt;/a&gt;, que possui um README muito bem detalhado do processo e é basicamente isso que vamos resumir nessa postagem.&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-remix@latest 
? Where would you like to create your app? remix-serverless
? What &lt;span class="nb"&gt;type &lt;/span&gt;of app &lt;span class="k"&gt;do &lt;/span&gt;you want to create? Just the basics
? Where &lt;span class="k"&gt;do &lt;/span&gt;you want to deploy? Architect &lt;span class="o"&gt;(&lt;/span&gt;AWS Lambda&lt;span class="o"&gt;)&lt;/span&gt;
? TypeScript or JavaScript? TypeScript
? Do you want me to run &lt;span class="sb"&gt;`&lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;? Yes
💿 That&lt;span class="s1"&gt;'s it! `cd` into "/Users/rafael/Developer/remix-serverless" and check the README for development and deploy instructions!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logo de cara podemos apagar alguns arquivos que não vamos utilizar como &lt;code&gt;server.js&lt;/code&gt;, &lt;code&gt;app.arc&lt;/code&gt; e &lt;code&gt;server/config.arc&lt;/code&gt;. Também podemos apagar os scripts &lt;code&gt;dev:arc&lt;/code&gt; e &lt;code&gt;start&lt;/code&gt; do nosso &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev:remix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev:arc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env NODE_ENV=development arc sandbox"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix build &amp;amp;&amp;amp; run-p &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;dev:*&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cross-env NODE_ENV=production arc sandbox"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos instalar as dependências do serverless pra nossa configuração.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;serverless esbuild serverless-esbuild serverless-s3-sync &lt;span class="nt"&gt;-D&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No arquivo &lt;code&gt;remix.config.js&lt;/code&gt;, vamos apagar o campo &lt;code&gt;server&lt;/code&gt; e adicionar um novo chamado &lt;code&gt;serverBuildDirectory&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** @type {import('@remix-run/dev').AppConfig} */&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;serverBuildTarget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ignoredRouteFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/.*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;serverBuildDirectory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;server/build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// appDirectory: "app",&lt;/span&gt;
  &lt;span class="c1"&gt;// assetsBuildDirectory: "public/build",&lt;/span&gt;
  &lt;span class="c1"&gt;// serverBuildPath: "server/index.js",&lt;/span&gt;
  &lt;span class="c1"&gt;// publicPath: "/_static/build/",&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com as dependências instaladas e o arquivo de configuração atualizado, podemos criar dois novos arquivo chamados &lt;code&gt;serverless.yml&lt;/code&gt; onde ficará a configuração da nossa aplicação e &lt;code&gt;server/remix.ts&lt;/code&gt; onde ficará o nosso Lambda handler do Remix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createRequestHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@remix-run/architect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ServerBuild&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@remix-run/node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;ServerBuild&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createRequestHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getLoadContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse arquivo será o handler da nossa Lambda e receberá todas as requisições do cliente.&lt;/p&gt;

&lt;p&gt;Agora vamos ver o arquivo de configuração do serverless.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;remix-serverless&lt;/span&gt;

&lt;span class="na"&gt;frameworkVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3'&lt;/span&gt;

&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-esbuild&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-s3-sync&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs16.x&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:stage, 'dev'}&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:region, 'us-east-1'}&lt;/span&gt;

&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;esbuild&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bundle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;minify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;sourcemap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;sourcesContent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;aws-sdk'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;node16'&lt;/span&gt;
    &lt;span class="na"&gt;platform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;node'&lt;/span&gt;

  &lt;span class="na"&gt;s3Sync&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;buckets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bucketNameKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WebsiteBucketName&lt;/span&gt;
        &lt;span class="na"&gt;bucketPrefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;website/&lt;/span&gt;
        &lt;span class="na"&gt;localDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;

&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;remix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server/remix.handler&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;httpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;any&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/{proxy+}'&lt;/span&gt;

&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;HttpApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::ApiGatewayV2::Api&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HttpApi-${self:service}&lt;/span&gt;
        &lt;span class="na"&gt;ProtocolType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTP&lt;/span&gt;

    &lt;span class="na"&gt;WebsiteBucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::Bucket&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;

    &lt;span class="na"&gt;WebsiteOriginAccessIdentity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::CloudFront::CloudFrontOriginAccessIdentity&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;CloudFrontOriginAccessIdentityConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Comment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Origin Access Identity to Access ${self:service} Website Bucket&lt;/span&gt;

    &lt;span class="na"&gt;WebsiteBucketPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::BucketPolicy&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;WebsiteBucket&lt;/span&gt;
        &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
              &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;s3:GetObject&lt;/span&gt;
              &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="s"&gt;Fn::Join:&lt;/span&gt;
                  &lt;span class="s"&gt;- /&lt;/span&gt;
                  &lt;span class="s"&gt;- - Fn::GetAtt:&lt;/span&gt;
                        &lt;span class="s"&gt;- WebsiteBucket&lt;/span&gt;
                        &lt;span class="s"&gt;- Arn&lt;/span&gt;
                    &lt;span class="s"&gt;- '*'&lt;/span&gt;
              &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;CanonicalUser&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="s"&gt;Fn::GetAtt:&lt;/span&gt;
                    &lt;span class="s"&gt;- WebsiteOriginAccessIdentity&lt;/span&gt;
                    &lt;span class="s"&gt;- S3CanonicalUserId&lt;/span&gt;

    &lt;span class="na"&gt;CDN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::CloudFront::Distribution&lt;/span&gt;
      &lt;span class="na"&gt;DependsOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;WebsiteBucket&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;HttpApi&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;DistributionConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;Origins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DomainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="s"&gt;Fn::GetAtt:&lt;/span&gt;
                  &lt;span class="s"&gt;- WebsiteBucket&lt;/span&gt;
                  &lt;span class="s"&gt;- RegionalDomainName&lt;/span&gt;
              &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;StaticOrigin&lt;/span&gt;
              &lt;span class="na"&gt;S3OriginConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;OriginAccessIdentity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="s"&gt;Fn::Join:&lt;/span&gt;
                    &lt;span class="s"&gt;- /&lt;/span&gt;
                    &lt;span class="s"&gt;- - origin-access-identity&lt;/span&gt;
                      &lt;span class="s"&gt;- cloudfront&lt;/span&gt;
                      &lt;span class="s"&gt;- !Ref WebsiteOriginAccessIdentity&lt;/span&gt;
              &lt;span class="na"&gt;OriginPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/website'&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DomainName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="s"&gt;Fn::Join:&lt;/span&gt;
                  &lt;span class="s"&gt;- ''&lt;/span&gt;
                  &lt;span class="s"&gt;- - Ref&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HttpApi&lt;/span&gt;
                    &lt;span class="s"&gt;- '.execute-api.${self:provider.region}.amazonaws.com'&lt;/span&gt;
              &lt;span class="na"&gt;Id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RemixOrigin&lt;/span&gt;
              &lt;span class="na"&gt;CustomOriginConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;OriginProtocolPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https-only&lt;/span&gt;
                &lt;span class="na"&gt;OriginSSLProtocols&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;TLSv1.2&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
          &lt;span class="na"&gt;DefaultCacheBehavior&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;AllowedMethods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;GET&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;HEAD&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;OPTIONS&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;PUT&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;PATCH&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;POST&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;DELETE&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
            &lt;span class="na"&gt;CachedMethods&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;GET&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;HEAD&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;OPTIONS&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
            &lt;span class="na"&gt;Compress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
            &lt;span class="na"&gt;TargetOriginId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RemixOrigin&lt;/span&gt;
            &lt;span class="na"&gt;ViewerProtocolPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redirect-to-https&lt;/span&gt;
            &lt;span class="na"&gt;ForwardedValues&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;QueryString&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
              &lt;span class="na"&gt;Cookies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;Forward&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;

  &lt;span class="na"&gt;Outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;WebsiteBucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;WebsiteBucket&lt;/span&gt;
    &lt;span class="na"&gt;DistributionID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CDN&lt;/span&gt;
    &lt;span class="na"&gt;WebsiteDomain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;Fn::GetAtt: [CDN, DomainName]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;serverless-s3-sync&lt;/code&gt; para subir esses arquivos diretamente no bucket em todo deploy.&lt;/p&gt;

</description>
      <category>remix</category>
      <category>serverless</category>
      <category>react</category>
    </item>
    <item>
      <title>Next.js com serverless-stack</title>
      <dc:creator>Rafael Franco</dc:creator>
      <pubDate>Sat, 12 Nov 2022 14:22:06 +0000</pubDate>
      <link>https://dev.to/rfoel/nextjs-com-serverless-stack-16p2</link>
      <guid>https://dev.to/rfoel/nextjs-com-serverless-stack-16p2</guid>
      <description>&lt;p&gt;Existem algumas formas de fazer deploy de uma aplicação &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; ou &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; no ambiente da &lt;a href="https://aws.amazon.com/pt/"&gt;AWS&lt;/a&gt; sem custos. Por exemplo, é possível subir uma aplicação &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; pura usando apenas &lt;a href="https://aws.amazon.com/pt/cloudfront/"&gt;CloudFront&lt;/a&gt; e o &lt;a href="https://aws.amazon.com/pt/s3/"&gt;S3&lt;/a&gt;, porém como o &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; existe a opção de usarmos como SSR vamos usar o &lt;a href="https://serverless-stack.com/"&gt;serverless-stack&lt;/a&gt;. Há outras formas de fazer isso como o &lt;a href="https://vercel.com/"&gt;Vercel&lt;/a&gt; (criadores do Next.js), &lt;a href="https://docs.amplify.aws/guides/hosting/nextjs/q/platform/js/"&gt;Amplify&lt;/a&gt; e &lt;a href="https://github.com/serverless-nextjs/serverless-next.js"&gt;Serverless Next.js (sls-next) Component&lt;/a&gt;, mas na minha opinião a abstração que o &lt;a href="https://serverless-stack.com/"&gt;serverless-stack&lt;/a&gt; (ou SST) é a melhor dentre as opções.&lt;/p&gt;

&lt;p&gt;Você pode conferir o código final &lt;a href="https://github.com/rfoel/exemplo-next.js-serverless-stack"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que você vai precisar
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uma conta na &lt;a href="https://aws.amazon.com/pt/"&gt;AWS&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/pt/cli/"&gt;AWS CLI&lt;/a&gt; instalado;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Criando uma aplicação SST
&lt;/h2&gt;

&lt;p&gt;O serverless-stack possuí uma CLI que facilita a criação de uma aplicação inicial, similar com o create-react-app (CRA) do React e create-next-app do Next.js.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-serverless-stack nextjs-app
&lt;span class="nb"&gt;cd &lt;/span&gt;nextjs-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dentro do diretório &lt;code&gt;nextjs-app&lt;/code&gt; você vai ver um arquivo chamado &lt;code&gt;sst.json&lt;/code&gt; com o conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"nextjs-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stacks/index.js"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A propriedade &lt;code&gt;name&lt;/code&gt; é o nome da aplicação, &lt;code&gt;region&lt;/code&gt; é a região que sua aplicação será hospedada e &lt;code&gt;main&lt;/code&gt; é o arquivo principal da sua aplicação SST. Por padrão a região selecionada sempre será &lt;code&gt;us-east-1&lt;/code&gt;, mas é possível trocar por &lt;code&gt;sa-east-1&lt;/code&gt; por exemplo, que são os servidores da AWS em São Paulo.&lt;/p&gt;

&lt;p&gt;No mesmo diretório também haverá uma pasta chamada &lt;code&gt;stacks&lt;/code&gt;, que é onde fica o código que servirá para gerar a infraestrutura da aplicação.&lt;/p&gt;

&lt;p&gt;Para este exemplo, vamos apagar a pasta &lt;code&gt;src&lt;/code&gt; que o SST criou por padrão porque vamos colocar nossa aplicação Next.js em uma pasta com esse mesmo nome.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Criando uma aplicação Next.js
&lt;/h2&gt;

&lt;p&gt;Para criar a aplicação vamos usar o &lt;a href="https://nextjs.org/docs/api-reference/create-next-app"&gt;create-next-app&lt;/a&gt;, que vai gerar uma aplicação do Next.js padrão. Nossa aplicação ficará no diretório &lt;code&gt;src&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-next-app src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para esse exemplo não vamos fazer nenhuma alteração no diretório do Next.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurando Next.js no SST
&lt;/h2&gt;

&lt;p&gt;Agora vamos configurar nossa aplicação Next.js no arquivo &lt;code&gt;stacks/MyStack.js&lt;/code&gt;. Inicialmente esse arquivo vai conter um exemplo de uma configuração de um lambda. Podemos remover essa configuração e colocar a seguinte configuração:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;sst&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@serverless-stack/resources&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;sst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Configuração do Next.js aqui&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;sst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NextjsSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addOutputs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em &lt;code&gt;path&lt;/code&gt; será onde sua aplicação do Next.js está.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subindo a aplicação
&lt;/h2&gt;

&lt;p&gt;Nesse ponto já podemos subir nossa aplicação com o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run deploy &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--stage&lt;/span&gt; prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse comando vai subir a infra da nossa aplicação e mostrar a URL da nossa aplicação. Essa URL será do CloudFront, mas é possível configurar um domínio customizado diretamente no SST, mas isso é conteúdo para outra postagem.&lt;/p&gt;

</description>
      <category>react</category>
      <category>serverless</category>
      <category>serverlessstack</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
