Skip to content

Instantly share code, notes, and snippets.

@nadnoslen
Last active February 7, 2016 00:53
Show Gist options
  • Select an option

  • Save nadnoslen/ab3b638088df3ee82d75 to your computer and use it in GitHub Desktop.

Select an option

Save nadnoslen/ab3b638088df3ee82d75 to your computer and use it in GitHub Desktop.
Ember Hosted On AWS S3
module.exports = function (grunt) {
grunt.initConfig({
// -------------------------------------------------------------------------------------------------------------
// Read the package.json file into a variable
// -------------------------------------------------------------------------------------------------------------
pkg: function () {
grunt.log.verbose.writeln("Loading `package.json` into the pkg variable.");
return grunt.file.readJSON("package.json");
}(),
bld: function () {
grunt.log.verbose.writeln("Loading the `.grunt/build.json` into the bld variable.");
return getBuildJSON();
}(),
aws: function () {
grunt.log.verbose.writeln("Loading the `.aws/config.json` into the aws variable.");
return getAWSConfigJSON();
}(),
// -------------------------------------------------------------------------------------------------------------
// Ember Execution
// -------------------------------------------------------------------------------------------------------------
exec: {
ember_test: {
cmd: "ember test"
},
ember_build: {
cmd: "ember build -prod"
}
},
// -------------------------------------------------------------------------------------------------------------
// Image Processing
// -------------------------------------------------------------------------------------------------------------
imagemin: {
options: {
optimizationLevel: 3
},
optimize: {
options: {
optimizationLevel: 3
},
files: [{
expand: true,
cwd: "public/assets/images",
src: "**/*.{png,jpg,gif}",
dest: "public/assets/images"
}]
},
thumbnails: {
files: [{
expand: true,
cwd: "public/assets/images",
src: "**/thumbnails/*.{png,jpg,gif}",
dest: "public/assets/images"
}]
}
},
image_resize: {
thumbnails: {
options: {
crop: true,
height: 75,
width: 75,
overwrite: true,
concurrency: 4
},
files: []
}
},
// -------------------------------------------------------------------------------------------------------------
// CDN Related (AWS S3 with CloudFront)
// -------------------------------------------------------------------------------------------------------------
aws_s3: {
options: {
accessKeyId: getAWSConfigJSON().AccessKeyId,
secretAccessKey: getAWSConfigJSON().SecretAccessKey,
region: "us-west-2",
uploadConcurrency: 5, // 5 simultaneous uploads
downloadConcurrency: 5, // 5 simultaneous downloads
params: {
CacheControl: "max-age=315360000", // 10 years...we version the files anyway
Expires: new Date(2038, 0, 1, 0, 0, 0, 0) // 20+ years from today but before than http://en.wikipedia.org/wiki/Year_2038_problem#Solutions
}
},
upload_assets: {
options: {
bucket: "luxus-s3",
access: "bucket-owner-full-control", // uploaded files are restricted to the bucket owner only; this fixes issues where assets are available from s3, but they should ALWAYS be sourced from CloudFront
differential: true // Only uploads the files that have changed
},
files: [{
action: "upload",
expand: true,
cwd: "dist",
src: ["assets/**"],
dest: "tdc"
}]
},
upload_staging_index: {
options: {
bucket: "staging.poderepanico.com",
access: "public-read", // uploaded files are restricted to the bucket owner only; this fixes issues where assets are available from s3, but they should ALWAYS be sourced from CloudFront
differential: true,
params: {
CacheControl: "max-age=no-cache", // don't want any caching
Expires: new Date(2015, 0, 1, 0, 0, 0, 0) // always expired
}
},
files: [{
action: "upload",
src: "dist/index.html",
//dest: "index." + new Date().toISOString() + ".html"
dest: "index.html"
}, {
action: "upload",
expand: true,
cwd: "dist",
// DO NOT upload robots.txt because we need to manage that for each of the staging environments separately
src: ["*.{xml,txt}", "!robots.txt"]
}]
},
upload_production_index: {
options: {
bucket: "poderepanico.com",
access: "public-read", // uploaded files are restricted to the bucket owner only; this fixes issues where assets are available from s3, but they should ALWAYS be sourced from CloudFront
differential: false,
params: {
CacheControl: "max-age=no-cache", // don't want any caching
Expires: new Date(2015, 0, 1, 0, 0, 0, 0) // always expired
}
},
files: [{
action: "upload",
src: "dist/index.html",
dest: "index." + new Date().toISOString() + ".html"
}, {
action: "upload",
expand: true,
cwd: "dist",
// DO NOT upload robots.txt because we need to manage that for each of the staging environments separately
src: ["*.{xml,txt}", "!robots.txt"]
}]
},
// USE WITH CAUTION
// example: grunt aws_s3:delete_assets --deleteDest=1.0.0
delete_assets: {
options: {
bucket: "luxus-s3"
},
files: [{
action: "delete",
dest: "tdc"
}]
}
// TODO: could create a delete index
}
});
// dynamically load the grunt tasks
require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);
// has the optimize flag been passed, this is good for running deploy and forcing an optimize
var isOptimize = grunt.option("optimize");
// grab the environment, either --staging or --production or --prod
var isProduction = grunt.option("prod") || grunt.option("production");
grunt.log.ok(isProduction ? "Working in the PRODUCTION environment." : "Working in the staging environment.");
// -------------------------------------------------------------------------------------------------------------
// These tasks marked with an * should instead be specified from within this Gruntfile wherever possible.
// -------------------------------------------------------------------------------------------------------------
grunt.registerTask("setBuildParameter", "Sets the specified build parameter in the .grunt/build.json file (e.g. grunt setBuildParameter:someName:someValue). *", function (name, value) {
if (arguments.length != 2) {
grunt.fail.fatal("`setBuildParameter` expects two arguments: e.g. `grunt setBuildParameter:enableCompression:true`.");
}
var build = grunt.config("bld");
var was = build[name];
build[name] = value;
writeBuildJSON(build);
grunt.log.ok(name + " was '" + was + "' and has now been set to '" + build[name] + "'.");
});
// -------------------------------------------------------------------------------------------------------------
// These tasks deploy the website
// -------------------------------------------------------------------------------------------------------------
grunt.registerTask("default", ["deploy"]);
grunt.registerTask("deploy", "Builds the app and deploys it to AWS S3.", function () {
if (!isAWSConfigPresent()) {
grunt.fail.fatal("AWS credentials are required to upload the assets to the Luxus CDN. Please run `grunt registerAWSCredentials:yourAccessKeyIdValue:yourSecretAccesssKeyValue` to create the .aws/config.json file.");
}
var tasks = isOptimize ? ["optimize"] : [];
grunt.task.run(
tasks.concat([
"exec:ember_test",
"exec:ember_build",
"aws_s3:upload_assets",
isProduction ? "aws_s3:upload_production_index" : "aws_s3:upload_staging_index"
]));
});
grunt.registerTask("optimize", "Optimizes (in-place) all the images found in the public folder.", function () {
grunt.task.run([
"imagemin:optimize"
]);
});
grunt.registerTask("thumbnails", "Re-sizes and minifies prescribed directories of images down to thumbnail images.", function () {
grunt.task.run([
"image_resize:thumbnails",
"imagemin:thumbnails"
]);
});
// -------------------------------------------------------------------------------------------------------------
// Registered Tasks for persisting build configuration changes.
// -------------------------------------------------------------------------------------------------------------
grunt.registerTask("registerAWSCredentials", "Sets your AWS credentials in the local .aws/config.json file.", function (accessKeyId, secretAccessKey) {
if (arguments.length != 2) {
grunt.fail.fatal("You must provide two arguments to task " + this.name + ". e.g. grunt " + this.name + ":yourAccessKeyIdValue:yourSecretAccesssKeyValue")
}
var config = getAWSConfigJSON();
config.AccessKeyId = accessKeyId;
config.SecretAccessKey = secretAccessKey;
writeAWSConfigJSON(config);
grunt.log.ok("Your AWS credentials for access key " + config.AccessKeyId + " have been stored in .aws/config.json.");
});
grunt.registerTask("pkgSettings", "Print the `package.json` settings to the grunt.log.", function () {
grunt.log.writeln("package.json=" + JSON.stringify(grunt.config("pkg")));
});
grunt.registerTask("bldSettings", "Print the `.grunt/build.json` settings to the grunt.log.", function () {
grunt.log.writeln(".grunt/build.json=" + JSON.stringify(grunt.config("bld")));
});
// -------------------------------------------------------------------------------------------------------------
// .grunt/build.json helpers
// -------------------------------------------------------------------------------------------------------------
function getBuildJSON() {
try {
return grunt.file.readJSON(".grunt/build.json");
} catch (e) {
grunt.verbose.writeln("The .grunt/build.json does not exist. Creating the default and returning it.");
var bld = {};
writeBuildJSON(bld);
return bld;
}
}
function writeBuildJSON(json) {
grunt.file.write(".grunt/build.json", JSON.stringify(json));
}
// -------------------------------------------------------------------------------------------------------------
// .aws/config.json helpers
// -------------------------------------------------------------------------------------------------------------
function isAWSConfigPresent() {
return grunt.file.exists(".aws/config.json");
}
function getAWSConfigJSON() {
try {
return grunt.file.readJSON(".aws/config.json");
} catch (e) {
grunt.verbose.writeln("The .aws/config.json does not exist. Returning the default config object.");
return {
AccessKeyId: null,
SecretAccessKey: null
};
}
}
function writeAWSConfigJSON(json) {
grunt.file.write(".aws/config.json", JSON.stringify(json));
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment