<?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: Pablo Eliseo</title>
    <description>The latest articles on DEV Community by Pablo Eliseo (@pabloelisseo).</description>
    <link>https://dev.to/pabloelisseo</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1186155%2F03eb2399-89c2-4a30-a8ed-34cfbdeff60b.jpeg</url>
      <title>DEV Community: Pablo Eliseo</title>
      <link>https://dev.to/pabloelisseo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pabloelisseo"/>
    <language>en</language>
    <item>
      <title>Deploying a React + Vite SPA to a Private S3 Bucket with CloudFront and OAC</title>
      <dc:creator>Pablo Eliseo</dc:creator>
      <pubDate>Wed, 19 Feb 2025 14:19:32 +0000</pubDate>
      <link>https://dev.to/one-beyond/deploying-a-react-vite-spa-to-a-private-s3-bucket-with-cloudfront-and-oac-mhh</link>
      <guid>https://dev.to/one-beyond/deploying-a-react-vite-spa-to-a-private-s3-bucket-with-cloudfront-and-oac-mhh</guid>
      <description>&lt;p&gt;Deploying a React + Vite single-page application (SPA) to a private AWS S3 bucket while using CloudFront with Origin Access Control (OAC) requires careful setup, especially to handle client-side routing and asset paths properly. This guide will walk you through the complete process, highlighting critical aspects such as &lt;code&gt;custom_error_response&lt;/code&gt; in CloudFront and the &lt;code&gt;base&lt;/code&gt; config in &lt;code&gt;vite.config.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;1. Understanding How OAC, CloudFront, and S3 Work Together&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is Origin Access Control (OAC)?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;OAC is a mechanism that allows CloudFront to securely access private content stored in an S3 bucket without exposing the bucket to the public internet. It replaces the older Origin Access Identity (OAI) with better security and fine-grained access control.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How CloudFront Works with S3 and OAC&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;S3 Bucket:&lt;/strong&gt; Stores your static site files (HTML, JS, CSS, images, etc.). Since it's private, it cannot be accessed directly via a public URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront Distribution:&lt;/strong&gt; Acts as a content delivery network (CDN), caching and serving requests efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAC:&lt;/strong&gt; Grants CloudFront permission to fetch content from the private S3 bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Error Handling:&lt;/strong&gt; Ensures deep links and client-side routing work properly by redirecting 404 errors for non-existing objects to &lt;code&gt;index.html&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With this setup, users access CloudFront, which in turn retrieves the content from the private S3 bucket, ensuring security and performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;2. Setting Up the S3 Bucket&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Since the S3 bucket is private, it must be configured to allow CloudFront access via OAC.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Terraform Configuration:&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket"&lt;/span&gt; &lt;span class="s2"&gt;"spa_bucket"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"react-vite-app"&lt;/span&gt;
  &lt;span class="nx"&gt;acl&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"private"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_s3_bucket_policy"&lt;/span&gt; &lt;span class="s2"&gt;"bucket_policy"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spa_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jsonencode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;Version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
    &lt;span class="nx"&gt;Statement&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="nx"&gt;Sid&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"AllowCloudFrontAccess"&lt;/span&gt;
        &lt;span class="nx"&gt;Effect&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="nx"&gt;Principal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"cloudfront.amazonaws.com"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;Action&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;
        &lt;span class="nx"&gt;Resource&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${aws_s3_bucket.spa_bucket.arn}/*"&lt;/span&gt;
        &lt;span class="nx"&gt;Condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;StringEquals&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"AWS:SourceArn"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_cloudfront_distribution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spa_distribution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&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;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;h2&gt;
  
  
  &lt;strong&gt;3. Creating a CloudFront Distribution with Custom Error Handling&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A major challenge when deploying an SPA is handling client-side routing. When a user directly visits &lt;code&gt;/dashboard&lt;/code&gt; or &lt;code&gt;/profile&lt;/code&gt;, CloudFront will look for &lt;code&gt;dashboard/index.html&lt;/code&gt; or &lt;code&gt;profile/index.html&lt;/code&gt; in S3, which doesn't exist. To fix this, we use &lt;code&gt;custom_error_response&lt;/code&gt; to serve &lt;code&gt;index.html&lt;/code&gt; whenever CloudFront encounters a 404 error.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why Use &lt;code&gt;custom_error_response&lt;/code&gt;?&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPAs rely on client-side routing.&lt;/strong&gt; The React app should handle the routes, not CloudFront.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prevents 404 errors.&lt;/strong&gt; Instead of returning a 404 from S3, CloudFront serves &lt;code&gt;index.html&lt;/code&gt;, allowing React to handle the routing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Terraform Configuration:&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_cloudfront_distribution"&lt;/span&gt; &lt;span class="s2"&gt;"spa_distribution"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="nx"&gt;origin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;domain_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spa_bucket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket_regional_domain_name&lt;/span&gt;
    &lt;span class="nx"&gt;origin_id&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"spa-s3-origin"&lt;/span&gt;
    &lt;span class="nx"&gt;origin_access_control_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_cloudfront_origin_access_control&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oac&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;default_cache_behavior&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;allowed_methods&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;cached_methods&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"HEAD"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;target_origin_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"spa-s3-origin"&lt;/span&gt;
    &lt;span class="nx"&gt;viewer_protocol_policy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"redirect-to-https"&lt;/span&gt;

    &lt;span class="nx"&gt;forwarded_values&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;query_string&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;forward&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"none"&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="nx"&gt;custom_error_response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;error_code&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;
    &lt;span class="nx"&gt;response_code&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="nx"&gt;response_page_path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/index.html"&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;It is very important here not to use the &lt;code&gt;origin_request_policy_id = "216adef6-5c7f-47e4-b989-5492eafa07d3" # AllViewer - Default ID&lt;/code&gt; as the AllViewer request policy forwards the host to the S3 bucket which will be configured to only accept requests from Cloudfront.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;4. Why Use Vite Instead of Webpack?&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Advantages of Vite&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster Development:&lt;/strong&gt; Vite uses native ES modules, significantly improving development speed compared to Webpack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Performance:&lt;/strong&gt; It only rebuilds changed files instead of bundling everything together.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimized Build Output:&lt;/strong&gt; Vite produces highly optimized static assets, reducing bundle size and improving load times.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For SPAs, especially with React, Vite provides a better developer experience and faster deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;5. When to Use This Approach vs. Other Alternatives&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Use This Approach When:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need a &lt;strong&gt;pure client-side application&lt;/strong&gt; without server-side rendering (SSR).&lt;/li&gt;
&lt;li&gt;You want &lt;strong&gt;cost-effective static hosting&lt;/strong&gt; with high security.&lt;/li&gt;
&lt;li&gt;You want full control over AWS infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Consider Other Options When:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js:&lt;/strong&gt; If you need SSR or static site generation (SSG), Next.js on Vercel or AWS Lambda may be a better choice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gatsby:&lt;/strong&gt; If your site is primarily static content with pre-built pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Amplify:&lt;/strong&gt; If you prefer a managed service that simplifies the deployment process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;6. Configuring Vite for Correct Asset Paths&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why the &lt;code&gt;base&lt;/code&gt; Option in &lt;code&gt;vite.config.js&lt;/code&gt;?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Vite's &lt;code&gt;base&lt;/code&gt; configuration determines how URLs are resolved in the generated output. If not set correctly, assets (JavaScript, CSS, favicon) may try to load from incorrect paths when navigating to deeper routes.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why Use &lt;code&gt;base: '/'&lt;/code&gt;?&lt;/strong&gt;
&lt;/h3&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&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;vite&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;react&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;@vitejs/plugin-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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Ensures all assets use absolute paths from the root&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;outDir&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dist&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;7. Deploying with GitHub Actions&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To automate deployment, we use GitHub Actions to build and upload the React app to the S3 bucket. I am using &lt;a href="https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions#using-secrets-in-a-workflow" rel="noopener noreferrer"&gt;Github Actions Secrets and Variables&lt;/a&gt; for configuring the workflow.&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to S3&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&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;Checkout Code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&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;Set up Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18&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;Install Dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&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;Build Application&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&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;Configure&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4.0.2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;vars.AWS_REGION&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;vars.AWS_ACCOUNT_ID&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}:role/github-actions_role"&lt;/span&gt;
          &lt;span class="na"&gt;role-session-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GitHub-Actions_Publish_Static_Site"&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;Deploy static site to S3 bucket&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws s3 sync ./dist/ s3://${{ vars.AWS_S3_BUCKET_NAME }} --delete --region ${{ vars.AWS_REGION }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, I am configuring the AWS credentials by using a IAM role. See &lt;a href="https://aws.amazon.com/blogs/security/use-iam-roles-to-connect-github-actions-to-actions-in-aws/" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; for more information on the topic.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This guide covered deploying a React + Vite SPA securely on AWS using S3, CloudFront, and OAC. By setting up CloudFront with &lt;code&gt;custom_error_response&lt;/code&gt;, using Vite for efficient builds, and automating deployment with GitHub Actions, you ensure a smooth, performant, and cost-effective solution for hosting your SPA.&lt;br&gt;
You can find the full code (with some more improvements) in this &lt;a href="https://github.com/pabloelisseo/react-vite-s3-cloudfront" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>vite</category>
      <category>s3</category>
      <category>aws</category>
    </item>
    <item>
      <title>The Future is Remote: The Pros, Cons, and Solutions to Working from Home</title>
      <dc:creator>Pablo Eliseo</dc:creator>
      <pubDate>Mon, 16 Oct 2023 10:42:14 +0000</pubDate>
      <link>https://dev.to/one-beyond/the-future-is-remote-the-pros-cons-and-solutions-to-working-from-home-c4k</link>
      <guid>https://dev.to/one-beyond/the-future-is-remote-the-pros-cons-and-solutions-to-working-from-home-c4k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction:
&lt;/h2&gt;

&lt;p&gt;Hi, I am Pablo, a software engineer at One Beyond. Even before I joined this company I worked remotely from several locations, including Maastricht, Berlin and Valladolid, my hometown. &lt;/p&gt;

&lt;p&gt;I enjoyed everything in the first months. The obvious advantages of working from home energized me, but over time, it grew a little more challenging for me. I made the decision to do my own research about remote work at that time because, despite being my first time, a lot of individuals effectively run their businesses in this way. &lt;/p&gt;

&lt;p&gt;A sizeable part of IT company personnel has been working remotely for a while now, so I wanted to ask these colleagues if this is their dream situation. In my opinion, the quality of life can increase tremendously after you know what to expect and how to deal with the drawbacks related to remote working. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GzekP_X4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjas11pm1q5dmk9n6ehd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GzekP_X4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjas11pm1q5dmk9n6ehd.jpg" alt="Person working remotely. Image available at https://unsplash.com/photos/mV4GwTDD8Tw" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, I would like to note that the entire post is based on my experience with remote work. Therefore, it is obvious that it is biased by my personal viewpoint and that it varies from person to person. Some advantages and disadvantages may be more objective than others, though. I do not want to claim to be an authority; I just want to share my opinion about this topic with you. &lt;/p&gt;

&lt;h2&gt;
  
  
  Pros of Working Remotely:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Flexibility: One of the most prized benefits. Work hours should be scheduled around your most productive times or around your personal commitments. I, for example, like to go to the gym first thing in the morning. Then I start working a bit later, but I'm fully awake and productive. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost Savings: Working from home cuts down the daily commute, leading to marked savings on fuel, public transport, and vehicle upkeep. Additionally, preparing meals at home curbs expenses on often-overpriced office dining options. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Work-Life Balance: The flexibility afforded by remote working in the UK makes it considerably easier to juggle work responsibilities with personal obligations, be it spending quality time with family, pursuing hobbies, or attending to household chores without feeling overwhelmed. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_b7lDnZb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvgvufzvswh2mff5hvb5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_b7lDnZb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gvgvufzvswh2mff5hvb5.jpg" alt="Stones balanced. Image available at https://unsplash.com/photos/FO7bKvgETgQ" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Access to a Global Talent Pool: In the UK's evolving business landscape, remote work breaks down geographic barriers, allowing companies to tap into a vast global talent pool, ensuring they're not confined to hiring just within their immediate vicinity or region. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reduced Overhead for Companies: Embracing remote work in the UK context allows businesses to significantly cut costs, as the need for extensive office space, associated utilities, and various on-site resources diminishes, leading to more streamlined operations and increased profitability. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Environmentally Friendly: Within the drive towards sustainability, remote working offers tangible benefits; fewer individuals commuting daily leads to reduced carbon emissions and less traffic congestion, contributing to a greener, cleaner environment and supporting the country's eco-conscious goals. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customized Work Environment: In the modern work landscape, remote employees have the liberty to tailor their workspace to their preferences, fostering a comfortable environment that not only boosts morale but also enhances productivity by catering to individual needs and tastes. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cons of Working Remotely:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Isolation: For employees, the shift to remote work can heighten feelings of loneliness due to diminished face-to-face interactions, potentially impacting well-being and cohesion across various teams and time zones. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TJF1spoA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a3zq3fr7xdkf7t2qu9h4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TJF1spoA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a3zq3fr7xdkf7t2qu9h4.jpg" alt="Man standing in front of a window. Image available at https://unsplash.com/photos/Pv5WeEyxMWU" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Distractions: The home environment introduces unique challenges, where anything from playful dogs to pending domestic chores can divert attention, potentially impeding productivity and focus during working hours. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Overworking: A notable concern arises for many individuals who struggle to "switch off" and delineate professional responsibilities from personal time, lacking the traditional boundaries set by a physical office environment. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Communication Barriers: Navigating the world of global remote employment presents challenges, notably the potential hurdles in ensuring clear and effective communication or collaboration, given the absence of face-to-face interactions and the nuances lost in virtual exchanges. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security Issues: There is an amplified concern surrounding the potential vulnerabilities in safeguarding confidential data, with the absence of controlled office infrastructures potentially compromising information security protocols. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lack of Team Cohesion: The absence of regular face-to-face interactions poses challenges in fostering genuine team chemistry, potentially making it harder to cultivate a sense of unity and shared purpose among diverse team members. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to successfully work from home:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Combat Isolation:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Virtual Social Events: Plan online game evenings, coffee breaks, or team-building activities. In our team, we have a weekly meeting to talk about non-work-related stuff or play a simple online game. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Co-working Spaces: People who miss working in an office setting might spend some time in shared communal workspaces. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Minimize Distractions:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Dedicated Workspace: Create a separate environment for work to help you psychologically distinguish between work and home modes. I usually work from a spare room I set up as my working office. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Time management strategies: These strategies, such as the Pomodoro technique, a time management method where work is broken into intervals, typically 25 minutes long, separated by short breaks, can help you stay focused. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prevent Overworking:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Set Up Clearly Delineated Boundaries: Choose your work's start and end times. It can be helpful to have another activity booked after your finishing time, such as language classes or practicing a sport. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regular Breaks: Be careful and remember to take brief rest periods, most of the time 5 minutes is enough. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Enhance Communication:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Tools &amp;amp; Software: For seamless communication, use collaborative applications like Slack, Zoom, or Microsoft Teams. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To make sure everyone is on the same page, schedule daily or weekly team meetings. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Address Security Concerns:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use encryption and a virtual private network (VPN) to secure data transfer when needed, protecting it from unauthorized interception and ensuring privacy. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regular Training: Inform staff members of the best ways to keep data integrity. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Build Team Cohesion:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;On-site Retreats: Plan quarterly or annual retreats to foster interpersonal relationships. I cannot wait for Christmas dinner! &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tools for Team Collaboration: Sites like Jira or Asana can keep everyone in the loop. A properly organized Jira board can give you all the insight you need to know about what your colleagues are doing. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;Despite working remotely having its share of difficulties, there are many advantages. The proper tactics, resources, and attitude can help you get through such obstacles. &lt;/p&gt;

&lt;p&gt;As remote work becomes more prevalent, adapting and adjusting to this paradigm is not only necessary but also a chance for growth, balance, and profitability. &lt;/p&gt;

&lt;p&gt;Remote work has offered me the luxury of balancing work and life from the comfort of my home, ending long commutes and rigid office hours. But I understand that it could be difficult for some people. Is this virtual work environment something you would thrive in, or would you miss the buzz and camaraderie of a traditional office? Can you stay disciplined and productive without the physical boundaries of a workplace? &lt;/p&gt;

</description>
      <category>remote</category>
      <category>workplace</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
