Friday, May 13, 2016

AngularJS and Amazon S3 & CloudFront - HTML5 mode and Social Sharing

The Setup
You have a single page AngularJS application hosted on Amazon S3 and CloudFront. You have used one of the two possible configurations, i.e. with or without static website hosting enabled on S3.

Problem
Sharing a link from your website on Facebook, Twitter, Linkedin etc does not work well, because none of them run JavaScript to understand a shared link. This is a huge problem because in a Single Page Application (SPA) you set the page titles and descriptions using JavaScript.

A minor problem is also that your website urls are not pretty and include hashbang symbols i.e. # or #!. Besides not looking nice, URLs with hashbang symbols also do not work well when links are shared on any of the social networks.

Solution
The first part of the solution requires enabling HTML5 mode in the AngularJS application. Once HTML5 mode is enabled your links will change from
http://example.com/#/path   TO  http://example.com/path
Client Side Changes
This part is simple as shown in this gist


Next make sure all the links in your app are correct
1. Change # to / in all hrefs in your app. This should be easily done via find and replace. Find matches for 'href="#' and replace with 'href="/'
2. Make sure any assets included in the apps' index.html have a href starting with /. That is change any href values from "path/to/css/ to "/path/to/css"

Server Side Changes
Now when you open the home page and use the website by clicking around everything should work fine. However, if you copy paste a link directly in the browser you will get a 404. To fix this 404 error we need some server side changes.

 - Development (Grunt)
Quite likely you are using Grunt on your dev machine. First install connect-modrewrite and then add a middleware to the livereload section as shown in this gist.


 - Production (Amazon S3 and CloudFront)
Assuming you do NOT have static website hosting enabled on S3. All you have to do is create couple of Custom Error Responses on CloudFront.



Detect JavaScript Support
We filter out the social networks by providing them with a static HTML page containing all the relevant meta tags, and also a simple JavaScript snippet that redirects JavaScript-capable browsers to the root URL, with the correct route hashed out, so that CloudFront & S3 take you to the application and Angular interprets the route correctly. An example of such a file is shown in this gist.

Now when you share the link "https://example.com/path/index.html" social networks will be able to create nice cards. When a user clicks on this link, they will be redirected to the right place.

Notice that the shared link includes "index.html", we can get rid of that if we enable Static Website Hosting on S3. More on that later...

Refrences
1. https://medium.com/@gigbloc/deep-linking-rich-social-sharing-seo-with-angularjs-and-amazon-s3-82f99cf83cb5#.fl6miptq1
2. http://www.ericluwj.com/2015/11/17/seo-for-angularjs-on-s3.html
3. http://www.ericluwj.com/2015/11/10/angularjs-with-html5-mode-on-s3.html
4. http://stackoverflow.com/questions/24283653/angularjs-html5mode-using-grunt-connect-grunt-0-4-5

Deploy a static web app to AWS Cloudfront and S3

There are two ways to deploy a static web apps to AWS CloudFront and S3.

1. Enable Static Website Hosting on S3. Once this is enabled, you can also setup CloudFront to point to S3 website endpoint. Make sure this is not the standard S3 endpoint. Here, CloudFront is simply caching the static files. All files in S3 will also be accessible without CloudFront.

2. Use CloudFront to point to the standard S3 endpoint. This way you make S3 bucket contents available only to CloudFront. In this scenario CloudFront both caches the files and is also a gatekeeper to all the files.