Using Grunt, Redis, and S3
- Upload assets (JS, CSS, Images) to S3, drop in CloudFront for CDN distribution.
- Push the raw content of index.html to Redis with a unique deployment key.
- Keep track of all deployment keys in a manifest.
- Load the index.html directly from Rails using the latest deploy to avoid dealing with CORS.
- Go to any specific deploy given a deployment key (easy for previewing deploys, etc.)
While I loved the idea, Luke’s approach using Rake Pipeline didn’t work for me completely since it was still dependent on Ruby. It was also a bit more complicated than what I needed for my workflow.
- Build the app, which is stored in the /dist folder in my case.
- Hash all assets using grunt-hashres.
- Deploy built assets to S3 using grunt-s3. My folder structure looks something like “bucket_name/1401666715802/assets/b478ca4.app.cache.js”
- Prepend the CDN url to all asset references in index.html.
- Store index.html to Redis with the timestamp as key.
- Store the latest deployment key in a list. The user can also specify a maximum manifest size so that he/she can choose to store the latest 10 or 100 deploys. The Redis related tasks uses my fork of the grunt-redis plugin.
See my sample Gruntfile here.
The great thing about Grunt here is that you can pass in options, which can specify build environments. As you can see in the Gruntfile, most tasks have both a “dev” and a “prod” key. For instance, If you pass in “--prod”, it will use production Redis, otherwise it will use local Redis.
On the Rails side, route all requests to an index action, grab the latest deploy from the manifest, and serve out index.html. Since we have a history of all previous deploys stored in Redis, we can simply pass it in as a query param (example.com?deploy_key=123213213) and instantaneously switch to a specific deploy.
See my sample Rails controller here.