<?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: Adham El Banhawy</title>
    <description>The latest articles on DEV Community by Adham El Banhawy (@adham_benhawy).</description>
    <link>https://dev.to/adham_benhawy</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%2F144135%2F45737bc1-7c55-444d-9a23-f7eb20e8f8bd.jpg</url>
      <title>DEV Community: Adham El Banhawy</title>
      <link>https://dev.to/adham_benhawy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adham_benhawy"/>
    <language>en</language>
    <item>
      <title>How to Preserve SPA route path in the browser using AWS CloudFront</title>
      <dc:creator>Adham El Banhawy</dc:creator>
      <pubDate>Sun, 07 Aug 2022 13:33:50 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-to-preserve-spa-route-path-in-the-browser-using-aws-cloudfront-oai</link>
      <guid>https://dev.to/aws-builders/how-to-preserve-spa-route-path-in-the-browser-using-aws-cloudfront-oai</guid>
      <description>&lt;p&gt;The other day I noticed a very irritating behavior on my personal website that I built using Angular. When I type in my domain name in the browser URL bar&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45j5wx7x9pn025ciblmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45j5wx7x9pn025ciblmt.png" alt="website url in browser url bar" width="209" height="31"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I get redirected to &lt;code&gt;elbanhawy.com/home&lt;/code&gt; and can see my website homepage load. That's not the annoying behavior, that the expected part. What I found out by accident was that if I tried to reload that page or enter a specific path on my website like &lt;code&gt;elbanhawy.com/blog&lt;/code&gt; I get an Access Denied response from AWS!&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq5ofbqekxmx8b276cs5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feq5ofbqekxmx8b276cs5.png" alt="Access Denied Page from S3" width="800" height="241"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's happening here??&lt;/p&gt;

&lt;p&gt;This might be a common shocker to anyone who's never deployed an SPA like React, Vue, and Angular on AWS S3 and CloudFront before so let's see how I tackled this issue.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Debugging Checklist
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Checking S3 bucket policies and the CF Origins and OAI configurations
&lt;/h3&gt;

&lt;p&gt;My angular site is hosted on an S3 bucket which is not public. My CloudFront distribution serves the S3 bucket content, so my S3 bucket policies should explicitly allow my CloudFront distribution to access all content inside the bucket. Let's take a look:&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;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2008-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PolicyForCloudFrontPrivateContent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"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;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&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;"AWS"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E3LLNG3QXXXXX"&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;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-angular-website/*"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bucket policy above explicitly allows my CloudFront OAI that I have associated with my CloudFront distribution to access/get all the objects inside the S3 bucket. I take note of that OAI ID E3LLNG3QXXXXX which I will need later.&lt;br&gt;
I double check in my CloudFront distribution Origins tab to see if my S3 bucket is listed as an origin.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3xxt8xih1v6idz231l2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3xxt8xih1v6idz231l2.png" alt="List of origins in CLoudFront console" width="800" height="121"&gt;&lt;/a&gt;&lt;br&gt;
I see that it is so I choose it and click "Edit" to see its configuration details:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhl5dbosl47sx32b56fg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhl5dbosl47sx32b56fg.png" alt="My S3 origin Edit configurations" width="800" height="502"&gt;&lt;/a&gt;&lt;br&gt;
I make sure that under S3 bucket access section that the "Yes use OAI" option is selected. &lt;/p&gt;

&lt;p&gt;Now I take note of the OAI name selected above. I go to CloudFront's console (CF/Security/Origin access identities) to see my listed OAIs. Remember that OAI ID I took note of from the S3 bucket policy? Now I need to make sure that it is present in the list.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylhoqwzdqvh2el96t7i9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fylhoqwzdqvh2el96t7i9.png" alt="List of Origin access identities in CloudFront console" width="800" height="272"&gt;&lt;/a&gt;&lt;br&gt;
I see that it is so I can safely assume that the CloudFront distribution that serves my website has correct access to my S3 bucket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Okay…So what else can be wrong??&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Solution
&lt;/h2&gt;

&lt;p&gt;At this point I'm scratching my head and trying to read countless AWS docs for hints without success. But then I spot an interesting tab in my CloudFront's distribution page.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupzmrqggozc8ghmdmykb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fupzmrqggozc8ghmdmykb.png" alt="Error pages tab in CloudFront console" width="800" height="155"&gt;&lt;/a&gt;&lt;br&gt;
Come to think of it, when I enter my root domain I didn't get any errors initially. It is only when I reload or include a specific route in my URL that I get an Access Denied error, which translates to a &lt;strong&gt;403&lt;/strong&gt; error code.&lt;/p&gt;

&lt;p&gt;So I decide to click "Create custom error response" and add an entry:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jzqr4i0uvy4smb1kh19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jzqr4i0uvy4smb1kh19.png" alt="Creating a custom error response in CloudFront console" width="800" height="687"&gt;&lt;/a&gt;&lt;br&gt;
I choose &lt;strong&gt;403:Forbidden&lt;/strong&gt; from the list of error codes, then select "Yes" to Customize error response and then, and this is the critical part, I enter "/index.html" as the &lt;strong&gt;Response page path&lt;/strong&gt; and 200: OK as the &lt;strong&gt;HTTP Response code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now if I enter my blog path URL in the browser and hit enter I get served the correct page without any Access Denied error even when I reload the page!&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3udiela7vv7pr4a1dst4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3udiela7vv7pr4a1dst4.png" alt="My blog page loading correctly" width="800" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: if you have more than one CloudFront distribution for your S3 website, you need to these steps for each one. For example, I had a separate distribution for my &lt;code&gt;www&lt;/code&gt; subdomain and had to apply the solution there as well as the distribution for the root domain (&lt;code&gt;elbanhawy.com&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Reflection
&lt;/h2&gt;

&lt;p&gt;I've solved the problem but what's still missing is a clear explanation of why this Access Denied error showed up in the first place.&lt;/p&gt;

&lt;p&gt;Well this can be attributed to the way S3 buckets behave in response to requests. S3 does not understand routes. An S3 bucket is like a server that is expecting a path to a specific file stored in it. For example, I can be more explicit and add &lt;code&gt;/index.html&lt;/code&gt; at the end of my domain url and I would still get the homepage. S3 understands this because it looks for a file called &lt;code&gt;index.html&lt;/code&gt; in the bucket and returns it.&lt;/p&gt;

&lt;p&gt;Originally, when I typed in my domain url &lt;code&gt;elbanhawy.com&lt;/code&gt; , because of my configurations, CloudFront automatically appended &lt;code&gt;/index.html&lt;/code&gt; to the request it forwarded to the S3 bucket which S3 understood and return my index.html file which had links to my compiled angular code. When loaded in the browser, the angular application takes over and the angular router takes effect.&lt;/p&gt;

&lt;p&gt;However, when I reloaded the page or type the route in my url, CloudFront forwarded the request to S3 as-is and S3 tries to find a literal match for a file with the same route name. For example, when I tried &lt;code&gt;elbanhawy.com/blog&lt;/code&gt; before the fix, S3 tried to look for a file called &lt;code&gt;blog&lt;/code&gt; which does not exist so it returns an error. Since I have not originally specified how errors should be handled by CloudFront, an Access Denied error was returned to the browser.&lt;/p&gt;

&lt;p&gt;The solution above, changed that default error behavior to always return the &lt;code&gt;index.html&lt;/code&gt; file whenever that error occurs and therefor the angular site is always returned and the angular router still gets access to the route in the URL and is able to show me the correct page.&lt;/p&gt;

&lt;p&gt;For more tips and insights on cloud and web development follow me on Twitter &lt;a href="https://twitter.com/adham_benhawy" rel="noopener noreferrer"&gt;@adham_benhawy&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudfront</category>
      <category>angular</category>
      <category>react</category>
    </item>
    <item>
      <title>My New Year’s Programming Resolution #2022</title>
      <dc:creator>Adham El Banhawy</dc:creator>
      <pubDate>Fri, 04 Feb 2022 17:00:05 +0000</pubDate>
      <link>https://dev.to/adham_benhawy/my-new-years-programming-resolution-2022-3n97</link>
      <guid>https://dev.to/adham_benhawy/my-new-years-programming-resolution-2022-3n97</guid>
      <description>&lt;p&gt;It’s that time of the year again! Actually I’m late to this and the time should have been at the start of January, but it’s better late than never!&lt;/p&gt;

&lt;h2&gt;
  
  
  2021 Reflections:
&lt;/h2&gt;

&lt;p&gt;It’s funny I have to write this down again because I just did so formally with my manager at work as part of the yearly evaluation. Suffice to say that went well!&lt;/p&gt;

&lt;p&gt;Informally speaking now, 2021 was a great year for me. I just spent 1 whole year working as a cloud developer at IBM and it has been everything I had hoped for and more. I was able to hone my existing skills, pickup and master new ones, and make friends along the way.&lt;/p&gt;

&lt;p&gt;I achieved almost all of my goals from last years’ programming resolution and more. Those include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Earn a AWS cloud certificate&lt;/em&gt; - I sat my first AWS exam and earned the Developer Associate&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Become proficient using kubernetes&lt;/em&gt; - luckily I got assigned a project at work where I deal with kubernetes a lot to deploy application. I went from 0 to a very capable kubernetes user in a span of a few months.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Do more side projects &amp;amp; update my portfolio&lt;/em&gt; - I managed to complete one freelance project for a small car wash business using React and Firebase. I do need to “update my portfolio” though to showcase that.&lt;/li&gt;
&lt;li&gt;Walk my dogs more often - Happy to report I walked my good boi &amp;amp; girl a lot more this year 🐕‍🦺&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had initially planned to earn an Azure cloud certificate as well, but I decided against it since I don’t really use it at work or personally anymore, unlike AWS which is my to-go cloud platform. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;New Year’s Resolution for 2022:&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Following last year’s good progress, I think I have good momentum to achieve even more goals.&lt;/p&gt;

&lt;p&gt;Here is my list for 2022:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Earn TWO AWS cloud certificates&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write technical blogs more frequently&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Launch a simple SaaS webapp on AWS&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are ambitious goals for me taking into account the huge amounts of time each of these tasks can take. Nevertheless, I will try my best to get it done and come out a more experienced developer by the end of the year.&lt;/p&gt;

&lt;p&gt;Here’s to the pursuit of success and error free deployments 🥂🤞&lt;/p&gt;

</description>
      <category>newyearsresolution</category>
      <category>developerproductivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Backup Squarespace-Managed Styles using AWS Cloud</title>
      <dc:creator>Adham El Banhawy</dc:creator>
      <pubDate>Tue, 15 Jun 2021 07:59:13 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-to-backup-squarespace-managed-styles-using-aws-cloud-160c</link>
      <guid>https://dev.to/aws-builders/how-to-backup-squarespace-managed-styles-using-aws-cloud-160c</guid>
      <description>&lt;p&gt;A while ago, I was doing side gig for a client who had website hosted on Squarespace. They asked me to implement an advanced design for a page that wasn't possible with the site's current DIY tools. &lt;/p&gt;

&lt;p&gt;For an experienced, and battle-tested web developer like me that was a simple task, despite never working with website making tools before. All I had to do is write my custom CSS, and javascript and inject them in the site, while keeping Squarespace developer documentation open for reference.&lt;/p&gt;

&lt;p&gt;However, despite my experience, I ran into a problem that brought me to my knees and made me doubt myself as a developer (oh hi imposter syndrome! Long time no see!). This is the story of how I encountered that problem, how I debugged it, and finally how I fixed it using AWS cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Did the Site's Styles Go??
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6obzvnvagnvvusgrdbtf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6obzvnvagnvvusgrdbtf.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I remember just changing the margin of class in the site's CSS editor using a variable. When I clicked save on the styles editor in the admin site, I saw the live preview just blank out. I opened the live site in a new tab, and I was greeted with a broken website on all routes. &lt;/p&gt;

&lt;p&gt;Weird...that simple change shouldn't have broken the site. Maybe their styles editor doesn't support variables? I deleted the CSS variable I created and used normal pixels. Site still broken. Console shows no error.&lt;/p&gt;

&lt;p&gt;Fine! I removed all my custom CSS from the styles editor. Same problem. At this point I start panicking. How did I break the site?? Why is the website refusing to load ANY styles?&lt;/p&gt;

&lt;p&gt;Wait. I just asked the right question. Why isn't the site &lt;strong&gt;loading&lt;/strong&gt; my styles? I realized I didn't know if all my custom and Squarespace CSS  were embedded into the HTML or if they were delivered over the network. I inspected the HTML for any linked stylesheets, and found a suspect in the header called &lt;em&gt;site.css&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5v3uk19fs0j0o6zjokeb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5v3uk19fs0j0o6zjokeb.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I confirmed the culprit when I switched to the Network tab to see if the request to this particular CSS file was successful. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglgyhxs1oct7e59072sg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglgyhxs1oct7e59072sg.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It wasn't. It was returning a 5XX error. In the screenshot I manually blocked the request to replicate the issue so the status is different from the original, but the effect is the same: our site is requesting the main stylesheet from Squarespace and that request was failing which broke the site's styling.&lt;/p&gt;

&lt;p&gt;Phew! I stopped panicking and regained my confidence. This wasn't my mistake, it was Squarespace's.&lt;/p&gt;

&lt;p&gt;To confirm, I looked up and visited Squarespace's status page. Indeed, their status page indicated that they were experiencing some problems on their servers that, among other things, caused styles not to load for many users.  Nothing more I could do. I just waited until the issue was resolved.&lt;/p&gt;

&lt;p&gt;It took 15 &lt;strong&gt;minutes&lt;/strong&gt; for Squarespace  to fix the problem. I thought maybe this was rare issue, and I got lucky it happened at a very late hour past midnight. I was so wrong...&lt;/p&gt;

&lt;h2&gt;
  
  
  We Needed a Solution
&lt;/h2&gt;

&lt;p&gt;A few days later, my client tried and failed to reach me to alert me that the site was, you guessed it, BROKEN.  By the time we got in touch later that day, I found out that the same issue happened again,. And it happened in the middle of the day for a longer period close to &lt;strong&gt;30 minutes.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;T&lt;/strong&gt;he client understandably freaked out and deleted all custom CSS (thankfully I had a local copy), and prayed for the best (while probably thinking I broke their website and vanished). &lt;/p&gt;

&lt;p&gt;In hindsight, I should have communicated better and informed them of that problem when I first faced it. It wasn't Squarespace's mistake this time (although it totally was), it was mine for not coming up with a solution when I encountered it.&lt;/p&gt;

&lt;p&gt;The problem here, as I see it, is that our stylesheets are hosted on a server that's not under our control. How do I remove that external dependency from the website?&lt;/p&gt;

&lt;p&gt;To answer that question I looked to the cloud...&lt;/p&gt;

&lt;h2&gt;
  
  
  My Initial AWS Solution
&lt;/h2&gt;

&lt;p&gt;In my original development, I would put my custom CSS code in  Squarespace's custom CSS editor. The site editor accepted SASS, so I wrote my styles in SASS, and always stored a copy on a local git folder I have on my machine to have some sort of versioning.&lt;/p&gt;

&lt;p&gt;As I mentioned before, the stylesheets are hosted on Squarespace's servers, so I needed my own hassle-free way to host these stylesheets. So I came up with the following solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn83ukzhv9umkqd6q8qc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn83ukzhv9umkqd6q8qc.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In this scenario, I, the website developer, would write my code on Squarespace's custom CSS editor, then copy/paste the SASS to my local machine. The following flow would then take place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I push my code to CodeCommit&lt;/li&gt;
&lt;li&gt;A Lambda function would get triggered by the push event&lt;/li&gt;
&lt;li&gt;The Lambda function would pull the latest SASS file, and convert it to a CSS stylesheet.&lt;/li&gt;
&lt;li&gt;The Lambda function would store the CSS stylesheet in a publicly available S3 bucket&lt;/li&gt;
&lt;li&gt;A custom inline script on the website would check if the expected stylesheet from Squarespace is loaded. If it's not, it requests the fallback stylesheet from the S3 bucket and injects it into the page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so I implemented this solution as quickly as I can before the site breaks again. The very next day, the new flow was set up and working as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring CodeCommit Trigger:
&lt;/h3&gt;

&lt;p&gt;After I pushed the code to my CodeCommit repository, I went to repository's Settings, then to the Triggers tab, and clicked "Create trigger" button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqypsakfoha46o6owvhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqypsakfoha46o6owvhj.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I named the trigger, selected the "Push to existing branch" as the event type, and master as my branch to listen on. Then I selected AWS Lambda as the service to use, and pointed to my Lambda function, then created the trigger.  This Lambda now runs right after any code is pushed to the master branch on CodeCommit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Logic
&lt;/h3&gt;

&lt;p&gt;Here's the JS code for the invoked lambda:&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;S3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;CodeCommit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;aws-sdk&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;sass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;node-sass&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;getFileFromCodeCommit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ccClient&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;CodeCommit&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us-east-1&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;ccParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;repositoryName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mebbels-assets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;ccClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ccParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;stringData&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;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&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="nx"&gt;fileContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stringData&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sendStylesheetToS3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s3Client&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;S3&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-south-1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;putObjectBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mebbels-assets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ACL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public-read&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ContentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;s3Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;putObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;putObjectBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&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="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;processSASS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&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="nx"&gt;sass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileData&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&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="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="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&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="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sassFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getFileFromCodeCommit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mebbels-sass.scss&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;processedSass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;processSASS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sassFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendStylesheetToS3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;processedSass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fallbackStyles.css&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Done&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;return&lt;/span&gt; &lt;span class="nx"&gt;response&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;In short, it pulls the SASS stylesheet (mebbels-sass.scss), converts it to CSS using node-sass package, and then puts the output CSS file to a public S3 bucket.&lt;/p&gt;

&lt;p&gt;Of course, for this lambda to run without issues related to accessing our resources on CodeCommit and S3 it needs the right permissions.&lt;/p&gt;

&lt;p&gt;Here's IAM Role policy attached to the function:&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;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VisualEditor0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&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="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"codecommit:GitPull"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObjectAcl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"codecommit:GetFile"&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;"Resource"&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="s2"&gt;"arn:aws:s3:::*/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::mebbels-assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:codecommit:us-east-1:6653912857032:mebbels-assets"&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="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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuring the S3 Bucket:
&lt;/h3&gt;

&lt;p&gt;The target S3 bucket that will store the fallback CSS stylsheets needs to be public. I made sure it was so during bucket creation, and double checked in the "Permissions" tab of my S3 bucket in the Block public access section:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewc17z90tpq08hiyunhb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewc17z90tpq08hiyunhb.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The bucket also needs to have &lt;a href="https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/cors.html" rel="noopener noreferrer"&gt;CORS enabled&lt;/a&gt; and setup, because we're going to request it from a different domain, namely mebbels.com.&lt;/p&gt;

&lt;p&gt;On the same "Permissions" tab, under the Cross-origin resource sharing (CORS) section, I added the following CORS configuration:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AllowedHeaders"&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="s2"&gt;"Authorization"&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;"AllowedMethods"&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="s2"&gt;"GET"&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;"AllowedOrigins"&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="s2"&gt;"https://www.mebbels.com"&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;"ExposeHeaders"&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;"MaxAgeSeconds"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&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="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Site Script
&lt;/h2&gt;

&lt;p&gt;And finally, here's the little inline script at the site's header that checks for the loaded state of the stylesheet requested from Squarespace. If it's not loaded after 20 milliseconds, then the script injects link into our site's header to our hosted fallback style in our S3 bucket.&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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;isSiteCssLoaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;siteCssLink&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;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link[href*='/site.css']&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;siteCssLink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;load&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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.css loaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;isSiteCssLoaded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&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;fallBackIfNeeded&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;isSiteCssLoaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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.css not loaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;headID&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;getElementsByTagName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;link&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="s1"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;link&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://mebbels-assets.s3.eu-south-1.amazonaws.com/fallbackStyles.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="nx"&gt;headID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fallback styles loaded&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;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fallBackIfNeeded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How to Test this Solution
&lt;/h2&gt;

&lt;p&gt;Obviously, I can't wait for Squarespace's servers to mess up again to test my solution. Here's how I test it.&lt;/p&gt;

&lt;p&gt;As I hinted at the beginning of the article, I can simulate a failed request to fetch our site's stylesheet from Squarespace  by going to the browser's Network tab (making sure I disable the cache to avoid cached stylesheets), and then blocking CSS request's url:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwj60u8vlp6m88wt9ahph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwj60u8vlp6m88wt9ahph.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;After clicking "Block request URL", and refreshing the page, we should see my script kicking in after 20 milliseconds, printing out "site.css not loaded" and "fallback styles loaded" in the console, and adding our fallback stylesheet from S3. And the site should work without breaking!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawbtbbl5l19kkn834mhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawbtbbl5l19kkn834mhx.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  A Better Solution
&lt;/h2&gt;

&lt;p&gt;Honestly, I was kind of proud of this quick solution and seeing it work was a joy. It's a cheap and serverless option that's not too complicated.&lt;/p&gt;

&lt;p&gt;But this solution &lt;em&gt;is&lt;/em&gt; more complicated than it needs to be. And it's not without its caveats. &lt;/p&gt;

&lt;p&gt;The downside of this solution is that the fallback style is still dependent on the website developer to keep the fallback styles in the CodeCommit repository up to date at all times. Also, since there are other site admin users (like the designers) who sometimes edit the site custom styles themselves,  this solution is reliant on perfect communication between team members to let the developer with AWS access know of custom changes so he/she can update the repository.&lt;/p&gt;

&lt;p&gt;As I was reading more about AWS services available for use, I came across an awesome service called CloudWatch Events. This service allows you to trigger workflows in your AWS account based on monitored metrics OR on a scheduled basis.&lt;/p&gt;

&lt;p&gt;So I decided to use CloudWatch Events as serverless cronjob that triggers a Lambda function that scrapes our website's stylesheet on a daily basis, and stores it in the S3 bucket.&lt;/p&gt;

&lt;p&gt;The modified solution now looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtz9xswmiru5m9wg3n43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frtz9xswmiru5m9wg3n43.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In this modified flow, we removed the dependency on the website developer to manually update the stylesheet and push to CodeCommit for the fallback styles to be created.&lt;/p&gt;

&lt;p&gt;In this case, we have a daily scheduled CloudWatch Event that triggers our a Lambda function.&lt;/p&gt;

&lt;p&gt;Our Lambda function then scrapes our website for externally linked stylesheets, merges them into one fallback CSS file, and stores it in the publicly available S3 bucket. The website script stays the same as it check for default stylesheet and requests it from our S3 bucket if not found. &lt;/p&gt;

&lt;h3&gt;
  
  
  Lambda Code:
&lt;/h3&gt;

&lt;p&gt;Let's start with the new lambda function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;botocore.exceptions&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt;

&lt;span class="n"&gt;s3_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;fallback_css_filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fallbackStyles.css&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;fallback_css_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/tmp/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fallback_css_filename&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://www.mebbels.com&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# request the initial page
&lt;/span&gt;    &lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;html.parser&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;fallback_styles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fallback_css_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ab&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text/css&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# get links to external style sheets
&lt;/span&gt;        &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;href&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# the address of the stylesheet
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="c1"&gt;# relative link
&lt;/span&gt;            &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;
        &lt;span class="n"&gt;css_file_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlretrieve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# make a request to download the stylesheet from the address, returns bytes
&lt;/span&gt;        &lt;span class="n"&gt;css&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;css_file_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fallback_styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="n"&gt;css&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;s3_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;fallback_css_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mebbels-assets&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;fallback_css_filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ExtraArgs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ACL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;public-read&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ContentType&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text/css&lt;/span&gt;&lt;span class="sh"&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;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;ClientError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this lambda, I use the BeautifulSoup library to web scrape our website, and download every single externally linked stylesheet and write them to a file in the temporary folder (AWS Lambdas allows you to store files temporarily in a folder called 'tmp' during runtime).&lt;/p&gt;

&lt;p&gt;After writing all the styles to a single fallbackStyles.css file, I upload that to our S3 bucket using the AWS SDK just like before.&lt;/p&gt;

&lt;p&gt;But unlike before, I now backup ANY externally linked stylesheet, so I could back up an externally linked Google fonts stylesheet or or Bootstrap CSS CDN for example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Scheduled CloudWatch Events
&lt;/h2&gt;

&lt;p&gt;This was a new service for me that I was very excited to try out in a practical use case like this. It's incredible how amazingly simple and easy to use with only 2 steps.&lt;/p&gt;

&lt;p&gt;In the AWS console, under CLoudWatch &amp;gt; Events &amp;gt; Rules, I created a new rule and defined my settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7aqk3pr29j3uri9mr79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7aqk3pr29j3uri9mr79.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;In the Event Source section , I chose the "Schedule" option and chose a period of 6 hours. That means this event will be triggered automatically and consistently every six hours. There is even an option for a custom cron expression if you want a very specific custom interval.&lt;/p&gt;

&lt;p&gt;But what does this event do? We need to tell it that in the Targets section. I picked "Lambda function" from the dropdown list and picked my available Lambda function. Then clicked "Configure details" to progress.&lt;/p&gt;

&lt;p&gt;In the next and last step, I just entered the name and description of the event rule I created. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxu1jlbi0ne6kqatx7klk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxu1jlbi0ne6kqatx7klk.png" alt="image"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Thankfully, that screen answered a burning question I had about permissions: "Will this event be allowed to trigger my Lambda function? Or will I have to assign it an IAM role??"&lt;/p&gt;

&lt;p&gt;And, as shown in the screenshot, CloudWatch completely handles assigning the required permission for the event to function on its target, so I didn't have to worry about extra work and testing. &lt;/p&gt;

&lt;h1&gt;
  
  
  Final Words...
&lt;/h1&gt;

&lt;p&gt;I hope this article was useful to you in anyway, weather you're interested in cloud development, website makers, or just programming in general. If you own and manage a Squarespace website (or any website maker) that has mysteriously broken and are reading this in panic mode, I advise you to visit their status page for updates. Outages like these usually get resolved within an hour.&lt;/p&gt;

&lt;p&gt;I am planning to build a cloud native web application to that will implement and automate this solution so I can offer it to my future and existing clients. You can follow me for updates as I build it in public.👨‍💻&lt;/p&gt;

&lt;p&gt;For more tips and insights on cloud and web development follow me on Twitter &lt;a class="mentioned-user" href="https://dev.to/adham_benhawy"&gt;@adham_benhawy&lt;/a&gt; &lt;/p&gt;

</description>
      <category>aws</category>
      <category>squarespace</category>
      <category>cloudwatch</category>
      <category>lambda</category>
    </item>
    <item>
      <title>What are the signs of workaholism?</title>
      <dc:creator>Adham El Banhawy</dc:creator>
      <pubDate>Sat, 03 Aug 2019 19:12:32 +0000</pubDate>
      <link>https://dev.to/adham_benhawy/what-are-the-signs-of-workaholism-o9a</link>
      <guid>https://dev.to/adham_benhawy/what-are-the-signs-of-workaholism-o9a</guid>
      <description>&lt;p&gt;&lt;em&gt;heavy sigh&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I love programing/development/coding. I love my web development job. I love my lifestyle so far. I've been a developer for almost 3 years now.&lt;/p&gt;

&lt;p&gt;Before that, I used to work as a project coordinator for a couple of months and I hated my job. But I remember I almost worked myself to death. I remember one time staying in the company offices till 2 am working on a high stake project all by myself to make it easier for my colleagues working on it the next day. Even though I was well paid and had a great boss, I was miserable and depressed. I think because I tried too hard to like my job by working my ass off. But truth of the matter was that I found the job boring, considered myself expandable, and it just wasn't my jam. &lt;/p&gt;

&lt;p&gt;The career switch I made really did do wonders to fend off that depression.&lt;/p&gt;

&lt;p&gt;Fast-forward to today. I find myself spending most of my free time working on coding side-projects, reading docs, reading tech blogs, trying new dev tools, solving coding challenges, helping others with their coding projects, etc. I am sure many developers can relate to this routine. I still occasionally see and hang out with friends, but I don't seek them out, and I do prefer alone time (I am an introvert).&lt;/p&gt;

&lt;p&gt;But when does this become workaholism? I've burnt out once before, but that was due to high pressure working as a fullstack dev in a small team at a startup and I have recovered. I am just scared I would burn out doing the "free time" dev activities I mentioned above, and that it would cause the same depression I got years ago.&lt;/p&gt;

&lt;p&gt;Does anyone have experience dealing with and avoiding workaholism/burnout?&lt;/p&gt;

</description>
      <category>programing</category>
      <category>career</category>
      <category>psychology</category>
    </item>
  </channel>
</rss>
