Browser Cache Busting on S3 + Cloudfront - caching

I host a static website on S3 + Cloudfront. To redeploy, I upload static files with
aws s3 sync static
and invalidate the cloudfront cache with
aws cloudfront create-invalidation
What is the recommended way to force browsers to get these new assets after I update them? The problem is that browsers are caching these assets and users are getting old (invalid) versions of scripts, images, and styles.

Generally, there are multiple steps you can do to make sure your AWS CloudFront and S3 setup to cache bust upon new deployments.
Make sure you invalidate the cache for index.html (If this is cached)
You can either have query parameters or new file names for static assets such as JavaScript, CSS & etc.
Using New File Names
<!doctype html>
<html lang="en">
<head>
<link href="styles.h2d1f722.css" rel="stylesheet" />
</head>
<body>
<script type="text/javascript" src="scripts.cbe3c974.js"></script>
</body>
</html>
You can generate new file names using your frontend build tool (e.g Webpack, Gulp & etc.)
Using Query Parameters
<!doctype html>
<html lang="en">
<head>
<link href="styles.css?hash=h2d1f722" rel="stylesheet" />
</head>
<body>
<script type="text/javascript" src="scripts.js?hash=cbe3c974"></script>
</body>
</html>
When setting up Query Parameters, make sure you have enabled it in CloudFront (Otherwise the cached response of the file will be returned).
Note: Comparing these two approaches there are pros and cons of each of them. Having same file name, you are able to version the files using S3 native versioning while having new names, it doesn't make much sense to do it since new deployments add new names for the files. Also having new file names, makes the S3 bucket cluttered unless you remove or move the old file to another bucket.
Make sure you have appropriate values Meta tags in the index.html (Cache-Control, Expires, and Pragma Headers).
Using Meta Tags
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
<link href="styles.css?hash=h2d1f722" rel="stylesheet" />
</head>
<body>
<script type="text/javascript" src="scripts.js?hash=cbe3c974"></script>
</body>
</html>
In this example, it instructs not to cache at browser. However, you can setup appropreate values for these.
Practice a versioning scheme for static assets, so that even if an older version of the index.html is served to the end user (Cached from the browser), still the web page loads with old assets (JS, CSS & etc.) without any issues.

You cannot force browsers remote if they already hold the cache values, unless manually intervened.
You need to append
script.something.js?buildid=someuniquereference
and make cloudfront not to cache on query string parameters.
You can also include filename.hash.js or filename.hash.html and with index.html / default document, reduce the time of caching with cache control headers.
This way if you make any changes, you can change that number, cache will be busted on the client as well.
But once you sent the cache headers, there is no way you can clean up the client cache on the browsers remotely.
Hope it helps.

Related

Laravel 5 Angular2 change the default base href

I have an existing working app in Laravel, the client wants to add another features, but this time he wanted to use Angular2 instead of the previous jQuery.
I created new folder inside resources folder using angular-cli tools. The example angular app that created tru angular-cli works fine when running ng serve, that would point to //localhost:3000/ . But I need the default angular base to something like this
myproject.dev/angular
myproject.dev contains the homepage for the Laravel project, so my user module with angular should be in
myproject.dev/angular //dev
www.myproject.com/angular //production
Running
ng build --bh /angular/
Would be successful in
localhost:4200/angular
But would display 404 in
myproject.dev/angular
I created a route
Route::get('/angular/', function () {
return view('welcome');
});
The welcome.blade.php is the
resources/views/welcome.blade.php
I just copy paste the default index.html inside the angular app to the welcome.blade.php
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Angular 2</title>
<base href="/angular/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
Any idea how to make this work?

Laravel 5.3 How does bootstrap interpret and display items without internet

I'm still learning Laravel 5.3 and started studying it a few days ago. One tutorial project I'm following made use of Fontawesome and Bootstrap where bootstrap link and fontawesome link was included within the <head></head> tag.
So I thought that if I disconnect the internet connection, it will fail to display the icons from fontawesome since no library file was downloaded and imported to project. But I was surprised that it still was able to display the fontawesome icons.
That's when I of thought of asking this simple question since I'm a beginner with Laravel and web programming. (Java programmer)
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>#yield('title')</title>
<!-- bootstrap link -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- fontawesome link -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css">
<!-- app.css link -->
<link rel="stylesheet" href="{{ URL::to('css/app.css') }}">
#yield('styles')
</head>
I read something from Laravel 5.3 documentation about the bootstrap directory that stores cached information. Is the caching the reason the fontawesome icons still displays even when it is not connected to the internet?
The Bootstrap Directory
The bootstrap directory contains files that bootstrap the framework
and configure autoloading. This directory also houses a cache
directory which contains framework generated files for performance
optimization such as the route and services cache files.
I'd appreciate any explanation to this so I can better understand how it works.
Your browser has cache too. Do hard refresh / reload - in Chrome you can do this by opening inspector and then right click on refresh button and click what suits you the most.
Describing what is actually going on would be too long for an answer.
Good description what is going on is here.
Google search terms: browser cache, web browser cache
If you use build system (gulp) you will most likely end up with large *.css file which contains bootstrap, font-awesome definitions etc.
More on that is right in documentation.

a href not working with a bare web page

I've been looking around for a solution to the problem I'm having, but it seems that none of the solutions on SO address my issue.
I was having the dreaded issue where the a href tag in my HTML does not actually take me to the link. At first, I tried removing the JavaScript includes, wondering if something in the JavaScript portion was messing up the page.
Then I removed the CSS portion as well, and ultimately removed everything until the page consisted of simply the header information for the HTML page and only the a href tag. I also changed the link to a non-existent page (to force a 404 error).
When clicking on the link, it keeps me on the current page and doesn't take me to the referenced page (or even give me a 404 error). Following is the stripped out code (everything but the commented out portion):
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>test</title>
<meta name="description" content="test1" />
<meta name="keywords" content="test2" />
</head>
<a href="test.html">Support</a/>
</html>
Thanks for the help.
I made the changes based on the answers given but still see the same behavior. As seen in the screenshot (sorry SO doesn't let me insert images), the URL shows /test.html but the page is still the main page. I changed the text of the link to ensure that the changes were applied.
I'm using rackup to quickly view the changes locally.
Screenshot
Updated code:
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>test</title>
<meta name="description" content="test1" />
<meta name="keywords" content="test2" />
</head>
<body>
Support2
</body>
</html>
Working and tested:
NOTE: Both files [ current one and test.html ] are in same directory.
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no" />
<title>test</title>
<meta name="description" content="test1" />
<meta name="keywords" content="test2" />
</head>
<body>
Support
</body>
</html>
Also test code is working fine using target="_blank" in anchor tag , which open link in new page if working fine, like below:
<a href="test.html" target="_blank" > support </a>
You have an extra slash in your closing a tag.
Should be
</a>.
I would also make sure they are in the same directory.
Apparently the answer was here:
How to setup URLs for static site with Ruby Rack on Heroku
Individual pages were being routed to "/" all the time. Needed to modify "config.ru" to get routing to work properly.
Next step is to look into "sinatra".

Application Cache - net::ERR_FAILED

I'm trying to build an offline web form. It only uses jQuery and twitter bootstrap as external resources. I've tried to cache them but when I refresh offline I get net::ERR_FAILED for both jQuery and bootstrap. I'm very new to AppCache so any help is appreciated. Here is my manifest and where I'm including things in my html:
CACHE MANIFEST
../style-bootstrap.css
http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
NETWORK:
*
HTML:
<!DOCTYPE html>
<html lang="en-us" manifest="/includes/pouchcontacts.manifest" type="text/cache-manifest">
<head>
<meta charset="utf-8" />
<title>Contacts [OFFLINE]</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="style-bootstrap.css">
</head>

Respond.js not working locally - Support for media queries in IE8

I am writing a html page using bootstrap3 template and including the respond.js in that, but when I run it on IE8, it gives me error "Access is denied" in console.
I am using this to make IE8 support media queries. I have tried a lot of things as given on forums, but no luck. Does respond.js works locally or we need to run on a localhost/web server?
Respond.js link - https://github.com/scottjehl/Respond
HTML:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="css/main.css" rel="stylesheet" media="screen">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="js/html5shiv.js"></script>
<script src="js/respond.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<h1>Hello, world!</h1>
<div class="main-cont">
</div>
</div>
<script src="js/jquery-1.10.2.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
</html>
CSS - main.css
.main-cont {background:#2d3a42; height:100px;}
Per the Respond.js Docs...
"Due to security restrictions, some browsers may not allow this script to work on file:// urls (because it uses xmlHttpRequest). Run it on a web server."
Specifically, "Respond.js re-requests the CSS files using Ajax and parses the text response," which is where IE's local security policy is blocking you. Another user elsewhere suggested changing the security settings in IE, but I can't confirm that solution since my copy of IE8 doesn't permit me to change those settings.
Oh, and to save you the trouble, I already tested and confirmed that using ajaxSetup() method in jQuery to set "isLocal" property to "true" won't overcome the local restriction in IE.
I just managed to make respond.js run on IE8 for media queries support , by running on localhost. If simply the html file opened, it does not help.

Resources