Serverless Consulting

Static Webapps Are a Smart Choice?

You Decide!

Static Webapps Are a Smart Choice?

By
Mahdi Ridho
November 4, 2022

Overview

I was using angular v2 and I needed a third party service for prerendering to perform SEO, as they were SPA. In that time, I saw that my PWA (Google Polymer v1) could be indexed properly by Google without any additional prerendering service. So I never used it anymore; till now.

I still don't understand why people should have to choose between SSR or static to serve their Webapp. People say SSR will boost your page load and help your SEO part, but I feel like I disagree with that or maybe I don't get the full point of the SSR advantages. Most of my projects are static Webapps. Google analytics can retrieve the pages easily and I can route to the specific page directly. I don't see how Static Webapps can be considered slow. I might even go as far as saying SSR is expensive. See this comparison:

With SSR :

  • I had to setup the server (I even needed load balancer for multiple Webapps in one instance)
  • My first experience with SSR on EC2: I had to remove the cache files regularly to manage the storage (as possible I didn't activate the autoscale)
  • Ineffective storage for just Webapp files (I have my Webapps avg >100MB)

With Static Hosting :

  • Just need to build version and deploy them to static hosting (I am using AWS S3)
  • They will be just 1 - 2MBs output sizes
  • No managed servers anymore (Serverless)

So here we go, let me share how easy it is to build a static Webapp with Sonic Way (Serverless)! If you have another sonic way, I would love to hear it!

The MVP of this contains :

  • Restricted static hosting with S3 + Cloudfront OAI
  • Webapp dummy, find the sample here
  • Build generator (I am falling in love with Rollup)
  • Service worker for caching management (I am following PWA Builder + Rollup)
  • Google tools (Analytics and Webmaster)

Static Hosting

Let me start this part with a link: Restricting access to Amazon S3 content by using an origin access identity (OAI)

It's so easy to deploy  static hosting with AWS. What we need is an S3 bucket which we will then set as static hosting. But relying on the s3 features alone is not secure enough to serve our public site. Serving an S3 behind a CDN as like Cloudfront will help boost our static Webapp securely.

Cloudfront has some scenarios that allows us to restrict our public static hosting. The preferred way can be found in the link I mentioned above. The short concept is that, we will restrict our public s3 bucket (as static hosting) behind Cloudfront with trusted identity, so no one has direct access to that S3 bucket and will get their access denied.

Just follow the  link above to create a restricted static s3 bucket. Now, say we  already have static hosting with a pre-served index.html that contains: "Hello www.mysite.com"

The basic design of www.mysite.com hosting will look like this :

Static Hosting Architecture

We can see that the S3 static hosting is publicly served. But no one has direct access unless the request is coming from a trusted identity which is a Cloudfront Origin Access Identity. It makes sure our public Webapp is secured.

We are allowed to point our verified domain name to the CDN Link and use Custom SSL with AWS Certificate Manager as well. For this dummy, I didn't set any custom domain nor custom SSL (Default CDN + SSL)

Bundler

What I do next is usually my favorite part, minify and bundle the Webapp files. It is to reduce the file size and mangle the code. So finally, we can save a lot of storage and have the more encapsulated code. I have experience with many bundler tools and Rollup is the best tool for my current use cases. You can use any preferred bundler tool such as Webpack, parcel, fuse, snowpack, esbuild, etc.

Well, how do I utilize the Rollup in a basic case? Let's start cloning the dummy files here. Just follow the “readme” to see how you can serve it locally and start building.

Let's do a short dive into the rollup.config.js file:

  • createSpaConfig, let us to build the Webapp as SPA (Single Page App)
  • Once successfully built, it generates several hash files into the output folder like so:
  
0039096c.js  3b101b7f.js  6c3533a0.js  7fee9d66.js  images      sw.js      workbox-80efdfd1.js
2beb7425.js  444eb09e.js  7015d3eb.js  d3eba316.js  index.html  sw.js.map  workbox-80efdfd1.js.map
  
  • The output files should be minified and mangled like so:
  
import{L as t,d as e,A as i,P as d,h as l,c as a,E as o,N as n,B as r,n as c,u as s,a as m,s as 
f}from"./444eb09e.js";import{P as p,S as h}from"./3b101b7f.js";const u=t=>e=>"function"==typeof 
e?((t,e)=>(window.customElements.define(t,e),e))(t,e):((t,e)=>{const{kind:i,elements:d}=e;
return{kind:i,elements:d,finisher
...
...

  

Let's see.. how do I get them to have a small size right now since it reduces the Webapp size a lot.

  
pwa-starter-kit$ du -sh --exclude=./build --exclude=./.git
98M     .
pwa-starter-kit$ du -sh build/
588K    build/
  
  • Use injectServiceWorker to activate the service worker
  • Use workbox to have a dynamic worker list from the generated hash files
  • We can call additional plugins and modules with Rollup
  • If you want more, just follow this docs or rollup with more native experiences

To have a more advanced Webapp, I always adjust my rollup config as required and follow the pwabuilder instructions to get it to feel like native

Google knows

Like I said, Google has the ability to discover, crawl, and index our SPA based Webapp on the static hosting nicely. What we need to do is let Google know we have a great Webapp. I just follow some docs or articles to make it up on the google page rank. I am not an SEO expert but you can give it a try my way.

  • Create the Google Analytic and put the generated gtag code into the index.html file; for example:
  
<script async src="https://www.googletagmanager.com/gtag/js?id=GA-ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'GA-ID');
</script>
  
  • Add a listener method to the root app file that will invoke the Google Analytic every time the app route/link is changed, something like this :
  
// before or after navigate to the new route/link, call this method
gaMeasure(link) {
  gtag('config', 'GA-ID', {'page_path': link});
}
  
  • Setup the sitemap to let Google up-to-date to our site links periodically. I will create a new property on the Google Webmaster Console, verify my property, and then Build & Submit a Sitemap to Google Webmaster.
  • Last but not least, regularly update the contents to boost the page rank organically

Most of my projects are using these approachs absolutely. I don't have any specific goal for the google page rank, but it's good enough if google knows about our Website, right?

Deploy

Time to deploy our bundled Webapp to the s3 hosting. You can use many things to push the Webapp files into S3 with AWS CLI, SDK, or manually upload them from the AWS Console. I would create a bash script that is running AWS CLI to synchronize my local Webapp system to s3. For example:

  
aws --profile <creds_profile> --region <region> s3 sync . s3://<bucket_name> --delete 
--exclude <exclude_files> --sse AES256 --cache-control no-cache
  

On the repo, I also provided a small bash script for advanced users and medium up project scale, I would recommend implementing CI/CD on the development. I am doing it a lot and find it very useful.

Conclusion

I came from the frontend role with little experience in server based applications. I did apache or nginx Web services and wrote PHP scripts for the backend to make my live sites, but that's an old story. I got to know the serverless microservices that have saved my life a lot.

  • Static Webapp with implemented PWA, I just demonstrated a feels-like native hybrid apps (in basic). And Google Play Store now open for Progressive Web Apps
  • I don't need to be stressed with managing a server
  • Developing a large project with small teams, why not?
  • It gives me many chances to keep up my lazy style

So… any comments? Find me on LinkedIn to have virtual-coffee, see ya on my next blog!

Bonus

As, I have become more familiar with rollup, I notice that I can’t stop sharing my exciting journeys using it.

Well, here is my latest case regarding cache issues on a browser. On previous approaches we had rollup already manage the cache with service worker dynamically by hash. But sometimes it failed on the end-user level where they were stuck with an old Webapp version. They had to force refresh the browser to make it up-to-date with the latest Webapp version. Or the worst scenario, they had to clear the browser caches. That’s not good, right?

So the question is “How do we make our static Webapp auto-update the latest version immediately when they have changes?”

I made another repository to give us another knowledge of the case. Let’s open the rollup config file how it looks like now! 

  • We now disable these native features
  
injectServiceWorker: false,
workbox: false
  
  • Replace them with another third party library 
  
import { injectManifest } from 'rollup-plugin-workbox';
  
  • And we now have ability to define which files should be dynamic hashing when found new updates
  
injectManifest({
  swSrc: 'pwabuilder-sw.js',
  swDest: outputDir +'/pwabuilder-sw.js',
  globPatterns: ['index.html','*.js','config.json','images/**/*.{ico,png,jpg,gif}'],
  globDirectory: outputDir +'/',
  maximumFileSizeToCacheInBytes: 4 * 1024 * 1024
})
  

Also we can find other new thing as like pwa-builder for initial worker library. With this line (on index.html) tells the end-users when there is an update available.

  
<script type="module" src="./pwabuilder-sw-register.js"></script>
  

So on the browser will popup a button when the service worker found new hash caches

From my experiences, we’re able to remove those popup feature as the registered pwabuilder worker already updated the caches immediately when users load the Webapp

  
navigator.serviceWorker.register("/pwabuilder-sw.js")
  

But with this popup feature will give more user knowledges to our Webapp right? Also, let the user know when your PWA is ready to use offline.

So do you have any interesting stories of Webapp development with AWS Serverless? I would love to have chats with you!