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.

Revisions

  1. nadnoslen revised this gist Feb 7, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Gruntfile.js
    Original file line number Diff line number Diff line change
    @@ -54,7 +54,7 @@ module.exports = function (grunt) {
    src: ["assets/**"],
    dest: "foo-folder"
    }]
    },
    },l
    upload_staging_index: {
    options: {
    bucket: "staging.example.com",
    @@ -140,7 +140,7 @@ module.exports = function (grunt) {
    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.");
    grunt.fail.fatal("AWS credentials are required to upload the assets to S3. Please run `grunt registerAWSCredentials:yourAccessKeyIdValue:yourSecretAccesssKeyValue` to create the .aws/config.json file.");
    }
    var tasks = isOptimize ? ["optimize"] : [];
    grunt.task.run(
  2. nadnoslen revised this gist Feb 7, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion ember-cli-build.js
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@ module.exports = function (defaults) {
    outputPaths: {
    app: {
    css: {
    'app': '/assets/tdc.css'
    'app': '/assets/foo.css'
    }
    }
    }
  3. nadnoslen revised this gist Feb 7, 2016. 1 changed file with 26 additions and 0 deletions.
    26 changes: 26 additions & 0 deletions .gitignore
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,26 @@
    # See http://help.github.com/ignore-files/ for more about ignoring files.

    # compiled output
    /dist
    /tmp

    # dependencies
    /node_modules
    /bower_components

    # misc
    /.sass-cache
    /connect.lock
    /coverage/*
    /libpeerconnection.log
    npm-debug.log
    testem.log

    # Jetbrains
    /.idea

    # Grunt
    /.grunt

    # AWS
    /.aws
  4. nadnoslen revised this gist Feb 7, 2016. 2 changed files with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion ember-cli-build.js
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ module.exports = function (defaults) {
    var app = new EmberApp(defaults, {
    fingerprint: {
    extensions: ['js', 'css', 'png', 'jpg', 'gif', 'svg', 'pdf'],
    prepend: "//cdn.example.com/foo/"
    prepend: "//cdn.example.com/foo-folder/"
    },
    outputPaths: {
    app: {
    File renamed without changes.
  5. nadnoslen revised this gist Feb 7, 2016. 3 changed files with 102 additions and 60 deletions.
    66 changes: 6 additions & 60 deletions Gruntfile.js
    Original file line number Diff line number Diff line change
    @@ -27,45 +27,6 @@ module.exports = function (grunt) {
    }
    },
    // -------------------------------------------------------------------------------------------------------------
    // 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: {
    @@ -82,7 +43,7 @@ module.exports = function (grunt) {
    },
    upload_assets: {
    options: {
    bucket: "luxus-s3",
    bucket: "foo-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
    },
    @@ -91,12 +52,12 @@ module.exports = function (grunt) {
    expand: true,
    cwd: "dist",
    src: ["assets/**"],
    dest: "tdc"
    dest: "foo-folder"
    }]
    },
    upload_staging_index: {
    options: {
    bucket: "staging.poderepanico.com",
    bucket: "staging.example.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: {
    @@ -107,7 +68,6 @@ module.exports = function (grunt) {
    files: [{
    action: "upload",
    src: "dist/index.html",
    //dest: "index." + new Date().toISOString() + ".html"
    dest: "index.html"
    }, {
    action: "upload",
    @@ -119,7 +79,7 @@ module.exports = function (grunt) {
    },
    upload_production_index: {
    options: {
    bucket: "poderepanico.com",
    bucket: "example.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: {
    @@ -143,22 +103,19 @@ module.exports = function (grunt) {
    // example: grunt aws_s3:delete_assets --deleteDest=1.0.0
    delete_assets: {
    options: {
    bucket: "luxus-s3"
    bucket: "foo-s3"
    },
    files: [{
    action: "delete",
    dest: "tdc"
    dest: "foo-folder"
    }]
    }
    // 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.");
    @@ -194,17 +151,6 @@ module.exports = function (grunt) {
    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.
    49 changes: 49 additions & 0 deletions ember-cli-build.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,49 @@
    /*jshint node:true*/
    /* global require, module */
    var EmberApp = require('ember-cli/lib/broccoli/ember-app');

    module.exports = function (defaults) {
    var app = new EmberApp(defaults, {
    fingerprint: {
    extensions: ['js', 'css', 'png', 'jpg', 'gif', 'svg', 'pdf'],
    prepend: "//cdn.example.com/foo/"
    },
    outputPaths: {
    app: {
    css: {
    'app': '/assets/tdc.css'
    }
    }
    }
    });

    // Use `app.import` to add additional libraries to the generated
    // output files.
    //
    // If you need to use different assets in different
    // environments, specify an object as the first parameter. That
    // object's keys should be the environment name and the values
    // should be the asset to use in that environment.
    //
    // If the library that you are including contains AMD or ES6
    // modules that you would like to import into your application
    // please specify an object with the list of modules as keys
    // along with the exports of each module as its value.
    app.import(app.bowerDirectory + "/bootstrap/fonts/glyphicons-halflings-regular.eot", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/bootstrap/fonts/glyphicons-halflings-regular.svg", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/bootstrap/fonts/glyphicons-halflings-regular.ttf", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/bootstrap/fonts/glyphicons-halflings-regular.woff", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/bootstrap/fonts/glyphicons-halflings-regular.woff2", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + '/bootstrap/dist/js/bootstrap.js');
    app.import(app.bowerDirectory + "/font-awesome/fonts/FontAwesome.otf", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/font-awesome/fonts/fontawesome-webfont.eot", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/font-awesome/fonts/fontawesome-webfont.svg", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/font-awesome/fonts/fontawesome-webfont.ttf", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/font-awesome/fonts/fontawesome-webfont.woff", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + "/font-awesome/fonts/fontawesome-webfont.woff2", {destDir: "assets/fonts"});
    app.import(app.bowerDirectory + '/keyevent/src/keyevent.js');
    app.import(app.bowerDirectory + '/moment/moment.js');
    app.import(app.bowerDirectory + '/numbro/dist/numbro.min.js');

    return app.toTree();
    };
    47 changes: 47 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    {
    "name": "foo",
    "version": "0.0.0",
    "description": "Small description for foo goes here",
    "private": true,
    "directories": {
    "doc": "doc",
    "test": "tests"
    },
    "scripts": {
    "build": "ember build",
    "start": "ember server",
    "test": "ember test"
    },
    "repository": "",
    "engines": {
    "node": ">= 0.10.0"
    },
    "author": "",
    "license": "MIT",
    "devDependencies": {
    "broccoli-asset-rev": "^2.2.0",
    "ember-cli": "1.13.13",
    "ember-cli-app-version": "^1.0.0",
    "ember-cli-babel": "^5.1.5",
    "ember-cli-content-security-policy": "0.4.0",
    "ember-cli-dependency-checker": "^1.1.0",
    "ember-cli-htmlbars": "^1.0.1",
    "ember-cli-htmlbars-inline-precompile": "^0.3.1",
    "ember-cli-ic-ajax": "0.2.4",
    "ember-cli-inject-live-reload": "^1.3.1",
    "ember-cli-less": "^1.5.3",
    "ember-cli-qunit": "^1.0.4",
    "ember-cli-release": "0.2.8",
    "ember-cli-sri": "^1.2.0",
    "ember-cli-uglify": "^1.2.0",
    "ember-data": "2.2.0",
    "ember-disable-proxy-controllers": "^1.0.1",
    "ember-export-application-global": "^1.0.4",
    "grunt": "^0.4.5",
    "grunt-aws-s3": "^0.14.4",
    "grunt-contrib-imagemin": "^1.0.0",
    "grunt-exec": "^0.4.6",
    "grunt-image-resize": "^1.0.0",
    "matchdep": "^1.0.0"
    }
    }
  6. nadnoslen created this gist Feb 7, 2016.
    272 changes: 272 additions & 0 deletions Gruntfile.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,272 @@
    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));
    }
    };