├── .gitignore ├── 01-getting-started ├── Gruntfile.js └── package.json ├── 02-grunt-contrib-uglifyjs ├── .gitignore ├── Gruntfile.js ├── README.md ├── dest │ ├── file1.min.js │ ├── file2.min.js │ ├── minified.js │ └── script.1411161327.min.js ├── dest2 │ └── jquery.all.min.js ├── index.html ├── package.json ├── src │ ├── angular.js │ └── jquery.js └── src2 │ ├── jquery-ui.js │ └── jquery.mobile.js ├── 03-grunt-contrib-watch ├── Gruntfile.js ├── README.md ├── dest │ └── script.js ├── index.html ├── package.json ├── server.js └── src │ ├── js │ └── init.js │ └── lib │ ├── jquery.js │ └── jquery.mobile.js ├── 04-grunt-jscs ├── .jscsrc ├── Gruntfile.js ├── README.md └── package.json ├── 06-grunt-contrib-copy ├── .gitignore ├── Gruntfile.js ├── README.md ├── package.json └── src │ └── assets │ └── copyThis.txt ├── 07-grunt-concurrent ├── Gruntfile.js ├── README.md ├── dist │ ├── jquery.js │ ├── jquery.mobile.js │ └── library.js ├── libraries │ ├── jquery.js │ └── jquery.mobile.js ├── package.json ├── server.js └── src │ ├── jquery.js │ └── jquery.mobile.js ├── 08-grunt-usemin ├── .tmp │ └── concat │ │ ├── css │ │ └── styles.css │ │ └── js │ │ └── script.js ├── Gruntfile.js ├── README.md ├── css │ ├── bootstrap.css │ ├── codemirror.css │ └── jquery.sidr.light.css ├── dist │ ├── css │ │ └── styles.7dea81d829f10a1fc486.css │ ├── index.html │ └── js │ │ └── script.459446c51efa85dbade2.js ├── index.html ├── js │ ├── angular.min.js │ ├── bootstrap.min.js │ ├── jquery.js │ └── jquery.superscrollorama.js └── package.json ├── 09-grunt-newer ├── Gruntfile.js ├── README.md ├── dist │ └── js │ │ └── minified.js ├── package.json └── src │ └── js │ ├── app.js │ ├── jquery.js │ └── jquery.superscrollorama.js ├── 10-grunt-bump ├── Gruntfile.js ├── README.md └── package.json ├── 11-load-grunt-tasks ├── .tmp │ └── concat │ │ ├── css │ │ └── styles.css │ │ └── js │ │ └── script.js ├── Gruntfile.js ├── README.md ├── css │ ├── bootstrap.css │ ├── codemirror.css │ └── jquery.sidr.light.css ├── dist │ ├── css │ │ ├── styles.7dea81d829f10a1fc486.7dea81d829f10a1fc486.7dea81d829f10a1fc486.css │ │ ├── styles.7dea81d829f10a1fc486.7dea81d829f10a1fc486.css │ │ └── styles.7dea81d829f10a1fc486.css │ ├── index.html │ └── js │ │ ├── script.459446c51efa85dbade2.459446c51efa85dbade2.459446c51efa85dbade2.js │ │ ├── script.459446c51efa85dbade2.459446c51efa85dbade2.js │ │ └── script.459446c51efa85dbade2.js ├── index.html ├── js │ ├── angular.min.js │ ├── bootstrap.min.js │ ├── jquery.js │ └── jquery.superscrollorama.js └── package.json ├── 12-autoprefixer ├── Gruntfile.js ├── README.md ├── css │ └── sample.css ├── dist │ └── sample.css └── package.json ├── 13-grunt-responsive-images ├── Gruntfile.js ├── README.md ├── dist │ ├── img │ │ ├── grunt-usemin-large.jpg │ │ ├── grunt-usemin-medium.jpg │ │ └── grunt-usemin-small.jpg │ └── index.html ├── package.json └── src │ ├── img │ └── grunt-usemin.jpg │ └── index.html ├── 14-grunt-jsdoc-ng ├── Gruntfile.js ├── README.md ├── docs │ ├── fonts │ │ ├── LICENSE.txt │ │ ├── Ubuntu-Bold.ttf │ │ ├── Ubuntu-BoldItalic.ttf │ │ ├── Ubuntu-Italic.ttf │ │ ├── Ubuntu-Light.ttf │ │ ├── Ubuntu-LightItalic.ttf │ │ ├── Ubuntu-Medium.ttf │ │ ├── Ubuntu-MediumItalic.ttf │ │ ├── Ubuntu-Regular.ttf │ │ ├── UbuntuMono-Bold.ttf │ │ ├── UbuntuMono-BoldItalic.ttf │ │ ├── UbuntuMono-Italic.ttf │ │ ├── UbuntuMono-Regular.ttf │ │ └── fonts.min.css │ ├── index.html │ ├── jsdoc-ng.data.js │ ├── jsdoc-ng.min.css │ ├── jsdoc-ng.min.js │ └── libs │ │ ├── angular.min.js │ │ ├── angular.min.js.map │ │ ├── highlight.min.css │ │ └── highlight.min.js ├── package.json └── src │ └── area.js ├── 15-grunt-remove-logging-calls ├── .gitignore ├── .tmp │ └── concat │ │ ├── css │ │ └── styles.css │ │ └── js │ │ ├── library.js │ │ └── script.js ├── Gruntfile.js ├── README.md ├── css │ ├── bootstrap.css │ ├── codemirror.css │ └── mystyle.css ├── index.html ├── js │ ├── bootstrap.min.js │ ├── jquery.js │ └── myscript.js └── package.json ├── 16-grunt-csscomb ├── .csscomb.json ├── Gruntfile.js ├── README.md ├── css │ ├── style.comb.css │ └── style.css ├── index.html └── package.json ├── 17-grunt-jsonlint ├── Gruntfile.js ├── README.md ├── config │ └── config.json ├── data │ └── cities.json └── package.json ├── 18-grunt-exec ├── Gruntfile.js ├── README.md └── package.json ├── 19-grunt-wiredep ├── .bowerrc ├── Gruntfile.js ├── README.md ├── bower.json ├── index.html └── package.json ├── 20-grunt-contrib-htmlmin ├── .tmp │ └── concat │ │ ├── css │ │ └── minified.css │ │ └── js │ │ └── minified.js ├── Gruntfile.js ├── README.md ├── css │ ├── bootstrap.css │ ├── codemirror.css │ └── custom.css ├── dist │ ├── css │ │ └── minified.c332d3794519c03df143.css │ ├── index.html │ └── js │ │ └── minified.a3ce7f4a36974f74504a.js ├── index.html ├── js │ ├── angular.min.js │ ├── bootstrap.min.js │ └── jquery.js └── package.json ├── 21-time-grunt ├── .tmp │ └── concat │ │ ├── css │ │ └── minified.css │ │ └── js │ │ └── minified.js ├── Gruntfile.js ├── README.md ├── css │ ├── bootstrap.css │ ├── codemirror.css │ └── custom.css ├── dist │ ├── css │ │ ├── minified.c332d3794519c03df143.c332d3794519c03df143.c332d3794519c03df143.c332d3794519c03df143.css │ │ ├── minified.c332d3794519c03df143.c332d3794519c03df143.c332d3794519c03df143.css │ │ ├── minified.c332d3794519c03df143.c332d3794519c03df143.css │ │ └── minified.c332d3794519c03df143.css │ ├── index.html │ └── js │ │ ├── minified.a3ce7f4a36974f74504a.a3ce7f4a36974f74504a.a3ce7f4a36974f74504a.a3ce7f4a36974f74504a.js │ │ ├── minified.a3ce7f4a36974f74504a.a3ce7f4a36974f74504a.a3ce7f4a36974f74504a.js │ │ ├── minified.a3ce7f4a36974f74504a.a3ce7f4a36974f74504a.js │ │ └── minified.a3ce7f4a36974f74504a.js ├── index.html ├── js │ ├── angular.min.js │ ├── bootstrap.min.js │ └── jquery.js └── package.json ├── 22-grunt-image-embed ├── Gruntfile.js ├── README.md ├── css │ ├── bootstrap.css │ ├── codemirror.css │ ├── custom.css │ └── output.css ├── images │ └── grunt-logo.png ├── index.html ├── js │ ├── angular.min.js │ ├── bootstrap.min.js │ └── jquery.js └── package.json ├── 23-grunt-browser-sync ├── Gruntfile.js ├── README.md ├── css │ ├── bootstrap.css │ └── custom.css ├── images │ └── browsersync.jpg ├── index.html └── package.json ├── 24-grunt-contrib-compress ├── Gruntfile.js ├── README.md ├── assets │ ├── css │ │ ├── bootstrap.css │ │ └── custom.css │ ├── images │ │ └── browsersync.jpg │ ├── index.html │ └── js │ │ ├── angular.min.js │ │ ├── bootstrap.min.js │ │ └── jquery.js ├── package.json ├── project.zip └── project │ ├── scripts │ ├── angular.min.js │ ├── bootstrap.min.js │ └── jquery.js │ └── styles │ ├── bootstrap.css │ └── custom.css ├── 25-grunt-purifycss ├── .tmp │ └── concat │ │ ├── css │ │ └── styles.css │ │ └── js │ │ └── script.js ├── Gruntfile.js ├── README.md ├── dest │ └── tmp.css ├── dist │ ├── css │ │ └── styles.f6d10cd6258251eddd11.css │ ├── index.html │ └── js │ │ └── script.3181b8c4ea503e69fddd.js ├── package.json └── src │ ├── css │ ├── bootstrap.css │ └── custom.css │ ├── images │ ├── browsersync.jpg │ └── css.jpg │ ├── index.html │ └── js │ └── jquery.js ├── 26-grunt-open ├── Gruntfile.js ├── README.md ├── package.json └── src │ ├── css │ ├── bootstrap.css │ └── custom.css │ ├── images │ ├── browsersync.jpg │ └── css.jpg │ ├── index.html │ └── js │ └── jquery.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | */node_modules/* 2 | */node_modules/.tmp/* 3 | */bower_components/* -------------------------------------------------------------------------------- /01-getting-started/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | uglify: { 4 | my_target: { 5 | files: { 6 | 'dest/minified.js': ['src/jquery.js', 'src/angular.js'] 7 | } 8 | } 9 | } 10 | }); 11 | 12 | grunt.loadNpmTasks('grunt-contrib-uglify'); 13 | grunt.registerTask('default', ['uglify']); 14 | }; -------------------------------------------------------------------------------- /01-getting-started/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GruntFile", 3 | "version": "0.0.0", 4 | "description": "Getting started with grunt", 5 | "main": "GruntFile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/kanakiyajay/front-end-tab.git" 12 | }, 13 | "keywords": [ 14 | "grunt" 15 | ], 16 | "author": "Jay Kanakiya", 17 | "license": "MIT", 18 | "homepage": "https://grunt-tasks.com/", 19 | "devDependencies": { 20 | "grunt": "0.4.5", 21 | "grunt-contrib-concat": "0.5.0", 22 | "grunt-contrib-uglify": "0.6.0", 23 | "grunt-contrib-cssmin": "0.10.0" 24 | } 25 | } -------------------------------------------------------------------------------- /02-grunt-contrib-uglifyjs/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* -------------------------------------------------------------------------------- /02-grunt-contrib-uglifyjs/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | uglify: { 5 | first_target: { 6 | options: { 7 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + 8 | '<%= grunt.template.today("yyyy-mm-dd") %> */' 9 | }, 10 | files: { 11 | 'dest/script.<%= grunt.template.today("yymmddHHMM") %>.min.js': ['src/jquery.js', 'src2/jquery.mobile.js'] 12 | } 13 | }, 14 | second_target: { 15 | files: { 16 | 'dest2/jquery.all.min.js': ['src/jquery.js', 'src2/jquery.mobile.js', 'src2/jquery-ui.js'] 17 | } 18 | } 19 | } 20 | }); 21 | 22 | grunt.loadNpmTasks('grunt-contrib-uglify'); 23 | grunt.registerTask('default', ['uglify']); 24 | }; -------------------------------------------------------------------------------- /02-grunt-contrib-uglifyjs/README.md: -------------------------------------------------------------------------------- 1 | Grunt contrib uglify is an official plugin in the grunt ecosystem to minify and concat your project's javascript files and integrating it with your build system. 2 | 3 | Here's the most simplest way on how to use it: 4 | 5 | From the command line: 6 | 7 | ## Simple Configuration 8 | 9 | `npm install grunt grunt-contrib-uglify --save-dev` 10 | 11 | This will install grunt as well uglifyjs in your node_modules devDependencies as well as update package.json 12 | 13 | Inside your Gruntfile.js: 14 | 15 | ``` 16 | module.exports = function(grunt) { 17 | grunt.initConfig({ 18 | uglify: { 19 | my_target: { 20 | files: { 21 | 'dest/minified.js': ['src/jquery.js', 'src/angular.js'] 22 | } 23 | } 24 | } 25 | }); 26 | 27 | grunt.loadNpmTasks('grunt-contrib-uglify'); // load the given tasks 28 | grunt.registerTask('default', ['uglify']); // Default grunt tasks maps to grunt 29 | }; 30 | ``` 31 | 32 | From the command line: 33 | 34 | ``` 35 | $ grunt 36 | Running "uglify:my_target" (uglify) task 37 | >> 1 file created. 38 | 39 | Done, without errors 40 | ``` 41 | 42 | The object that we have to look at is this 43 | 44 | ``` 45 | uglify: { 46 | my_target: { 47 | files: { 48 | 'dest/minified.js': ['src/jquery.js', 'src/angular.js'] 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | ## Multiple Folder and files 55 | 56 | You can create multiple 'targets' or major folders while 'files' param should specify what should go inside that folder. 57 | If you have a project configuration such as this 58 | 59 | ``` 60 | . 61 | ├── dest 62 | │   ├── file1.min.js 63 | │   ├── file2.min.js 64 | ├── dest2 65 | │   └── jquery.all.min.js 66 | ├── src 67 | │   ├── angular.js 68 | │   └── jquery.js 69 | └── src2 70 | ├── jquery.mobile.js 71 | └── jquery-ui.js 72 | ``` 73 | You want dest2 is another sub-project where you require all the jquery files minified. 74 | To achive this you need to change your Grunt-file like this: 75 | 76 | ``` 77 | first_target: { 78 | files: { 79 | 'dest/file1.min.js': ['src/jquery.js', 'src2/jquery.mobile.js'], 80 | 'dest/file2.min.js': ['src/jquery.js', 'src/angular.js'] 81 | } 82 | }, 83 | second_target: { 84 | files: { 85 | 'dest2/jquery.all.min.js': ['src/jquery.js', 'src2/jquery.mobile.js', 'src2/jquery-ui.js'] 86 | } 87 | } 88 | ``` 89 | 90 | After running grunt you should see the minified files being generated. 91 | What if you only want one first_target or only *1 sub-project* minified folder being generated ? 92 | 93 | Run : 94 | 95 | `grunt uglify:first_target` 96 | 97 | ## Adding banners 98 | 99 | Generally its good practise to add comments above every minified file to indicate the package name, build information and extra information. 100 | 101 | ``` 102 | grunt.initConfig({ 103 | pkg: grunt.file.readJSON('package.json'), 104 | uglify: { 105 | options: { 106 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + 107 | '<%= grunt.template.today("yyyy-mm-dd") %> */' 108 | } ... 109 | } 110 | }); 111 | ``` 112 | The erb tags that you see refers to grunt template system, the grunt.template.today is a helper function while `<%= pkg.name %>` will map to 'name' in package.json file. 113 | 114 | ## Dynamic filenames 115 | 116 | Caching of files takes place depending upon the filename, so how do we create a new min.js for every build ? 117 | 118 | ``` 119 | first_target: { 120 | files: { 121 | 'dest/script.<%= grunt.template.today('yymmddHHMM') %>.min.js': ['src/jquery.js', 'src2/jquery.mobile.js'] 122 | } 123 | } 124 | ``` 125 | 126 | This will create a minified file with name script.1411161327.min.js with comment 127 | 128 | `/*! grunt-contrib-uglifyjs - v0.0.0 - 2014-11-16 */` 129 | 130 | ## Pattern Matching for multiple files 131 | 132 | Most of the time there are more than 6 sub-projects and more than 60 javascript files in a project. 133 | How do map all of them using minimal grunt code ? 134 | 135 | ``` 136 | first_target: { 137 | files: [ 138 | { src: 'src/common/*js', dest: 'dest/common.js'}, // All the common files 139 | { src: 'src/ui/*js', dest: 'dest/ui.js'} 140 | ] 141 | } 142 | ``` 143 | 144 | [More on globbing patterns](http://gruntjs.com/configuring-tasks#globbing-patterns) 145 | -------------------------------------------------------------------------------- /02-grunt-contrib-uglifyjs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sample Page 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /02-grunt-contrib-uglifyjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grunt-contrib-uglifyjs", 3 | "version": "0.0.0", 4 | "description": "A tutorial on how to use grunt-contrib-uglifyjs", 5 | "keywords": "grunt, gruntjs", 6 | "main": "Gruntfile.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Jay Kanakiya", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "grunt": "^0.4.5", 14 | "grunt-contrib-uglify": "^0.6.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /03-grunt-contrib-watch/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | watch: { 5 | express: { 6 | files: ["src/js/*.js", "index.html"], 7 | tasks: ["uglify:dev", "express:defaults"], 8 | options: { 9 | livereload: true, 10 | spawn: false 11 | } 12 | } 13 | }, 14 | uglify: { 15 | all: { 16 | files: { 17 | 'dest/lib.js': ['src/lib/jquery.js', 'src/lib/jquery.mobile.js'], 18 | 'dest/script.js': ['src/js/init.js'] 19 | } 20 | }, 21 | dev: { 22 | 'dest/script.js': ['src/js/init.js'] 23 | } 24 | }, 25 | express: { 26 | options: { 27 | script: 'server.js', 28 | port: 3000 29 | }, 30 | defaults: {} 31 | } 32 | }); 33 | 34 | grunt.loadNpmTasks('grunt-contrib-watch'); 35 | grunt.loadNpmTasks('grunt-contrib-uglify'); 36 | grunt.loadNpmTasks('grunt-express-server'); 37 | 38 | grunt.registerTask('default', ['express', 'watch']); 39 | 40 | }; -------------------------------------------------------------------------------- /03-grunt-contrib-watch/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog Post](http://grunt-tasks.com/grunt-contrib-watch/ "Grunt Watch") 2 | 3 | grunt contrib watch is an amazing plugin that does one simple thing, run a grunt task whenever a file changes. 4 | This post should get you up and running with grunt-watch as fast as possible with some tips on how to leverage its full potential. 5 | So if your development workflow is like this 6 | 7 | > Editor -> Save -> Restart Server -> Refresh browser -> See Changes -> Repeat. 8 | 9 | It will change to just : 10 | 11 | > Save -> Refresh Browser -> See Changes -> Repeat 12 | 13 | Congratulations, you just eliminated one step. 14 | You can eliminate one step even further: 15 | 16 | > Save -> See Changes -> Repeat* 17 | 18 | This might seem like a small change in time, but overtime the difference this minor workflow change will cause is huge. 19 | 20 | ## Step1: Sample Gruntfile.js 21 | 22 | Lets start with a sample Gruntfile.js :- 23 | 24 | ``` 25 | module.exports = function(grunt) { 26 | grunt.initConfig({ 27 | pkg: grunt.file.readJSON('package.json'), 28 | watch: { 29 | files: ["src/*.js"], 30 | tasks: ["uglify"] 31 | }, 32 | uglify: { 33 | target: { 34 | files: { 35 | 'dest/script.js': ['src/jquery.js', 'src/jquery.mobile.js', 'src/init.js'] 36 | } 37 | } 38 | } 39 | }); 40 | 41 | grunt.loadNpmTasks('grunt-contrib-watch'); 42 | grunt.loadNpmTasks('grunt-contrib-uglify'); 43 | grunt.registerTask('default', ['watch']); 44 | }; 45 | ``` 46 | The grunt configuration will run uglify command whenever any file inside changes. 47 | After running grunt from the command line 48 | 49 | ``` 50 | $ grunt 51 | Running "watch" task 52 | Waiting... 53 | >> File "README.md" changed. 54 | Running "uglify:target" (uglify) task 55 | >> 1 file created. 56 | 57 | Done, without errors. 58 | Completed in 12.352s at Sat Nov 22 2014 10:39:12 GMT+0530 (India Standard Time) - Waiting... 59 | ``` 60 | 61 | ## Step 2: Only watch certain files 62 | 63 | Ideally, we dont want this because it took 12 secs to run the command and it should only be run when the related javascript file changes. 64 | 65 | Just change the files that are being watched: 66 | ``` 67 | watch: { 68 | src: { 69 | files: ["src/js/*.js"], 70 | tasks: ["uglify"] 71 | } 72 | } 73 | 74 | // Also the file configuration 75 | files: { 76 | 'dest/script.js': ['src/lib/jquery.js', 'src/lib/jquery.mobile.js', 'src/js/init.js'] 77 | } 78 | ``` 79 | This will make sure that when js files in src/js/* changes and then run uglify task. 80 | 81 | ``` 82 | $ grunt 83 | Running "watch" task 84 | Waiting... 85 | >> File "src\js\init.js" changed. 86 | Running "uglify:target" (uglify) task 87 | >> 1 file created. 88 | 89 | Done, without errors. 90 | Completed in 12.359s at Sat Nov 22 2014 10:53:34 GMT+0530 (India Standard Time) - Waiting... 91 | ``` 92 | 93 | You can have multiple watch configurations using the same patterns: 94 | 95 | ### Multiple Configurations 96 | 97 | ``` 98 | watch: { 99 | task1: { 100 | files: ["src/js/*.js"], 101 | tasks: ["uglify"] 102 | }, 103 | task2: { 104 | files: ["src/js/*.js"], 105 | tasks: ["jshint"] 106 | } 107 | } 108 | ``` 109 | 110 | ## Live Refresh and Reload using Watch 111 | 112 | > Eliminate the most repititive tasks by using grunt server and live reload. 113 | 114 | It is critical to the `save->change->observe` cycle as fast as possible. Chances are if you are a developer you will be doing this multiple times in a day. Get started with the following template. 115 | 116 | We are going to be using express 4.0 and a very simple app for demonstration. 117 | The express app will run on port 3000 and live reload on port 35729 118 | You will also need another plugin grunt-express-server 119 | 120 | `npm install grunt-express-server --save-dev` 121 | 122 | And here is the grunt file: 123 | ``` 124 | module.exports = function(grunt) { 125 | grunt.initConfig({ 126 | pkg: grunt.file.readJSON('package.json'), 127 | watch: { 128 | express: { 129 | files: ["src/js/*.js", "index.html"], 130 | tasks: ["uglify:dev", "express:defaults"], 131 | options: { 132 | livereload: true, 133 | spawn: false 134 | } 135 | } 136 | }, 137 | uglify: { 138 | all: { 139 | files: { 140 | 'dest/lib.js': ['src/lib/jquery.js', 'src/lib/jquery.mobile.js'], 141 | 'dest/script.js': ['src/js/init.js'] 142 | } 143 | }, 144 | dev: { 145 | 'dest/script.js': ['src/js/init.js'] 146 | } 147 | }, 148 | express: { 149 | options: { 150 | script: 'server.js', 151 | port: 3000 152 | }, 153 | defaults: {} 154 | } 155 | }); 156 | 157 | grunt.loadNpmTasks('grunt-contrib-watch'); 158 | grunt.loadNpmTasks('grunt-contrib-uglify'); 159 | grunt.loadNpmTasks('grunt-express-server'); 160 | 161 | grunt.registerTask('default', ['express', 'watch']); 162 | 163 | }; 164 | ``` 165 | 166 | The default task first runs express server and watches the resp. files for changes, once a file changes, uglify:dev task is run and livereload will refresh the page. 167 | So your workflow just went to *Save -> Observe*. 168 | 169 | We will cover more options, how to run parallel tasks etc. in the next blog posts. -------------------------------------------------------------------------------- /03-grunt-contrib-watch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Sample Live Reload File 6 | 7 | 8 | 9 |

10 | The following script tag is added, 11 | <script src="//localhost:35729/livereload.js"></script> 12 | It will listen on port 35729 server and refresh the page whenever a the init.js file is changed. 13 |

14 | 15 | -------------------------------------------------------------------------------- /03-grunt-contrib-watch/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "03-grunt-contrib-watch", 3 | "version": "0.0.0", 4 | "description": "Simple way to use grunt watch", 5 | "main": "Gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "grunt": "^0.4.5", 13 | "grunt-contrib-watch": "^0.6.1", 14 | "grunt-contrib-uglify": "^0.6.0", 15 | "grunt-express-server": "^0.4.19" 16 | }, 17 | "dependencies": { 18 | "express": "^4.10.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /03-grunt-contrib-watch/server.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var path = require("path"); 3 | var app = express(); 4 | 5 | app.get("/", function (req, res) { 6 | res.sendFile(path.join(__dirname, "index.html")); 7 | }); 8 | 9 | app.listen(3000); 10 | console.log("Listening on 3000"); 11 | 12 | module.exports = app; -------------------------------------------------------------------------------- /03-grunt-contrib-watch/src/js/init.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function () { 2 | console.log(" Jay Kanakiya "); 3 | $("body").on("click", function () { 4 | console.log("Clicked"); 5 | }); 6 | }); -------------------------------------------------------------------------------- /04-grunt-jscs/.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "disallowSpacesInNamedFunctionExpression": { 3 | "beforeOpeningRoundBrace": true 4 | }, 5 | "disallowSpacesInFunctionExpression": { 6 | "beforeOpeningRoundBrace": true 7 | }, 8 | "disallowSpacesInAnonymousFunctionExpression": { 9 | "beforeOpeningRoundBrace": true 10 | }, 11 | "disallowSpacesInFunctionDeclaration": { 12 | "beforeOpeningRoundBrace": true 13 | }, 14 | "disallowEmptyBlocks": true, 15 | "disallowSpacesInsideArrayBrackets": true, 16 | "disallowSpacesInsideParentheses": true, 17 | "disallowQuotedKeysInObjects": true, 18 | "disallowSpaceAfterObjectKeys": true, 19 | "disallowSpaceAfterPrefixUnaryOperators": true, 20 | "disallowSpaceBeforePostfixUnaryOperators": true, 21 | "disallowSpaceBeforeBinaryOperators": [ 22 | "," 23 | ], 24 | "disallowMixedSpacesAndTabs": true, 25 | "disallowTrailingWhitespace": true, 26 | "disallowTrailingComma": true, 27 | "disallowYodaConditions": true, 28 | "disallowKeywords": [ "with" ], 29 | "disallowMultipleLineBreaks": true, 30 | "requireSpaceBeforeBlockStatements": true, 31 | "requireParenthesesAroundIIFE": true, 32 | "requireSpacesInConditionalExpression": true, 33 | "requireMultipleVarDecl": "onevar", 34 | "requireBlocksOnNewline": 1, 35 | "requireCommaBeforeLineBreak": true, 36 | "requireSpaceBeforeBinaryOperators": true, 37 | "requireSpaceAfterBinaryOperators": true, 38 | "requireCamelCaseOrUpperCaseIdentifiers": true, 39 | "requireLineFeedAtFileEnd": true, 40 | "requireCapitalizedConstructors": true, 41 | "requireDotNotation": true, 42 | "requireCurlyBraces": [ 43 | "do" 44 | ], 45 | "requireSpaceAfterKeywords": [ 46 | "if", 47 | "else", 48 | "for", 49 | "while", 50 | "do", 51 | "switch", 52 | "case", 53 | "return", 54 | "try", 55 | "catch", 56 | "typeof" 57 | ], 58 | "safeContextKeyword": "_this", 59 | "validateLineBreaks": "LF", 60 | "validateQuoteMarks": "'", 61 | "validateIndentation": 2 62 | } -------------------------------------------------------------------------------- /04-grunt-jscs/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | jscs: { 4 | src: 'Gruntfile.js', 5 | options: { 6 | config: '.jscsrc' 7 | } 8 | } 9 | }); 10 | grunt.loadNpmTasks('grunt-jscs'); 11 | grunt.registerTask('default', ['jscs']); 12 | }; 13 | -------------------------------------------------------------------------------- /04-grunt-jscs/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-jscs/ "grunt jscs") 2 | 3 | grunt jscs is grunt plugin for javascript code linting of all the javascript files for coding conventions. 4 | The jscs has got over 60 code validation rules coveringn wide range of options like indentation, maximum line length, maximum function block length, maximum file length, line breaks. curly braces, spaces before functions, array declaration etc. 5 | 6 | For your front-end project, you should have a .jscsrc file which contains javascript style checklist for that project. 7 | This is the ".jscsrc" file for Airbnb style guide 8 | *[Sample jscsrc files](https://github.com/jscs-dev/node-jscs/tree/master/presets)* 9 | ``` 10 | { 11 | "disallowSpacesInNamedFunctionExpression": { 12 | "beforeOpeningRoundBrace": true 13 | }, 14 | "disallowSpacesInFunctionExpression": { 15 | "beforeOpeningRoundBrace": true 16 | }, 17 | "disallowSpacesInAnonymousFunctionExpression": { 18 | "beforeOpeningRoundBrace": true 19 | }, 20 | "disallowSpacesInFunctionDeclaration": { 21 | "beforeOpeningRoundBrace": true 22 | }, 23 | "disallowEmptyBlocks": true, 24 | "disallowSpacesInsideArrayBrackets": true, 25 | "disallowSpacesInsideParentheses": true, 26 | "disallowQuotedKeysInObjects": true, 27 | "disallowSpaceAfterObjectKeys": true, 28 | "disallowSpaceAfterPrefixUnaryOperators": true, 29 | "disallowSpaceBeforePostfixUnaryOperators": true, 30 | "disallowSpaceBeforeBinaryOperators": [ 31 | "," 32 | ], 33 | "disallowMixedSpacesAndTabs": true, 34 | "disallowTrailingWhitespace": true, 35 | "disallowTrailingComma": true, 36 | "disallowYodaConditions": true, 37 | "disallowKeywords": [ "with" ], 38 | "disallowMultipleLineBreaks": true, 39 | "requireSpaceBeforeBlockStatements": true, 40 | "requireParenthesesAroundIIFE": true, 41 | "requireSpacesInConditionalExpression": true, 42 | "requireMultipleVarDecl": "onevar", 43 | "requireBlocksOnNewline": 1, 44 | "requireCommaBeforeLineBreak": true, 45 | "requireSpaceBeforeBinaryOperators": true, 46 | "requireSpaceAfterBinaryOperators": true, 47 | "requireCamelCaseOrUpperCaseIdentifiers": true, 48 | "requireLineFeedAtFileEnd": true, 49 | "requireCapitalizedConstructors": true, 50 | "requireDotNotation": true, 51 | "requireCurlyBraces": [ 52 | "do" 53 | ], 54 | "requireSpaceAfterKeywords": [ 55 | "if", 56 | "else", 57 | "for", 58 | "while", 59 | "do", 60 | "switch", 61 | "case", 62 | "return", 63 | "try", 64 | "catch", 65 | "typeof" 66 | ], 67 | "safeContextKeyword": "_this", 68 | "validateLineBreaks": "LF", 69 | "validateQuoteMarks": "'", 70 | "validateIndentation": 2 71 | } 72 | ``` 73 | 74 | ## Getting Started. (Commit: 37e6a597c) 75 | 76 | Lets start by writing a sample jscs grunt task that should check Gruntfile.js for code covention errors according to the AirBnb javascript style guide. Save it as .jscsrc. 77 | Here's its grunt file: 78 | 79 | ``` 80 | module.exports = function(grunt) { 81 | grunt.initConfig({ 82 | jscs: { 83 | src: 'Gruntfile.js', 84 | options: { 85 | config: '.jscsrc' 86 | } 87 | } 88 | }); 89 | 90 | grunt.loadNpmTasks('grunt-jscs'); 91 | grunt.registerTask('default', ['jscs']); 92 | }; 93 | ``` 94 | 95 | On running grunt from cmd, you should get this error: 96 | 97 | ``` 98 | $ grunt 99 | Running "jscs:src" (jscs) task 100 | Invalid line break at Gruntfile.js : 101 | 1 |module.exports = function(grunt) { 102 | ------------------------------------------^ 103 | 2 | grunt.initConfig({ 104 | 3 | jscs: { 105 | Missing line feed at file end at Gruntfile.js : 106 | 11 | grunt.loadNpmTasks('grunt-jscs'); 107 | 12 | grunt.registerTask('default', ['jscs']); 108 | 13 |}; 109 | --------^ 110 | >> 2 code style errors found! 111 | Warning: Task "jscs:src" failed. Use --force to continue. 112 | 113 | Aborted due to warnings. 114 | ``` 115 | 116 | Both of them are related to line endings for windows line ending are "CRLF" for linux its "LF", this can be easily fixed in Sublime (or your text editor) by setting Settings -> Users -> as 117 | 118 | ``` 119 | "default_line_ending": "LF", 120 | "default_line_ending": "unix", 121 | ``` 122 | 123 | After running grunt you should now be able to successfully run grunt on it. 124 | If you want to check all the rules visit this [link](http://catatron.com/node-jscs/rules/ "jscs rules") 125 | 126 | ## For multiple files 127 | 128 | ``` 129 | module.exports = function(grunt) { 130 | grunt.initConfig({ 131 | jscs: { 132 | main: "app.js", 133 | controllers: { 134 | src: ['Gruntfile.js', 'src/js/*.js'], 135 | options: { 136 | config: '.jscsrc' 137 | } 138 | } 139 | // You can add more configurations over here 140 | } 141 | }); 142 | 143 | grunt.loadNpmTasks('grunt-jscs'); 144 | grunt.registerTask('default', ['jscs']); 145 | }; 146 | ``` -------------------------------------------------------------------------------- /04-grunt-jscs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "04-grunt-jscs", 3 | "version": "0.0.0", 4 | "description": "A tutorial on how to use grunt jscs", 5 | "keywords": [ 6 | "grunt", 7 | "grunt-jscs", 8 | "jscs" 9 | ], 10 | "main": "Gruntfile.js", 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "author": "Jay Kanakiya", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "grunt": "^0.4.5", 18 | "grunt-jscs": "^1.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /06-grunt-contrib-copy/.gitignore: -------------------------------------------------------------------------------- 1 | dist/* -------------------------------------------------------------------------------- /06-grunt-contrib-copy/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | copy: { 4 | main: { 5 | files: [{ 6 | expand: true, 7 | cwd: 'src/', 8 | src: ['**'], 9 | dest: 'dist/' 10 | }] 11 | } 12 | } 13 | }); 14 | 15 | grunt.loadNpmTasks('grunt-contrib-copy'); 16 | grunt.registerTask('default', ['copy']); 17 | }; -------------------------------------------------------------------------------- /06-grunt-contrib-copy/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-contrib-imagemin/ "grunt imagemin") 2 | 3 | grunt-contrib-copy is an official grunt plugin for advanced files and folders copying/moving for automated front end development. 4 | You can set up a grunt task in your 'build' that will copy certain files and folders to locations that you specify, for example config files, pdf assets. 5 | To install this in your project just run : 6 | `npm install grunt-contrib-copy --save-dev` 7 | This will add it in node_modules and the flag --save-dev will also add it in devDependencies of package.json 8 | 9 | ## Getting started. (1eccb4a) 10 | 11 | First we will create a simple grunt task that just copies all files and folders from src/* and saves them to dist/*. 12 | 13 | Folder and File Structure: 14 | 15 | ``` 16 | ├── Gruntfile.js 17 | ├── package.json 18 | ├── README.md 19 | └── src 20 | └── assets 21 | └── copyThis.txt 22 | ``` 23 | 24 | Gruntfile.js 25 | ``` 26 | module.exports = function(grunt) { 27 | grunt.initConfig({ 28 | copy: { 29 | main: { 30 | files: [{ 31 | expand: true, 32 | cwd: 'src/', 33 | src: ['**'], 34 | dest: 'dist/' 35 | }] 36 | } 37 | } 38 | }); 39 | 40 | grunt.loadNpmTasks('grunt-contrib-copy'); 41 | grunt.registerTask('default', ['copy']); 42 | }; 43 | ``` 44 | 45 | On running grunt from cmd: 46 | 47 | ``` 48 | $ grunt 49 | Running "copy:main" (copy) task 50 | Created 2 directories, copied 1 file 51 | 52 | Done, without errors. 53 | ``` 54 | 55 | New folder structure 56 | 57 | ``` 58 | . 59 | ├── dist 60 | │   └── assets 61 | │   └── copyThis.txt 62 | ├── Gruntfile.js 63 | ├── package.json 64 | ├── README.md 65 | └── src 66 | └── assets 67 | └── copyThis.txt 68 | ``` 69 | 70 | ## Files and Folders settings 71 | 72 | You can use different combinations of src and dest for advanced copying configuration. 73 | 74 | * To include files within path 75 | `{expand: true, src: ['path/*'], dest: 'dest/', filter: 'isFile'}` 76 | 77 | * To include files within path and its sub-directories 78 | `{expand: true, src: ['path/**'], dest: 'dest/'}` 79 | 80 | * To make all src relative to cwd 81 | `{expand: true, cwd: 'path/', src: ['**'], dest: 'dest/'}` 82 | 83 | * To flatten results to a single level 84 | `{expand: true, flatten: true, src: ['path/**'], dest: 'dest/', filter: 'isFile'}` 85 | 86 | ## Process while copying 87 | 88 | grunt-contrib-copy also provides a to replace certain placeholders in all your files but correct value. 89 | This can be done via the `options` param 90 | This config will replace PATH to /hello/world wherever it finds it. 91 | ``` 92 | copy: { 93 | main: { 94 | src: 'src/a', 95 | dest: 'src/a.bak', 96 | options: { 97 | process: function (content, srcpath) { 98 | return content.replace(/[PATH]/,"/hello/world"); 99 | }, 100 | }, 101 | }, 102 | }, 103 | ``` 104 | You can use this simple functions to do more things not just do regex replace, Eg: inform how many files contain a particular word, do some textual analysis of code.. , replacing html anchor links to point to different paths when in production etc 105 | -------------------------------------------------------------------------------- /06-grunt-contrib-copy/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "06-grunt-contrib-copy", 3 | "version": "0.0.0", 4 | "description": "grunt contrib copy for advanced automated copying of files and folders", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Jay Kanakiya", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "grunt": "^0.4.5", 13 | "grunt-contrib-copy": "^0.7.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /06-grunt-contrib-copy/src/assets/copyThis.txt: -------------------------------------------------------------------------------- 1 | This file should get copied. -------------------------------------------------------------------------------- /07-grunt-concurrent/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | uglify: { 5 | main: { 6 | files: [ 7 | { src: 'libraries/*.js', dest: 'dist/library.js' } 8 | ] 9 | } 10 | }, 11 | copy: { 12 | main: { 13 | files: [{ 14 | expand: true, 15 | cwd: 'src/', 16 | src: ['**'], 17 | dest: 'dist/' 18 | }] 19 | } 20 | }, 21 | concurrent: { 22 | target1: ['copy', 'uglify'] 23 | } 24 | }); 25 | 26 | grunt.loadNpmTasks('grunt-contrib-copy'); 27 | grunt.loadNpmTasks('grunt-contrib-uglify'); 28 | grunt.loadNpmTasks('grunt-concurrent'); 29 | 30 | grunt.registerTask('default', ['concurrent:target1']); 31 | }; -------------------------------------------------------------------------------- /07-grunt-concurrent/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-concurrent/ "grunt concurrent") 2 | 3 | grunt-concurrent is an amazing grunt plugin that allows you to run grunt tasks concurrently / in parallel. 4 | This is important because many grunt tasks are slower or take a lot of time which hampers your build process.You dont want your build time to be more than 5 minutes. 5 | Using grunt-concurrent will speed up your build process by running grunt-tasks in parallel using your machines multiple cores, thus saving you critical time. 6 | 7 | To install this in your project, run 8 | `npm install grunt-concurrent --save-dev` 9 | This will add it in node_modules and the flag --save-dev will also add it in devDependencies of package.json 10 | 11 | ## Getting Started 12 | 13 | For your current project, you have two grunt tasks run [copy](http://grunt-tasks.com/grunt-contrib-copy/ "copy" ) and [grunt-uglify](http://grunt-tasks.com/grunt-contrib-uglify/ "grunt uglify") and we want them to run in parallel. 14 | First lets install them: 15 | `npm install grunt-contrib-copy grunt-contrib-uglify --save-dev` 16 | 17 | The below code will make sure that target1 tasks run concurrently, if you have got an 4 core machine, this will mean 4 tasks can be carried out in parallel. 18 | ``` 19 | concurrent: { 20 | target1: ['copy', 'uglify'] 21 | } 22 | ``` 23 | 24 | > The full Gruntfile.js 25 | 26 | ``` 27 | module.exports = function(grunt) { 28 | grunt.initConfig({ 29 | pkg: grunt.file.readJSON('package.json'), 30 | uglify: { 31 | main: { 32 | files: [ 33 | { src: 'libraries/*.js', dest: 'dist/library.js' } 34 | ] 35 | } 36 | }, 37 | copy: { 38 | main: { 39 | files: [{ 40 | expand: true, 41 | cwd: 'src/', 42 | src: ['**'], 43 | dest: 'dist/' 44 | }] 45 | } 46 | }, 47 | concurrent: { 48 | target1: ['copy', 'uglify'] 49 | } 50 | }); 51 | 52 | grunt.loadNpmTasks('grunt-contrib-copy'); 53 | grunt.loadNpmTasks('grunt-contrib-uglify'); 54 | grunt.loadNpmTasks('grunt-concurrent'); 55 | 56 | grunt.registerTask('default', ['concurrent:target1']); 57 | }; 58 | ``` 59 | The above code will copy whatever is inside src/ to dist/ while also running uglify-js on the js files in libraries folder and minifying them to dist/library.js 60 | 61 | Folder and File structure 62 | 63 | ``` 64 | . 65 | ├── dist 66 | │   ├── jquery.js 67 | │   ├── jquery.mobile.js 68 | │   └── library.js 69 | ├── Gruntfile.js 70 | ├── libraries 71 | │   ├── jquery.js 72 | │   └── jquery.mobile.js 73 | ├── package.json 74 | ├── README.md 75 | ├── server.js 76 | └── src 77 | ├── jquery.js 78 | └── jquery.mobile.js 79 | ``` 80 | 81 | ## Other options 82 | 83 | You can specify some options in grunt-concurrent like :- 84 | 85 | - limit > limits the number of grunt tasks carried out simultaneously.[] 86 | - logConcurrentOutput > log the output of your concurrent tasks together. [Default is false] 87 | -------------------------------------------------------------------------------- /07-grunt-concurrent/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "07-grunt-concurrent", 3 | "version": "0.0.0", 4 | "description": "grunt concurrent to run tasks in parallel", 5 | "main": "Gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "grunt" 11 | ], 12 | "author": "Jay Kanakiya", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "grunt-concurrent": "^1.0.0", 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-copy": "^0.7.0", 18 | "grunt-contrib-uglify": "^0.6.0" 19 | }, 20 | "dependencies": {} 21 | } 22 | -------------------------------------------------------------------------------- /07-grunt-concurrent/server.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var path = require("path"); 3 | var app = express(); 4 | 5 | app.get("/", function (req, res) { 6 | res.sendFile(path.join(__dirname, "index.html")); 7 | }); 8 | 9 | app.listen(3000); 10 | console.log("Listening on 3000"); 11 | 12 | module.exports = app; -------------------------------------------------------------------------------- /08-grunt-usemin/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | copy: { 4 | generated: { 5 | src: 'index.html', 6 | dest: 'dist/index.html' 7 | } 8 | }, 9 | filerev: { 10 | options: { 11 | encoding: 'utf8', 12 | algorithm: 'md5', 13 | length: 20 14 | }, 15 | source: { 16 | files: [{ 17 | src: [ 18 | 'dist/js/*.js', 19 | 'dist/css/*.css' 20 | ] 21 | }] 22 | } 23 | }, 24 | useminPrepare: { 25 | html: 'index.html', 26 | options: { 27 | dest: 'dist' 28 | } 29 | }, 30 | usemin: { 31 | html: 'dist/index.html', 32 | options: { 33 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 34 | } 35 | } 36 | }); 37 | 38 | grunt.loadNpmTasks('grunt-usemin'); 39 | grunt.loadNpmTasks('grunt-contrib-copy'); 40 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 41 | grunt.loadNpmTasks('grunt-contrib-uglify'); 42 | grunt.loadNpmTasks('grunt-contrib-concat'); 43 | grunt.loadNpmTasks('grunt-filerev'); 44 | 45 | grunt.registerTask('default', [ 46 | 'copy:generated', 47 | 'useminPrepare', 48 | 'concat', 49 | 'uglify', 50 | 'cssmin', 51 | 'filerev', 52 | 'usemin' 53 | ]); 54 | }; -------------------------------------------------------------------------------- /08-grunt-usemin/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-usemin/ "grunt usemin") 2 | 3 | grunt-usemin is an amazing grunt plugin that allows you to specify the build and concatenation stylesheets and javascript inside html references. This helps you to maintain only one file from where you can define dependencies as well as how to minify them. 4 | 5 | It scans your html files or your template files and optimizes javascript files and stylesheets as specified. 6 | 7 | ## Getting Started 8 | 9 | To install this in your project, run 10 | `npm install grunt-usemin --save-dev` 11 | 12 | This will add it in node_modules and the flag --save-dev will also add it in devDependencies of package.json 13 | 14 | Usemin exports two tasks, viz. usemin and useminPrepare as well as other grunt plugins like [concat](http://grunt-tasks.com/grunt-contrib-copy/), [uglify](http://grunt-tasks.com/grunt-contrib-uglify/), cssmin, filerev 15 | 16 | You will also have to install them manually. 17 | `npm install grunt-contrib-copy grunt-contrib-uglify grunt-contrib-cssmin grunt-filerev --save-dev` 18 | 19 | We will also require [grunt-contrib-copy](http://grunt-tasks.com/grunt-contrib-copy/) for copying the index.html to the 20 | 21 | dist folder which will be for production only. 22 | *useminPrepare* : This task prepares the configuration to transform specific blocks in the scrutinized file into a single line, targeting an optimized version of the files. This is done by generating subtasks called generated for each of the optimization steps handled by the Grunt plugins 23 | 24 | *usemin*: This task replaces the blocks by the file they reference, and replaces all references to assets by their revisioned version if it is found on the disk. This target modifies the files it is working on. 25 | 26 | In short, useminPrepare is where you define the configuration while usemin is where you define the files. 27 | How to specify dependencies inside html: 28 | 29 | ``` html 30 | 31 | ... HTML Markup, list of script / link tags. 32 | 33 | ``` 34 | 35 | > The full Gruntfile.js 36 | 37 | js 38 | ``` 39 | module.exports = function(grunt) { 40 | grunt.initConfig({ 41 | copy: { 42 | generated: { 43 | src: 'index.html', 44 | dest: 'dist/index.html' 45 | } 46 | }, 47 | filerev: { 48 | options: { 49 | encoding: 'utf8', 50 | algorithm: 'md5', 51 | length: 20 52 | }, 53 | source: { 54 | files: [{ 55 | src: [ 56 | 'dist/js/*.js', 57 | 'dist/css/*.css' 58 | ] 59 | }] 60 | } 61 | }, 62 | useminPrepare: { 63 | html: 'index.html', 64 | options: { 65 | dest: 'dist' 66 | } 67 | }, 68 | usemin: { 69 | html: 'dist/index.html', 70 | options: { 71 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 72 | } 73 | } 74 | }); 75 | 76 | grunt.loadNpmTasks('grunt-usemin'); 77 | grunt.loadNpmTasks('grunt-contrib-copy'); 78 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 79 | grunt.loadNpmTasks('grunt-contrib-uglify'); 80 | grunt.loadNpmTasks('grunt-contrib-concat'); 81 | grunt.loadNpmTasks('grunt-filerev'); 82 | 83 | grunt.registerTask('default', [ 84 | 'copy:generated', 85 | 'useminPrepare', 86 | 'concat', 87 | 'uglify', 88 | 'cssmin', 89 | 'filerev', 90 | 'usemin' 91 | ]); 92 | }; 93 | ``` 94 | 95 | Folder and File structure 96 | 97 | ``` 98 | . 99 | ├── css 100 | │   ├── bootstrap.css 101 | │   ├── codemirror.css 102 | │   └── jquery.sidr.light.css 103 | ├── dist <- folder where all new files are generated 104 | │   ├── css 105 | │   │   └── styles.7dea81d829f10a1fc486.css <- filerev 106 | │   ├── index.html 107 | │   └── js 108 | │   └── script.459446c51efa85dbade2.js <- filerev 109 | ├── Gruntfile.js 110 | ├── index.html 111 | ├── js 112 | │   ├── angular.min.js 113 | │   ├── bootstrap.min.js 114 | │   ├── jquery.js 115 | │   └── jquery.superscrollorama.js 116 | ├── package.json 117 | └── README.md 118 | ``` 119 | 120 | Grunt usemin first copies index.html to dist/, concat then copies as well as concatenates all css and js files to 121 | dist/js and dist/css. Uglify and cssmin then minifies the javascript and css files. 122 | Filerev runs then runs the concatenated files through a file content has and gives a revision to each file. 123 | usemin is the final task that changes index.html to point to the rev version. 124 | 125 | Therefore you can grunt-usemin for your build process easily. 126 | Using the same above configuration you can add more html files and folders and make a complex build process easier to manage, change and use. 127 | 128 | Futher: [How to use grunt-usemin with grunt-remove-logging](http://grunt-tasks.com/grunt-remove-logging/) 129 | 130 | Above post will explain how you can still keep those pesky yet required console.log statements in your development folder and remove them in your production files. 131 | 132 | Further 2: [How to use grunt-usmin with grunt-htmlmin](http://grunt-tasks.com/grunt-htmlmin/) 133 | 134 | Above post explains the steps to minify html, css and js files using the above plugins. 135 | 136 | Further 3: [Usage with time-grunt](http://grunt-tasks.com/time-grunt/) 137 | 138 | Further 4: [Usage with grunt-image-embed](http://grunt-tasks.com/grunt-image-embed/) 139 | 140 | Above post will explain how to replace your small image assets referenced in your css files by data-uris. -------------------------------------------------------------------------------- /08-grunt-usemin/css/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 100%; 7 | } 8 | .CodeMirror-scroll { 9 | /* Set scrolling behaviour here */ 10 | overflow: auto; 11 | } 12 | 13 | /* PADDING */ 14 | 15 | .CodeMirror-lines { 16 | padding: 4px 0; /* Vertical padding around content */ 17 | } 18 | .CodeMirror pre { 19 | padding: 0 4px; /* Horizontal padding of content */ 20 | } 21 | 22 | .CodeMirror-scrollbar-filler { 23 | background-color: white; /* The little square between H and V scrollbars */ 24 | } 25 | 26 | /* GUTTER */ 27 | 28 | .CodeMirror-gutters { 29 | border-right: 1px solid #ddd; 30 | background-color: #f7f7f7; 31 | } 32 | .CodeMirror-linenumbers {} 33 | .CodeMirror-linenumber { 34 | padding: 0 3px 0 5px; 35 | min-width: 20px; 36 | text-align: right; 37 | color: #999; 38 | } 39 | 40 | /* CURSOR */ 41 | 42 | .CodeMirror pre.CodeMirror-cursor { 43 | border-left: 1px solid black; 44 | } 45 | /* Shown when moving in bi-directional text */ 46 | .CodeMirror pre.CodeMirror-secondarycursor { 47 | border-left: 1px solid silver; 48 | } 49 | .cm-keymap-fat-cursor pre.CodeMirror-cursor { 50 | width: auto; 51 | border: 0; 52 | background: transparent; 53 | background: rgba(0, 200, 0, .4); 54 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); 55 | } 56 | /* Kludge to turn off filter in ie9+, which also accepts rgba */ 57 | .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) { 58 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 59 | } 60 | /* Can style cursor different in overwrite (non-insert) mode */ 61 | .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} 62 | 63 | /* DEFAULT THEME */ 64 | 65 | .cm-s-default .cm-keyword {color: #708;} 66 | .cm-s-default .cm-atom {color: #219;} 67 | .cm-s-default .cm-number {color: #164;} 68 | .cm-s-default .cm-def {color: #00f;} 69 | .cm-s-default .cm-variable {color: black;} 70 | .cm-s-default .cm-variable-2 {color: #05a;} 71 | .cm-s-default .cm-variable-3 {color: #085;} 72 | .cm-s-default .cm-property {color: black;} 73 | .cm-s-default .cm-operator {color: black;} 74 | .cm-s-default .cm-comment {color: #a50;} 75 | .cm-s-default .cm-string {color: #a11;} 76 | .cm-s-default .cm-string-2 {color: #f50;} 77 | .cm-s-default .cm-meta {color: #555;} 78 | .cm-s-default .cm-error {color: #f00;} 79 | .cm-s-default .cm-qualifier {color: #555;} 80 | .cm-s-default .cm-builtin {color: #30a;} 81 | .cm-s-default .cm-bracket {color: #997;} 82 | .cm-s-default .cm-tag {color: #170;} 83 | .cm-s-default .cm-attribute {color: #00c;} 84 | .cm-s-default .cm-header {color: blue;} 85 | .cm-s-default .cm-quote {color: #090;} 86 | .cm-s-default .cm-hr {color: #999;} 87 | .cm-s-default .cm-link {color: #00c;} 88 | 89 | .cm-negative {color: #d44;} 90 | .cm-positive {color: #292;} 91 | .cm-header, .cm-strong {font-weight: bold;} 92 | .cm-em {font-style: italic;} 93 | .cm-emstrong {font-style: italic; font-weight: bold;} 94 | .cm-link {text-decoration: underline;} 95 | 96 | .cm-invalidchar {color: #f00;} 97 | 98 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 99 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 100 | 101 | /* STOP */ 102 | 103 | /* The rest of this file contains styles related to the mechanics of 104 | the editor. You probably shouldn't touch them. */ 105 | 106 | .CodeMirror { 107 | line-height: 1; 108 | position: relative; 109 | overflow: hidden; 110 | } 111 | 112 | .CodeMirror-scroll { 113 | /* 30px is the magic margin used to hide the element's real scrollbars */ 114 | /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */ 115 | margin-bottom: -30px; margin-right: -30px; 116 | padding-bottom: 30px; padding-right: 30px; 117 | height: 100%; 118 | outline: none; /* Prevent dragging from highlighting the element */ 119 | position: relative; 120 | } 121 | .CodeMirror-sizer { 122 | position: relative; 123 | } 124 | 125 | /* The fake, visible scrollbars. Used to force redraw during scrolling 126 | before actuall scrolling happens, thus preventing shaking and 127 | flickering artifacts. */ 128 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler { 129 | position: absolute; 130 | z-index: 6; 131 | display: none; 132 | } 133 | .CodeMirror-vscrollbar { 134 | right: 0; top: 0; 135 | overflow-x: hidden; 136 | overflow-y: scroll; 137 | } 138 | .CodeMirror-hscrollbar { 139 | bottom: 0; left: 0; 140 | overflow-y: hidden; 141 | overflow-x: scroll; 142 | } 143 | .CodeMirror-scrollbar-filler { 144 | right: 0; bottom: 0; 145 | z-index: 6; 146 | } 147 | 148 | .CodeMirror-gutters { 149 | position: absolute; left: 0; top: 0; 150 | height: 100%; 151 | z-index: 3; 152 | } 153 | .CodeMirror-gutter { 154 | height: 100%; 155 | display: inline-block; 156 | /* Hack to make IE7 behave */ 157 | *zoom:1; 158 | *display:inline; 159 | } 160 | .CodeMirror-gutter-elt { 161 | position: absolute; 162 | cursor: default; 163 | z-index: 4; 164 | } 165 | 166 | .CodeMirror-lines { 167 | cursor: text; 168 | } 169 | .CodeMirror pre { 170 | /* Reset some styles that the rest of the page might have set */ 171 | -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0; 172 | border-width: 0; 173 | background: transparent; 174 | font-family: inherit; 175 | font-size: inherit; 176 | margin: 0; 177 | white-space: pre; 178 | word-wrap: normal; 179 | line-height: inherit; 180 | color: inherit; 181 | z-index: 2; 182 | position: relative; 183 | overflow: visible; 184 | } 185 | .CodeMirror-wrap pre { 186 | word-wrap: break-word; 187 | white-space: pre-wrap; 188 | word-break: normal; 189 | } 190 | .CodeMirror-linebackground { 191 | position: absolute; 192 | left: 0; right: 0; top: 0; bottom: 0; 193 | z-index: 0; 194 | } 195 | 196 | .CodeMirror-linewidget { 197 | position: relative; 198 | z-index: 2; 199 | } 200 | 201 | .CodeMirror-wrap .CodeMirror-scroll { 202 | overflow-x: hidden; 203 | } 204 | 205 | .CodeMirror-measure { 206 | position: absolute; 207 | width: 100%; height: 0px; 208 | overflow: hidden; 209 | visibility: hidden; 210 | } 211 | .CodeMirror-measure pre { position: static; } 212 | 213 | .CodeMirror pre.CodeMirror-cursor { 214 | position: absolute; 215 | visibility: hidden; 216 | border-right: none; 217 | width: 0; 218 | } 219 | .CodeMirror-focused pre.CodeMirror-cursor { 220 | visibility: visible; 221 | } 222 | 223 | .CodeMirror-selected { background: #d9d9d9; } 224 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 225 | 226 | .CodeMirror-searching { 227 | background: #ffa; 228 | background: rgba(255, 255, 0, .4); 229 | } 230 | 231 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */ 232 | .CodeMirror span { *vertical-align: text-bottom; } 233 | 234 | @media print { 235 | /* Hide the cursor when printing */ 236 | .CodeMirror pre.CodeMirror-cursor { 237 | visibility: hidden; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /08-grunt-usemin/css/jquery.sidr.light.css: -------------------------------------------------------------------------------- 1 | /* line 3, ../../src/scss/sidr/_base.scss */ 2 | .sidr { 3 | /* Default Settings */ 4 | display: none; 5 | position: absolute; 6 | position: fixed; 7 | top: 0; 8 | height: 100%; 9 | z-index: 999999; 10 | width: 260px; 11 | overflow-x: none; 12 | overflow-y: auto; 13 | /* Theme Settings */ 14 | font-family: "lucida grande", tahoma, verdana, arial, sans-serif; 15 | font-size: 15px; 16 | background: #f8f8f8; 17 | color: #333333; 18 | -webkit-box-shadow: inset 0 0 5px 5px #ebebeb; 19 | -moz-box-shadow: inset 0 0 5px 5px #ebebeb; 20 | box-shadow: inset 0 0 5px 5px #ebebeb; 21 | } 22 | /* line 15, ../../src/scss/sidr/_base.scss */ 23 | .sidr .sidr-inner { 24 | padding: 0 0 15px; 25 | } 26 | /* line 18, ../../src/scss/sidr/_base.scss */ 27 | .sidr .sidr-inner > p { 28 | margin-left: 15px; 29 | margin-right: 15px; 30 | } 31 | /* line 24, ../../src/scss/sidr/_base.scss */ 32 | .sidr.right { 33 | left: auto; 34 | right: -260px; 35 | } 36 | /* line 29, ../../src/scss/sidr/_base.scss */ 37 | .sidr.left { 38 | left: -260px; 39 | right: auto; 40 | } 41 | /* line 41, ../../src/scss/sidr/_base.scss */ 42 | .sidr h1, .sidr h2, .sidr h3, .sidr h4, .sidr h5, .sidr h6 { 43 | font-size: 11px; 44 | font-weight: normal; 45 | padding: 0 15px; 46 | margin: 0 0 5px; 47 | color: #333333; 48 | line-height: 24px; 49 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #dfdfdf)); 50 | background-image: -webkit-linear-gradient(#ffffff, #dfdfdf); 51 | background-image: -moz-linear-gradient(#ffffff, #dfdfdf); 52 | background-image: -o-linear-gradient(#ffffff, #dfdfdf); 53 | background-image: linear-gradient(#ffffff, #dfdfdf); 54 | -webkit-box-shadow: 0 5px 5px 3px rgba(0, 0, 0, 0.2); 55 | -moz-box-shadow: 0 5px 5px 3px rgba(0, 0, 0, 0.2); 56 | box-shadow: 0 5px 5px 3px rgba(0, 0, 0, 0.2); 57 | } 58 | /* line 52, ../../src/scss/sidr/_base.scss */ 59 | .sidr p { 60 | font-size: 13px; 61 | margin: 0 0 12px; 62 | } 63 | /* line 55, ../../src/scss/sidr/_base.scss */ 64 | .sidr p a { 65 | color: rgba(51, 51, 51, 0.9); 66 | } 67 | /* line 60, ../../src/scss/sidr/_base.scss */ 68 | .sidr > p { 69 | margin-left: 15px; 70 | margin-right: 15px; 71 | } 72 | /* line 65, ../../src/scss/sidr/_base.scss */ 73 | .sidr ul { 74 | display: block; 75 | margin: 0 0 15px; 76 | padding: 0; 77 | border-top: 1px solid #dfdfdf; 78 | border-bottom: 1px solid white; 79 | } 80 | /* line 72, ../../src/scss/sidr/_base.scss */ 81 | .sidr ul li { 82 | display: block; 83 | margin: 0; 84 | line-height: 48px; 85 | border-top: 1px solid white; 86 | border-bottom: 1px solid #dfdfdf; 87 | } 88 | /* line 81, ../../src/scss/sidr/_base.scss */ 89 | .sidr ul li:hover, .sidr ul li.active, .sidr ul li.sidr-class-active { 90 | border-top: none; 91 | line-height: 49px; 92 | } 93 | /* line 85, ../../src/scss/sidr/_base.scss */ 94 | .sidr ul li:hover > a, .sidr ul li:hover > span, .sidr ul li.active > a, .sidr ul li.active > span, .sidr ul li.sidr-class-active > a, .sidr ul li.sidr-class-active > span { 95 | -webkit-box-shadow: inset 0 0 15px 3px #ebebeb; 96 | -moz-box-shadow: inset 0 0 15px 3px #ebebeb; 97 | box-shadow: inset 0 0 15px 3px #ebebeb; 98 | } 99 | /* line 90, ../../src/scss/sidr/_base.scss */ 100 | .sidr ul li a, .sidr ul li span { 101 | padding: 0 15px; 102 | display: block; 103 | text-decoration: none; 104 | color: #333333; 105 | } 106 | /* line 97, ../../src/scss/sidr/_base.scss */ 107 | .sidr ul li ul { 108 | border-bottom: none; 109 | margin: 0; 110 | } 111 | /* line 100, ../../src/scss/sidr/_base.scss */ 112 | .sidr ul li ul li { 113 | line-height: 40px; 114 | font-size: 13px; 115 | } 116 | /* line 104, ../../src/scss/sidr/_base.scss */ 117 | .sidr ul li ul li:last-child { 118 | border-bottom: none; 119 | } 120 | /* line 110, ../../src/scss/sidr/_base.scss */ 121 | .sidr ul li ul li:hover, .sidr ul li ul li.active, .sidr ul li ul li.sidr-class-active { 122 | border-top: none; 123 | line-height: 41px; 124 | } 125 | /* line 114, ../../src/scss/sidr/_base.scss */ 126 | .sidr ul li ul li:hover > a, .sidr ul li ul li:hover > span, .sidr ul li ul li.active > a, .sidr ul li ul li.active > span, .sidr ul li ul li.sidr-class-active > a, .sidr ul li ul li.sidr-class-active > span { 127 | -webkit-box-shadow: inset 0 0 15px 3px #ebebeb; 128 | -moz-box-shadow: inset 0 0 15px 3px #ebebeb; 129 | box-shadow: inset 0 0 15px 3px #ebebeb; 130 | } 131 | /* line 119, ../../src/scss/sidr/_base.scss */ 132 | .sidr ul li ul li a, .sidr ul li ul li span { 133 | color: rgba(51, 51, 51, 0.8); 134 | padding-left: 30px; 135 | } 136 | /* line 128, ../../src/scss/sidr/_base.scss */ 137 | .sidr form { 138 | margin: 0 15px; 139 | } 140 | /* line 132, ../../src/scss/sidr/_base.scss */ 141 | .sidr label { 142 | font-size: 13px; 143 | } 144 | /* line 146, ../../src/scss/sidr/_base.scss */ 145 | .sidr input[type="text"], 146 | .sidr input[type="password"], 147 | .sidr input[type="date"], 148 | .sidr input[type="datetime"], 149 | .sidr input[type="email"], 150 | .sidr input[type="number"], 151 | .sidr input[type="search"], 152 | .sidr input[type="tel"], 153 | .sidr input[type="time"], 154 | .sidr input[type="url"], 155 | .sidr textarea, .sidr select { 156 | width: 100%; 157 | font-size: 13px; 158 | padding: 5px; 159 | -webkit-box-sizing: border-box; 160 | -moz-box-sizing: border-box; 161 | box-sizing: border-box; 162 | margin: 0 0 10px; 163 | -webkit-border-radius: 2px; 164 | -moz-border-radius: 2px; 165 | -ms-border-radius: 2px; 166 | -o-border-radius: 2px; 167 | border-radius: 2px; 168 | border: none; 169 | background: rgba(0, 0, 0, 0.1); 170 | color: rgba(51, 51, 51, 0.6); 171 | display: block; 172 | clear: both; 173 | } 174 | /* line 160, ../../src/scss/sidr/_base.scss */ 175 | .sidr input[type=checkbox] { 176 | width: auto; 177 | display: inline; 178 | clear: none; 179 | } 180 | /* line 167, ../../src/scss/sidr/_base.scss */ 181 | .sidr input[type=button], 182 | .sidr input[type=submit] { 183 | color: #f8f8f8; 184 | background: #333333; 185 | } 186 | /* line 171, ../../src/scss/sidr/_base.scss */ 187 | .sidr input[type=button]:hover, 188 | .sidr input[type=submit]:hover { 189 | background: rgba(51, 51, 51, 0.9); 190 | } 191 | -------------------------------------------------------------------------------- /08-grunt-usemin/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt Usemin Example 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /08-grunt-usemin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt Usemin Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /08-grunt-usemin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "08-grunt-usemin", 3 | "version": "0.0.0", 4 | "description": "grunt usemin for optimizing your stylesheets and javascripts", 5 | "main": "Gruntfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "grunt": "^0.4.5", 13 | "grunt-usemin": "^3.0.0", 14 | "grunt-filerev": "^2.1.2", 15 | "grunt-contrib-concat": "^0.5.0", 16 | "grunt-contrib-uglify": "^0.7.0", 17 | "grunt-contrib-cssmin": "^0.11.0", 18 | "grunt-contrib-copy": "^0.7.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /09-grunt-newer/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | uglify: { 5 | all: { 6 | files: { 7 | 'dist/js/minified.js': ['src/**/*.js'] 8 | } 9 | } 10 | } 11 | }); 12 | 13 | grunt.loadNpmTasks('grunt-contrib-uglify'); 14 | grunt.loadNpmTasks('grunt-newer'); 15 | 16 | grunt.registerTask('default', ['uglify:all']); 17 | grunt.registerTask('nw', ['newer:uglify:all']); 18 | 19 | }; -------------------------------------------------------------------------------- /09-grunt-newer/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-newer/ "grunt newer") 2 | 3 | grunt-newer is an simple yet extremely useful grunt plugin that allows you to configure specific tasks to run only when the the file has changed. If you have a long build process or one that takes a lot of time, you can use this to cut down that time, by only running certain tasks when its related files has changed. 4 | 5 | For example, you can use this for uglify which sometimes take a good deal of them. By correctly configuring both the tasks you can only run 'uglify' when its source files have changed. 6 | 7 | ## Getting Started 8 | 9 | The best way to integrate grunt-newer in your build process is to add newer as the first argument when running other tasks. For example `jscs:all` will become `newer:jscs:all` 10 | Lets create a simple Grunt file that will uglify js src files into minified files. 11 | 12 | Heres the folder file structure: 13 | ``` 14 | . 15 | ├── dist 16 | │   └── js 17 | │   └── minified.js 18 | ├── Gruntfile.js 19 | ├── package.json 20 | ├── README.md 21 | └── src 22 | └── js 23 | ├── app.js 24 | ├── jquery.js 25 | └── jquery.superscrollorama.js 26 | ``` 27 | Heres the Gruntfile.js: 28 | ``` 29 | module.exports = function(grunt) { 30 | 31 | grunt.initConfig({ 32 | uglify: { 33 | all: { 34 | files: { 35 | 'dist/js/minified.js': ['src/**/*.js'] 36 | } 37 | } 38 | } 39 | }); 40 | 41 | grunt.loadNpmTasks('grunt-contrib-uglify'); 42 | grunt.loadNpmTasks('grunt-newer'); 43 | 44 | grunt.registerTask('default', ['uglify:all']); 45 | grunt.registerTask('nw', ['newer:uglify:all']); 46 | 47 | }; 48 | ``` 49 | 50 | The default task runs uglify while the nw task will only run uglify if either of the three files have changed. 51 | On running `grunt nw` first time: 52 | 53 | ``` 54 | $ grunt nw 55 | Running "newer:uglify:all" (newer) task 56 | 57 | Running "uglify:all" (uglify) task 58 | >> 1 file created. 59 | 60 | Running "newer-postrun:uglify:all:1:H:\grunt-tasks.com\github\09-grunt-newer\node_modules\grunt-newer\.cache" (newer-postrun) task 61 | 62 | Done, without errors. 63 | ``` 64 | 65 | On running `grunt nw` second time 66 | ``` 67 | $ grunt nw 68 | Running "newer:uglify:all" (newer) task 69 | No newer files to process. 70 | 71 | Done, without errors. 72 | ``` 73 | 74 | If you see the outputs of the commands, grunt-newer does not uglify task once again. 75 | It does all this by keeping track of the last modified time of each file and keeping them in .cache 76 | Then during runtime if theres a diff in any files last modified time, run the task, and update in .cache 77 | 78 | -------------------------------------------------------------------------------- /09-grunt-newer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "09-grunt-newer", 3 | "version": "0.0.1", 4 | "description": "Run grunt tasks on new files", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt-contrib-uglify": "^0.7.0", 17 | "grunt": "^0.4.5", 18 | "grunt-newer": "^1.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /09-grunt-newer/src/js/app.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | console.log('Hello World'); 3 | }); 4 | -------------------------------------------------------------------------------- /10-grunt-bump/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.initConfig({ 4 | bump: { 5 | options: { 6 | files: ['package.json'], 7 | commitFiles: ['package.json', 'Gruntfile.js', 'README.md'], 8 | commitMessage: 'Release v%VERSION%', 9 | createTag: true, 10 | tagName: 'v%VERSION%', 11 | tagMessage: 'The Release %VERSION%' 12 | } 13 | } 14 | }); 15 | 16 | grunt.loadNpmTasks('grunt-bump'); 17 | 18 | grunt.registerTask('bm', ['bump']); 19 | }; -------------------------------------------------------------------------------- /10-grunt-bump/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-bump/ "grunt bump") 2 | 3 | grunt-newer is an simple utility grunt plugin for automatic updation of package versions. grunt-bump allows you to update your versions in your file and additionally do a git-commit with pre-defined tagnames, descriptions 4 | 5 | ## [Semantic Versioning](http://semver.org/) in short 6 | 7 | Given a version number MAJOR.MINOR.PATCH, increment the: 8 | 9 | MAJOR version when you make incompatible API changes, 10 | MINOR version when you add functionality in a backwards-compatible manner, and 11 | PATCH version when you make backwards-compatible bug fixes. 12 | Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. 13 | 14 | ## Getting Started 15 | 16 | Install grunt-bump by 17 | `npm install grunt-bump --save-dev` 18 | Lets create a simple gruntfile that will just update the version param of package.json 19 | 20 | ``` 21 | module.exports = function(grunt) { 22 | 23 | grunt.initConfig({ 24 | bump: { 25 | options: { 26 | files: ['package.json'], 27 | commit: false, 28 | createTag: false, 29 | push: false, 30 | } 31 | } 32 | }); 33 | 34 | grunt.loadNpmTasks('grunt-bump'); 35 | 36 | grunt.registerTask('bm', ['bump']); 37 | }; 38 | ``` 39 | On running grunt the version will be updated to 0.0.2 40 | 41 | ``` 42 | $ grunt bm 43 | Running "bump" task 44 | >> Version bumped to 0.0.2 (in package.json) 45 | 46 | Done, without errors. 47 | ``` 48 | 49 | The `files` parameter in options object takes in an array of files where you want to update the versions. 50 | For example, component.json, bower.json or any application specific versioning files. 51 | 52 | ## Git and grunt-bump 53 | 54 | -------------------------------------------------------------------------------- /10-grunt-bump/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "10-grunt-bump", 3 | "version": "0.0.7", 4 | "description": "Automatic incrementation of plugin versions", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "keywords": "grunt, grunt-bump", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "grunt": "^0.4.5", 18 | "grunt-bump": "^0.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /11-load-grunt-tasks/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | require('load-grunt-tasks')(grunt); 3 | grunt.initConfig({ 4 | copy: { 5 | generated: { 6 | src: 'index.html', 7 | dest: 'dist/index.html' 8 | } 9 | }, 10 | filerev: { 11 | options: { 12 | encoding: 'utf8', 13 | algorithm: 'md5', 14 | length: 20 15 | }, 16 | source: { 17 | files: [{ 18 | src: [ 19 | 'dist/js/*.js', 20 | 'dist/css/*.css' 21 | ] 22 | }] 23 | } 24 | }, 25 | useminPrepare: { 26 | html: 'index.html', 27 | options: { 28 | dest: 'dist' 29 | } 30 | }, 31 | usemin: { 32 | html: 'dist/index.html', 33 | options: { 34 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 35 | } 36 | } 37 | }); 38 | 39 | grunt.registerTask('default', [ 40 | 'copy:generated', 41 | 'useminPrepare', 42 | 'concat', 43 | 'uglify', 44 | 'cssmin', 45 | 'filerev', 46 | 'usemin' 47 | ]); 48 | }; -------------------------------------------------------------------------------- /11-load-grunt-tasks/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/load-grunt-tasks/ "load grunt tasks") 2 | 3 | load-grunt-tasks is a grunt plugin to quickly install all the required packages just using 1 line instead of loading one by one. Lets say that you have a around 10 to 12 dependencies for grunt, as the project goes older and older, manually taking care of which grunt dependency to add, and which grunt dependency to remove becomes cumbersome. 4 | So instead, use package.json as your main configuration file, from which only load the grunt-dependencies defined inside it. 5 | 6 | "load-grunt-tasks" automatically reads the "devDependencies" of package.json and loads them in your Gruntfile.js just using the following line; 7 | `require('load-grunt-tasks')(grunt);` 8 | 9 | To install: 10 | ` npm install --save-dev load-grunt-tasks` 11 | 12 | In your Gruntfile.js replace all this lines: 13 | 14 | ``` 15 | grunt.loadNpmTasks('') 16 | grunt.loadNpmTasks('') 17 | grunt.loadNpmTasks('') 18 | grunt.loadNpmTasks('') 19 | ``` 20 | 21 | by this single line 22 | `require('load-grunt-tasks')(grunt);` 23 | 24 | ## How to use load-grunt-tasks 25 | 26 | Lets consider a simple project with one html files and its css and js dependencies. 27 | You want to write a simple Gruntfile.js which can automatically that html's file dependencies and concatenates, minifies revisions and copies them to the dist folder. 28 | 29 | Heres that Gruntfile 30 | ``` 31 | module.exports = function(grunt) { 32 | grunt.initConfig({ 33 | copy: { 34 | generated: { 35 | src: 'index.html', 36 | dest: 'dist/index.html' 37 | } 38 | }, 39 | filerev: { 40 | options: { 41 | encoding: 'utf8', 42 | algorithm: 'md5', 43 | length: 20 44 | }, 45 | source: { 46 | files: [{ 47 | src: [ 48 | 'dist/js/*.js', 49 | 'dist/css/*.css' 50 | ] 51 | }] 52 | } 53 | }, 54 | useminPrepare: { 55 | html: 'index.html', 56 | options: { 57 | dest: 'dist' 58 | } 59 | }, 60 | usemin: { 61 | html: 'dist/index.html', 62 | options: { 63 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 64 | } 65 | } 66 | }); 67 | 68 | grunt.loadNpmTasks('grunt-usemin'); 69 | grunt.loadNpmTasks('grunt-contrib-copy'); 70 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 71 | grunt.loadNpmTasks('grunt-contrib-uglify'); 72 | grunt.loadNpmTasks('grunt-contrib-concat'); 73 | grunt.loadNpmTasks('grunt-filerev'); 74 | 75 | grunt.registerTask('default', [ 76 | 'copy:generated', 77 | 'useminPrepare', 78 | 'concat', 79 | 'uglify', 80 | 'cssmin', 81 | 'filerev', 82 | 'usemin' 83 | ]); 84 | }; 85 | ``` 86 | 87 | Observe lines #38 to #43, doesn't it seem it violates DRY, this is where load-grunt-tasks comes into play. 88 | This is the new Gruntfile.js: 89 | 90 | ``` 91 | module.exports = function(grunt) { 92 | require('load-grunt-tasks')(grunt); 93 | grunt.initConfig({ 94 | copy: { 95 | generated: { 96 | src: 'index.html', 97 | dest: 'dist/index.html' 98 | } 99 | }, 100 | filerev: { 101 | options: { 102 | encoding: 'utf8', 103 | algorithm: 'md5', 104 | length: 20 105 | }, 106 | source: { 107 | files: [{ 108 | src: [ 109 | 'dist/js/*.js', 110 | 'dist/css/*.css' 111 | ] 112 | }] 113 | } 114 | }, 115 | useminPrepare: { 116 | html: 'index.html', 117 | options: { 118 | dest: 'dist' 119 | } 120 | }, 121 | usemin: { 122 | html: 'dist/index.html', 123 | options: { 124 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 125 | } 126 | } 127 | }); 128 | 129 | grunt.registerTask('default', [ 130 | 'copy:generated', 131 | 'useminPrepare', 132 | 'concat', 133 | 'uglify', 134 | 'cssmin', 135 | 'filerev', 136 | 'usemin' 137 | ]); 138 | }; 139 | ``` 140 | 141 | It produces the same output as before 142 | ``` 143 | $ grunt 144 | Running "copy:generated" (copy) task 145 | Copied 1 file 146 | 147 | Running "useminPrepare:html" (useminPrepare) task 148 | Configuration changed for concat, uglify, cssmin 149 | 150 | Running "concat:generated" (concat) task 151 | File .tmp\concat\css\styles.css created. 152 | File .tmp\concat\js\script.js created. 153 | 154 | Running "uglify:generated" (uglify) task 155 | >> 1 file created. 156 | 157 | Running "cssmin:generated" (cssmin) task 158 | 159 | Running "filerev:source" (filerev) task 160 | Revved 6 files 161 | 162 | Running "usemin:html" (usemin) task 163 | Replaced 1 reference to assets 164 | 165 | Done, without errors. 166 | ``` 167 | 168 | If you have any comments, feel free to drop it below. -------------------------------------------------------------------------------- /11-load-grunt-tasks/css/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 100%; 7 | } 8 | .CodeMirror-scroll { 9 | /* Set scrolling behaviour here */ 10 | overflow: auto; 11 | } 12 | 13 | /* PADDING */ 14 | 15 | .CodeMirror-lines { 16 | padding: 4px 0; /* Vertical padding around content */ 17 | } 18 | .CodeMirror pre { 19 | padding: 0 4px; /* Horizontal padding of content */ 20 | } 21 | 22 | .CodeMirror-scrollbar-filler { 23 | background-color: white; /* The little square between H and V scrollbars */ 24 | } 25 | 26 | /* GUTTER */ 27 | 28 | .CodeMirror-gutters { 29 | border-right: 1px solid #ddd; 30 | background-color: #f7f7f7; 31 | } 32 | .CodeMirror-linenumbers {} 33 | .CodeMirror-linenumber { 34 | padding: 0 3px 0 5px; 35 | min-width: 20px; 36 | text-align: right; 37 | color: #999; 38 | } 39 | 40 | /* CURSOR */ 41 | 42 | .CodeMirror pre.CodeMirror-cursor { 43 | border-left: 1px solid black; 44 | } 45 | /* Shown when moving in bi-directional text */ 46 | .CodeMirror pre.CodeMirror-secondarycursor { 47 | border-left: 1px solid silver; 48 | } 49 | .cm-keymap-fat-cursor pre.CodeMirror-cursor { 50 | width: auto; 51 | border: 0; 52 | background: transparent; 53 | background: rgba(0, 200, 0, .4); 54 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); 55 | } 56 | /* Kludge to turn off filter in ie9+, which also accepts rgba */ 57 | .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) { 58 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 59 | } 60 | /* Can style cursor different in overwrite (non-insert) mode */ 61 | .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} 62 | 63 | /* DEFAULT THEME */ 64 | 65 | .cm-s-default .cm-keyword {color: #708;} 66 | .cm-s-default .cm-atom {color: #219;} 67 | .cm-s-default .cm-number {color: #164;} 68 | .cm-s-default .cm-def {color: #00f;} 69 | .cm-s-default .cm-variable {color: black;} 70 | .cm-s-default .cm-variable-2 {color: #05a;} 71 | .cm-s-default .cm-variable-3 {color: #085;} 72 | .cm-s-default .cm-property {color: black;} 73 | .cm-s-default .cm-operator {color: black;} 74 | .cm-s-default .cm-comment {color: #a50;} 75 | .cm-s-default .cm-string {color: #a11;} 76 | .cm-s-default .cm-string-2 {color: #f50;} 77 | .cm-s-default .cm-meta {color: #555;} 78 | .cm-s-default .cm-error {color: #f00;} 79 | .cm-s-default .cm-qualifier {color: #555;} 80 | .cm-s-default .cm-builtin {color: #30a;} 81 | .cm-s-default .cm-bracket {color: #997;} 82 | .cm-s-default .cm-tag {color: #170;} 83 | .cm-s-default .cm-attribute {color: #00c;} 84 | .cm-s-default .cm-header {color: blue;} 85 | .cm-s-default .cm-quote {color: #090;} 86 | .cm-s-default .cm-hr {color: #999;} 87 | .cm-s-default .cm-link {color: #00c;} 88 | 89 | .cm-negative {color: #d44;} 90 | .cm-positive {color: #292;} 91 | .cm-header, .cm-strong {font-weight: bold;} 92 | .cm-em {font-style: italic;} 93 | .cm-emstrong {font-style: italic; font-weight: bold;} 94 | .cm-link {text-decoration: underline;} 95 | 96 | .cm-invalidchar {color: #f00;} 97 | 98 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 99 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 100 | 101 | /* STOP */ 102 | 103 | /* The rest of this file contains styles related to the mechanics of 104 | the editor. You probably shouldn't touch them. */ 105 | 106 | .CodeMirror { 107 | line-height: 1; 108 | position: relative; 109 | overflow: hidden; 110 | } 111 | 112 | .CodeMirror-scroll { 113 | /* 30px is the magic margin used to hide the element's real scrollbars */ 114 | /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */ 115 | margin-bottom: -30px; margin-right: -30px; 116 | padding-bottom: 30px; padding-right: 30px; 117 | height: 100%; 118 | outline: none; /* Prevent dragging from highlighting the element */ 119 | position: relative; 120 | } 121 | .CodeMirror-sizer { 122 | position: relative; 123 | } 124 | 125 | /* The fake, visible scrollbars. Used to force redraw during scrolling 126 | before actuall scrolling happens, thus preventing shaking and 127 | flickering artifacts. */ 128 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler { 129 | position: absolute; 130 | z-index: 6; 131 | display: none; 132 | } 133 | .CodeMirror-vscrollbar { 134 | right: 0; top: 0; 135 | overflow-x: hidden; 136 | overflow-y: scroll; 137 | } 138 | .CodeMirror-hscrollbar { 139 | bottom: 0; left: 0; 140 | overflow-y: hidden; 141 | overflow-x: scroll; 142 | } 143 | .CodeMirror-scrollbar-filler { 144 | right: 0; bottom: 0; 145 | z-index: 6; 146 | } 147 | 148 | .CodeMirror-gutters { 149 | position: absolute; left: 0; top: 0; 150 | height: 100%; 151 | z-index: 3; 152 | } 153 | .CodeMirror-gutter { 154 | height: 100%; 155 | display: inline-block; 156 | /* Hack to make IE7 behave */ 157 | *zoom:1; 158 | *display:inline; 159 | } 160 | .CodeMirror-gutter-elt { 161 | position: absolute; 162 | cursor: default; 163 | z-index: 4; 164 | } 165 | 166 | .CodeMirror-lines { 167 | cursor: text; 168 | } 169 | .CodeMirror pre { 170 | /* Reset some styles that the rest of the page might have set */ 171 | -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0; 172 | border-width: 0; 173 | background: transparent; 174 | font-family: inherit; 175 | font-size: inherit; 176 | margin: 0; 177 | white-space: pre; 178 | word-wrap: normal; 179 | line-height: inherit; 180 | color: inherit; 181 | z-index: 2; 182 | position: relative; 183 | overflow: visible; 184 | } 185 | .CodeMirror-wrap pre { 186 | word-wrap: break-word; 187 | white-space: pre-wrap; 188 | word-break: normal; 189 | } 190 | .CodeMirror-linebackground { 191 | position: absolute; 192 | left: 0; right: 0; top: 0; bottom: 0; 193 | z-index: 0; 194 | } 195 | 196 | .CodeMirror-linewidget { 197 | position: relative; 198 | z-index: 2; 199 | } 200 | 201 | .CodeMirror-wrap .CodeMirror-scroll { 202 | overflow-x: hidden; 203 | } 204 | 205 | .CodeMirror-measure { 206 | position: absolute; 207 | width: 100%; height: 0px; 208 | overflow: hidden; 209 | visibility: hidden; 210 | } 211 | .CodeMirror-measure pre { position: static; } 212 | 213 | .CodeMirror pre.CodeMirror-cursor { 214 | position: absolute; 215 | visibility: hidden; 216 | border-right: none; 217 | width: 0; 218 | } 219 | .CodeMirror-focused pre.CodeMirror-cursor { 220 | visibility: visible; 221 | } 222 | 223 | .CodeMirror-selected { background: #d9d9d9; } 224 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 225 | 226 | .CodeMirror-searching { 227 | background: #ffa; 228 | background: rgba(255, 255, 0, .4); 229 | } 230 | 231 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */ 232 | .CodeMirror span { *vertical-align: text-bottom; } 233 | 234 | @media print { 235 | /* Hide the cursor when printing */ 236 | .CodeMirror pre.CodeMirror-cursor { 237 | visibility: hidden; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /11-load-grunt-tasks/css/jquery.sidr.light.css: -------------------------------------------------------------------------------- 1 | /* line 3, ../../src/scss/sidr/_base.scss */ 2 | .sidr { 3 | /* Default Settings */ 4 | display: none; 5 | position: absolute; 6 | position: fixed; 7 | top: 0; 8 | height: 100%; 9 | z-index: 999999; 10 | width: 260px; 11 | overflow-x: none; 12 | overflow-y: auto; 13 | /* Theme Settings */ 14 | font-family: "lucida grande", tahoma, verdana, arial, sans-serif; 15 | font-size: 15px; 16 | background: #f8f8f8; 17 | color: #333333; 18 | -webkit-box-shadow: inset 0 0 5px 5px #ebebeb; 19 | -moz-box-shadow: inset 0 0 5px 5px #ebebeb; 20 | box-shadow: inset 0 0 5px 5px #ebebeb; 21 | } 22 | /* line 15, ../../src/scss/sidr/_base.scss */ 23 | .sidr .sidr-inner { 24 | padding: 0 0 15px; 25 | } 26 | /* line 18, ../../src/scss/sidr/_base.scss */ 27 | .sidr .sidr-inner > p { 28 | margin-left: 15px; 29 | margin-right: 15px; 30 | } 31 | /* line 24, ../../src/scss/sidr/_base.scss */ 32 | .sidr.right { 33 | left: auto; 34 | right: -260px; 35 | } 36 | /* line 29, ../../src/scss/sidr/_base.scss */ 37 | .sidr.left { 38 | left: -260px; 39 | right: auto; 40 | } 41 | /* line 41, ../../src/scss/sidr/_base.scss */ 42 | .sidr h1, .sidr h2, .sidr h3, .sidr h4, .sidr h5, .sidr h6 { 43 | font-size: 11px; 44 | font-weight: normal; 45 | padding: 0 15px; 46 | margin: 0 0 5px; 47 | color: #333333; 48 | line-height: 24px; 49 | background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #dfdfdf)); 50 | background-image: -webkit-linear-gradient(#ffffff, #dfdfdf); 51 | background-image: -moz-linear-gradient(#ffffff, #dfdfdf); 52 | background-image: -o-linear-gradient(#ffffff, #dfdfdf); 53 | background-image: linear-gradient(#ffffff, #dfdfdf); 54 | -webkit-box-shadow: 0 5px 5px 3px rgba(0, 0, 0, 0.2); 55 | -moz-box-shadow: 0 5px 5px 3px rgba(0, 0, 0, 0.2); 56 | box-shadow: 0 5px 5px 3px rgba(0, 0, 0, 0.2); 57 | } 58 | /* line 52, ../../src/scss/sidr/_base.scss */ 59 | .sidr p { 60 | font-size: 13px; 61 | margin: 0 0 12px; 62 | } 63 | /* line 55, ../../src/scss/sidr/_base.scss */ 64 | .sidr p a { 65 | color: rgba(51, 51, 51, 0.9); 66 | } 67 | /* line 60, ../../src/scss/sidr/_base.scss */ 68 | .sidr > p { 69 | margin-left: 15px; 70 | margin-right: 15px; 71 | } 72 | /* line 65, ../../src/scss/sidr/_base.scss */ 73 | .sidr ul { 74 | display: block; 75 | margin: 0 0 15px; 76 | padding: 0; 77 | border-top: 1px solid #dfdfdf; 78 | border-bottom: 1px solid white; 79 | } 80 | /* line 72, ../../src/scss/sidr/_base.scss */ 81 | .sidr ul li { 82 | display: block; 83 | margin: 0; 84 | line-height: 48px; 85 | border-top: 1px solid white; 86 | border-bottom: 1px solid #dfdfdf; 87 | } 88 | /* line 81, ../../src/scss/sidr/_base.scss */ 89 | .sidr ul li:hover, .sidr ul li.active, .sidr ul li.sidr-class-active { 90 | border-top: none; 91 | line-height: 49px; 92 | } 93 | /* line 85, ../../src/scss/sidr/_base.scss */ 94 | .sidr ul li:hover > a, .sidr ul li:hover > span, .sidr ul li.active > a, .sidr ul li.active > span, .sidr ul li.sidr-class-active > a, .sidr ul li.sidr-class-active > span { 95 | -webkit-box-shadow: inset 0 0 15px 3px #ebebeb; 96 | -moz-box-shadow: inset 0 0 15px 3px #ebebeb; 97 | box-shadow: inset 0 0 15px 3px #ebebeb; 98 | } 99 | /* line 90, ../../src/scss/sidr/_base.scss */ 100 | .sidr ul li a, .sidr ul li span { 101 | padding: 0 15px; 102 | display: block; 103 | text-decoration: none; 104 | color: #333333; 105 | } 106 | /* line 97, ../../src/scss/sidr/_base.scss */ 107 | .sidr ul li ul { 108 | border-bottom: none; 109 | margin: 0; 110 | } 111 | /* line 100, ../../src/scss/sidr/_base.scss */ 112 | .sidr ul li ul li { 113 | line-height: 40px; 114 | font-size: 13px; 115 | } 116 | /* line 104, ../../src/scss/sidr/_base.scss */ 117 | .sidr ul li ul li:last-child { 118 | border-bottom: none; 119 | } 120 | /* line 110, ../../src/scss/sidr/_base.scss */ 121 | .sidr ul li ul li:hover, .sidr ul li ul li.active, .sidr ul li ul li.sidr-class-active { 122 | border-top: none; 123 | line-height: 41px; 124 | } 125 | /* line 114, ../../src/scss/sidr/_base.scss */ 126 | .sidr ul li ul li:hover > a, .sidr ul li ul li:hover > span, .sidr ul li ul li.active > a, .sidr ul li ul li.active > span, .sidr ul li ul li.sidr-class-active > a, .sidr ul li ul li.sidr-class-active > span { 127 | -webkit-box-shadow: inset 0 0 15px 3px #ebebeb; 128 | -moz-box-shadow: inset 0 0 15px 3px #ebebeb; 129 | box-shadow: inset 0 0 15px 3px #ebebeb; 130 | } 131 | /* line 119, ../../src/scss/sidr/_base.scss */ 132 | .sidr ul li ul li a, .sidr ul li ul li span { 133 | color: rgba(51, 51, 51, 0.8); 134 | padding-left: 30px; 135 | } 136 | /* line 128, ../../src/scss/sidr/_base.scss */ 137 | .sidr form { 138 | margin: 0 15px; 139 | } 140 | /* line 132, ../../src/scss/sidr/_base.scss */ 141 | .sidr label { 142 | font-size: 13px; 143 | } 144 | /* line 146, ../../src/scss/sidr/_base.scss */ 145 | .sidr input[type="text"], 146 | .sidr input[type="password"], 147 | .sidr input[type="date"], 148 | .sidr input[type="datetime"], 149 | .sidr input[type="email"], 150 | .sidr input[type="number"], 151 | .sidr input[type="search"], 152 | .sidr input[type="tel"], 153 | .sidr input[type="time"], 154 | .sidr input[type="url"], 155 | .sidr textarea, .sidr select { 156 | width: 100%; 157 | font-size: 13px; 158 | padding: 5px; 159 | -webkit-box-sizing: border-box; 160 | -moz-box-sizing: border-box; 161 | box-sizing: border-box; 162 | margin: 0 0 10px; 163 | -webkit-border-radius: 2px; 164 | -moz-border-radius: 2px; 165 | -ms-border-radius: 2px; 166 | -o-border-radius: 2px; 167 | border-radius: 2px; 168 | border: none; 169 | background: rgba(0, 0, 0, 0.1); 170 | color: rgba(51, 51, 51, 0.6); 171 | display: block; 172 | clear: both; 173 | } 174 | /* line 160, ../../src/scss/sidr/_base.scss */ 175 | .sidr input[type=checkbox] { 176 | width: auto; 177 | display: inline; 178 | clear: none; 179 | } 180 | /* line 167, ../../src/scss/sidr/_base.scss */ 181 | .sidr input[type=button], 182 | .sidr input[type=submit] { 183 | color: #f8f8f8; 184 | background: #333333; 185 | } 186 | /* line 171, ../../src/scss/sidr/_base.scss */ 187 | .sidr input[type=button]:hover, 188 | .sidr input[type=submit]:hover { 189 | background: rgba(51, 51, 51, 0.9); 190 | } 191 | -------------------------------------------------------------------------------- /11-load-grunt-tasks/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt Usemin Example 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /11-load-grunt-tasks/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt Usemin Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /11-load-grunt-tasks/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "11-load-grunt-tasks", 3 | "version": "0.0.1", 4 | "description": "Automatically Grunt Tasks from package.json into your Gruntfile.js", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "keywords": "grunt, load-grunt-tasks", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "grunt": "^0.4.5", 18 | "grunt-contrib-concat": "^0.5.0", 19 | "grunt-contrib-copy": "^0.7.0", 20 | "grunt-contrib-cssmin": "^0.11.0", 21 | "grunt-contrib-uglify": "^0.7.0", 22 | "grunt-filerev": "^2.1.2", 23 | "grunt-usemin": "^3.0.0", 24 | "load-grunt-tasks": "^3.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /12-autoprefixer/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | autoprefixer: { 7 | options: { 8 | browsers: ['last 2 versions', 'ie 8', 'ie 9', '> 1%'] 9 | }, 10 | main: { 11 | expand: true, 12 | flatten: true, 13 | src: 'css/*.css', 14 | dest: 'dist/' 15 | } 16 | } 17 | }); 18 | 19 | grunt.registerTask('default', ['autoprefixer']); 20 | }; -------------------------------------------------------------------------------- /12-autoprefixer/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/autoprefixer/ "autoprefixer") 2 | 3 | Grunt AutoPrefixer is a grunt plugin that parses all your css files in your web app and adds vendor specifix prefixes like -webkit- or -moz depending upon [Can I Use](http://caniuse.com/). 4 | Its extremely easy to setup and requires little configuration and is recommended by Google and is actively used by Twitter. 5 | 6 | ## Some of the examples that this plugin can add :- 7 | 8 | The following css property applied on an anchor element 9 | ```css 10 | :fullscreen a { 11 | display: flex; 12 | transition: 1s all; 13 | } 14 | ``` 15 | 16 | will be automatically converted to 17 | 18 | ```css 19 | :-webkit-full-screen a { 20 | display: -webkit-box; 21 | display: -webkit-flex; 22 | display: flex; 23 | -webkit-transition: 1s all; 24 | transition: 1s all; 25 | } 26 | :-moz-full-screen a { 27 | display: flex; 28 | transition: 1s all; 29 | } 30 | :-ms-fullscreen a { 31 | display: -ms-flexbox; 32 | display: flex; 33 | transition: 1s all; 34 | } 35 | :fullscreen a { 36 | display: -webkit-box; 37 | display: -webkit-flex; 38 | display: -ms-flexbox; 39 | display: flex; 40 | -webkit-transition: 1s all; 41 | transition: 1s all; 42 | } 43 | ``` 44 | 45 | It requires autoprefixer-core to be explicitly declared. 46 | To start using this in your build configuration first install it 47 | `npm install grunt-postcss autoprefixer-core --save-dev` 48 | 49 | Here's the grunt file that we have used: 50 | ```js 51 | module.exports = function(grunt) { 52 | 53 | var autoprefixer = require('autoprefixer-core'); 54 | require('load-grunt-tasks')(grunt); 55 | 56 | grunt.initConfig({ 57 | postcss: { 58 | options: { 59 | processors: [ 60 | autoprefixer({ 61 | browers: ['> 0.5%', 'last 2 versions', 'Firefox ESR', 'Opera 12.1'] 62 | }).postcss 63 | ] 64 | }, 65 | dist: { 66 | files: { 67 | 'dist/': 'css/*.css' 68 | } 69 | } 70 | } 71 | }); 72 | 73 | grunt.registerTask('default', ['postcss']); 74 | }; 75 | ``` 76 | 77 | After running grunt on the sample.css inside folder, its replaced by the vendor prefixed version. 78 | 79 | Another great grunt plugin that does the same thing is [grunt-autoprefixer](https://github.com/nDmitry/grunt-autoprefixer). 80 | Its easier to install 81 | `npm install grunt-autoprefixer autoprefixer-core --save-dev` 82 | 83 | According to this configuration: 84 | ```js 85 | autoprefixer: { 86 | options: { 87 | browsers: ['last 2 versions', 'ie 8', 'ie 9', '> 1%'] 88 | }, 89 | main: { 90 | expand: true, 91 | flatten: true, 92 | src: 'css/*.css', 93 | dest: 'dist/' 94 | } 95 | } 96 | ``` 97 | On running Grunt this time, it will scan css/sample.css and vendor prefixes to dist/sample.css. 98 | This is a much better option to keep your source files as clean as possible without browser prefixes or some weird browser behaviours. -------------------------------------------------------------------------------- /12-autoprefixer/css/sample.css: -------------------------------------------------------------------------------- 1 | :fullscreen a { 2 | display: flex; 3 | transition: 1s all; 4 | } -------------------------------------------------------------------------------- /12-autoprefixer/dist/sample.css: -------------------------------------------------------------------------------- 1 | :-webkit-full-screen a { 2 | display: -webkit-box; 3 | display: -webkit-flex; 4 | display: flex; 5 | -webkit-transition: 1s all; 6 | transition: 1s all; 7 | } 8 | :-moz-full-screen a { 9 | display: flex; 10 | transition: 1s all; 11 | } 12 | :-ms-fullscreen a { 13 | display: -ms-flexbox; 14 | display: flex; 15 | transition: 1s all; 16 | } 17 | :fullscreen a { 18 | display: -webkit-box; 19 | display: -webkit-flex; 20 | display: -ms-flexbox; 21 | display: flex; 22 | -webkit-transition: 1s all; 23 | transition: 1s all; 24 | } -------------------------------------------------------------------------------- /12-autoprefixer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "12-autoprefixer", 3 | "version": "0.0.1", 4 | "description": "Automatically prefix all your css files", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "keywords": "grunt, css, autoprefixer", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "autoprefixer-core": "^5.1.7", 18 | "grunt": "^0.4.5", 19 | "grunt-autoprefixer": "^2.2.0", 20 | "load-grunt-tasks": "^3.1.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /13-grunt-responsive-images/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | responsive_images: { 7 | main: { 8 | options: { 9 | engine: 'im' 10 | }, 11 | files: [{ 12 | expand: true, 13 | src: ['img/**/*.{gif,png,jpg,jpge}'], 14 | cwd: 'src/', 15 | dest: 'dist/' 16 | }] 17 | } 18 | }, 19 | responsive_images_extender: { 20 | main: { 21 | options: { 22 | sizes: [{ 23 | selector: 'img', 24 | sizeList: [{ 25 | cond: 'min-width: 300px', 26 | size: '50vw' 27 | }, { 28 | cond: 'min-width: 700px', 29 | size: '70vw' 30 | }, { 31 | cond: 'default', 32 | size: '100vw' 33 | }] 34 | }] 35 | }, 36 | files: [{ 37 | expand: true, 38 | src: ['**/*.{html,htm,php}'], 39 | cwd: 'src/', 40 | dest: 'dist/' 41 | }] 42 | } 43 | } 44 | }); 45 | 46 | grunt.registerTask('default', ['responsive_images', 'responsive_images_extender']); 47 | }; -------------------------------------------------------------------------------- /13-grunt-responsive-images/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/responsive-images/ "grunt responsive images") 2 | 3 | Grunt responsive images is a grunt-js plugin that automatically produces scales images to different sizes for different devices in order to create responsive images. 4 | 5 | Consider a medium based website. As with most new websites image form a big part of it. Now you don't want to load the same image for a person visiting the website on an iMac or his handheld device. You want to deliver the optimum experience on all devices and responsive images form a huge part in that. 6 | 7 | Thats why, browser vendors have come up with a new standard [picture](http://www.html5rocks.com/en/tutorials/responsive/picture-element/) that will solve the responsive images headache. 8 | 9 | Theres also a [demo](http://googlechrome.github.io/samples/picture-element/) available on how to use picture element. 10 | 11 | Instead of manually resizing all images, you can automate this task. Here's how: 12 | 13 | ## Getting Started 14 | 15 | Pre-requirements: You need to have GraphicsMagick or ImageMagick installed on your machine because grunt responsive images depends on this to do the resizing. 16 | If you are using ImageMagick, be sure to specify 'im' in engine in options. 17 | 18 | After that 19 | 20 | `npm install grunt-responsive-images --save-dev` 21 | 22 | This will add the grunt-responsive images in developer dependencies of package.json 23 | Lets say this is your folder-file structure: 24 | ``` 25 | . 26 | ├── dist 27 | ├── Gruntfile.js 28 | ├── index.html 29 | └── src 30 | └── img 31 | └── grunt-usemin.jpg 32 | ``` 33 | Where you have all your development files in your src/ folder and your minified/production files in dist/ 34 | 35 | Add that as a task in your Gruntfile.js 36 | ```js 37 | responsive_images: { 38 | main: { 39 | options: { 40 | engine: 'im', 41 | sizes: [{ 42 | width: 100 43 | }, { 44 | width: 250 45 | }] 46 | }, 47 | files: [{ 48 | expand: true, 49 | src: ['img/**/*.{gif,png,jpg,jpge}'], 50 | cwd: 'src/', 51 | dest: 'dist/' 52 | }] 53 | } 54 | } 55 | ``` 56 | 57 | if you want to have scaled up images you have to add `upscale: true` in the sizes object property. 58 | After you run grunt it will resize the images and put them in img/ 59 | ``` 60 | ├── dist 61 | │   └── img 62 | │   ├── grunt-usemin-400.jpg 63 | │   └── grunt-usemin-800.jpg 64 | ``` 65 | 66 | 67 | But this will only generate the images, not replace them in the src in your html. 68 | Ideally it should do both, replace all img tags with the picture polyfill as well as generate the new images. 69 | 70 | Thankfully, [Stephan Max](http://stephanmax.is/) has written another grunt plugin [grunt-responsive-images-extender](https://github.com/smaxtastic/grunt-responsive-images-extender) to complement grunt-responsive-image 71 | 72 | Similarly, install it and add it to devDependencies 73 | `npm install grunt-responsive-images-extender --save-dev` 74 | 75 | The default options for sizes in both the grunt plugins is 76 | ```js 77 | [{ 78 | name: 'small', width: 320 79 | }, { 80 | name: 'medium', width: 640 81 | },{ 82 | name: 'large', width: 1024 83 | }] 84 | ``` 85 | 86 | This is the grunt task used for responsive images extender: 87 | 88 | ```js 89 | responsive_images_extender: { 90 | main: { 91 | options: { 92 | sizes: [{ 93 | selector: 'img', 94 | sizeList: [{ 95 | cond: 'min-width: 300px', 96 | size: '50vw' 97 | }, { 98 | cond: 'min-width: 700px', 99 | size: '70vw' 100 | }, { 101 | cond: 'default', 102 | size: '100vw' 103 | }] 104 | }] 105 | }, 106 | files: [{ 107 | expand: true, 108 | src: ['**/*.{html,htm,php}'], 109 | cwd: 'src/', 110 | dest: 'dist/' 111 | }] 112 | } 113 | } 114 | ``` 115 | 116 | On running the above `grunt`, it will find all the images as specified in `selector` property and add the corresponding attributes as specified in `sizes`. 117 | In this case I am using the default grunt-responsive-image property of producing three images with suffix large, medium and small. 118 | 119 | 120 | Source: src/index.html 121 | ```html 122 | a cute kitten 123 | ``` 124 | 125 | Production: dist/index.html 126 | ```html 127 | a cute kitten 128 | ``` 129 | 130 | Read more about srcset and sizes [here](http://martinwolf.org/2014/05/07/the-new-srcset-and-sizes-explained/ "srcset") 131 | 132 | Make sure to also add picturefill.js to the head for older browsers. 133 | -------------------------------------------------------------------------------- /13-grunt-responsive-images/dist/img/grunt-usemin-large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/13-grunt-responsive-images/dist/img/grunt-usemin-large.jpg -------------------------------------------------------------------------------- /13-grunt-responsive-images/dist/img/grunt-usemin-medium.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/13-grunt-responsive-images/dist/img/grunt-usemin-medium.jpg -------------------------------------------------------------------------------- /13-grunt-responsive-images/dist/img/grunt-usemin-small.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/13-grunt-responsive-images/dist/img/grunt-usemin-small.jpg -------------------------------------------------------------------------------- /13-grunt-responsive-images/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Using Grunt Responsive Images 6 | 7 | 8 | 9 | 10 | a cute kitten 11 | 12 | -------------------------------------------------------------------------------- /13-grunt-responsive-images/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "13-grunt-responsive-images", 3 | "version": "0.0.1", 4 | "description": "Automatically produce images at different sizes for different images", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "keywords": "grunt, grunt-responsive-images, responsive", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "grunt": "^0.4.5", 18 | "grunt-responsive-images": "^0.1.6", 19 | "grunt-responsive-images-extender": "^1.0.0", 20 | "load-grunt-tasks": "^3.1.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /13-grunt-responsive-images/src/img/grunt-usemin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/13-grunt-responsive-images/src/img/grunt-usemin.jpg -------------------------------------------------------------------------------- /13-grunt-responsive-images/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Using Grunt Responsive Images 6 | 7 | 8 | 9 | 10 | a cute kitten 11 | 12 | -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | 'jsdoc-ng' : { 7 | dist : { 8 | src: ['src/*.js', 'README.md' ], 9 | dest: 'docs', 10 | template : 'jsdoc-ng', 11 | options: { 12 | } 13 | } 14 | } 15 | }); 16 | 17 | grunt.registerTask('default', ['jsdoc-ng']); 18 | }; -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-jsdoc/ "grunt jsdoc") 2 | 3 | Grunt jsdoc-ng is an awesome grunt plugin that allows you to create documentation automatically from your javascript source code in your build process itself. 4 | Bonus point is that the docs which are generated is a single page web app based on angular-js for faster navigation. 5 | 6 | > We wont be using grunt-jsdoc because of [this issue](https://github.com/krampstudio/grunt-jsdoc/issues/124) 7 | 8 | jsdoc is a javascript documentation generation framework used to build custom documentation based on your source code comments. Using its block tags you can have a beautiful documentation of your code/API. 9 | By making use of grunt jsdoc you are removing the work of maintaining your code documentation. It is extremely important to keep your source code documented and an easy to use API. 10 | 11 | > For more information on how to use jsdoc please visit [jsdoc](http://usejsdoc.org/ "jsdoc") 12 | 13 | ![sublime-jsdoc](https://camo.githubusercontent.com/415148aecc6dac2e5ebb12b7f7584f4a8744eca4/687474703a2f2f73706164676f732e6769746875622e696f2f7375626c696d652d6a73646f63732f696d616765732f66756e6374696f6e2d74656d706c6174652e676966 "sublime-jsdoc") 14 | 15 | > If you are using sublime then there's an awesome [plugin](https://github.com/spadgos/sublime-jsdocs) to create comments for your code: 16 | 17 | ## Getting it all set up 18 | 19 | To install grunt-jsdoc-ng: 20 | 21 | `npm install --save-dev grunt-jsdoc-ng` 22 | 23 | Lets consider a simple javascript file `area.js` which encompasses the @Area constructor and its methods and properties. 24 | It has got getters like fetching its width, its height, its total area and setters for setting its width or height. 25 | 26 | Here's the corresponding section in Gruntfile.js 27 | ``` 28 | grunt.initConfig({ 29 | 'jsdoc-ng' : { 30 | dist : { 31 | src: ['src/*.js', 'README.md' ], 32 | dest: 'docs', 33 | template : 'jsdoc-ng', 34 | options: { 35 | } 36 | } 37 | } 38 | }); 39 | ``` 40 | 41 | Here's the source code for area.js: 42 | and here's the [link](https://rawgit.com/kanakiyajay/grunt-tasks/master/14-grunt-jsdoc-ng/docs/index.html#!/Area) to what the generated documentation looks like. 43 | 44 | ```js 45 | "use strict"; 46 | /** 47 | * Creates a new geometrical Area Block 48 | * @param {int} width the width of the area 49 | * @param {int} height the height of the area 50 | */ 51 | function Area(width, height) { 52 | this.width = width; 53 | this.height = height; 54 | 55 | /** 56 | * Returns the width of the area 57 | * @return {int} the width of the area 58 | */ 59 | this.getWidth = function() { 60 | return this.width; 61 | }; 62 | 63 | /** 64 | * Returns the height of the area 65 | * @return {int} the height of the area 66 | */ 67 | this.getHeight = function() { 68 | return this.height; 69 | }; 70 | 71 | /** 72 | * Returns the 2D area of the object 73 | * @return {int} height x width 74 | */ 75 | this.getTotalArea = function() { 76 | return this.height * this.width; 77 | }; 78 | 79 | /** 80 | * Returns whether height or width is greater 81 | * @return {string} 82 | */ 83 | this.getGreater = function() { 84 | var greater = this.height > this.width ? "height" : "width"; 85 | return greater; 86 | }; 87 | 88 | /** 89 | * Changes the Height of the area 90 | * @param {int} ht new height 91 | */ 92 | this.setHeight = function(ht) { 93 | this.height = ht; 94 | return ht; 95 | }; 96 | 97 | /** 98 | * Changes the Width of the area 99 | * @param {int} wd new width 100 | */ 101 | this.setWidth = function(wd) { 102 | this.width = wd; 103 | return wd; 104 | }; 105 | } 106 | ``` 107 | 108 | On running grunt from the command line 109 | 110 | ``` 111 | $ grunt 112 | Invoking JsDoc 113 | Parsing H:\grunt-tasks.com\github\14-grunt-jsdoc-ng\src\area.js ...>> complete. 114 | Generating output files... 115 | >> Output minification enabled 116 | >> Minifying JavaScript output 117 | Writing output files...>> complete. 118 | >> Finished running in 1.21 seconds. 119 | 120 | JsDoc completed 121 | ``` 122 | It will automatically create the documentation from our comments in area.js, format it and output a beautiful html file containing the docs. It will parse our READMEmd file and generate its documentation. 123 | 124 | > In this app, because I am fetching the README.md and posting it on this blog post, the jsdoc documentation generated will also contain the blog post. 125 | 126 | This the final tree structure of our app: 127 | 128 | ``` 129 | . 130 | ├── docs 131 | │   ├── fonts 132 | │   │   ├── fonts.min.css 133 | │   │   ├── LICENSE.txt 134 | │   │   ├── Ubuntu-Bold.ttf 135 | │   │   ├── Ubuntu-BoldItalic.ttf 136 | │   │   ├── Ubuntu-Italic.ttf 137 | │   │   ├── Ubuntu-Light.ttf 138 | │   │   ├── Ubuntu-LightItalic.ttf 139 | │   │   ├── Ubuntu-Medium.ttf 140 | │   │   ├── Ubuntu-MediumItalic.ttf 141 | │   │   ├── UbuntuMono-Bold.ttf 142 | │   │   ├── UbuntuMono-BoldItalic.ttf 143 | │   │   ├── UbuntuMono-Italic.ttf 144 | │   │   ├── UbuntuMono-Regular.ttf 145 | │   │   └── Ubuntu-Regular.ttf 146 | │   ├── index.html 147 | │   ├── jsdoc-ng.data.js 148 | │   ├── jsdoc-ng.min.css 149 | │   ├── jsdoc-ng.min.js 150 | │   └── libs 151 | │   ├── angular.min.js 152 | │   ├── angular.min.js.map 153 | │   ├── highlight.min.css 154 | │   └── highlight.min.js 155 | ├── Gruntfile.js 156 | ├── package.json 157 | ├── README.md 158 | └── src 159 | └── area.js 160 | ``` 161 | 162 | Here'a [link](https://rawgit.com/kanakiyajay/grunt-tasks/master/14-grunt-jsdoc-ng/docs/index.html#!/Area) to the documentation generated and the screenshot is below 163 | 164 | ![grunt-jsdoc-ng](http://i.imgur.com/FoXba8Z.jpg) 165 | 166 | You can find all the other options for grunt-jsdoc-ng below. -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | ------------------------------- 2 | UBUNTU FONT LICENCE Version 1.0 3 | ------------------------------- 4 | 5 | PREAMBLE 6 | This licence allows the licensed fonts to be used, studied, modified and 7 | redistributed freely. The fonts, including any derivative works, can be 8 | bundled, embedded, and redistributed provided the terms of this licence 9 | are met. The fonts and derivatives, however, cannot be released under 10 | any other licence. The requirement for fonts to remain under this 11 | licence does not require any document created using the fonts or their 12 | derivatives to be published under this licence, as long as the primary 13 | purpose of the document is not to be a vehicle for the distribution of 14 | the fonts. 15 | 16 | DEFINITIONS 17 | "Font Software" refers to the set of files released by the Copyright 18 | Holder(s) under this licence and clearly marked as such. This may 19 | include source files, build scripts and documentation. 20 | 21 | "Original Version" refers to the collection of Font Software components 22 | as received under this licence. 23 | 24 | "Modified Version" refers to any derivative made by adding to, deleting, 25 | or substituting -- in part or in whole -- any of the components of the 26 | Original Version, by changing formats or by porting the Font Software to 27 | a new environment. 28 | 29 | "Copyright Holder(s)" refers to all individuals and companies who have a 30 | copyright ownership of the Font Software. 31 | 32 | "Substantially Changed" refers to Modified Versions which can be easily 33 | identified as dissimilar to the Font Software by users of the Font 34 | Software comparing the Original Version with the Modified Version. 35 | 36 | To "Propagate" a work means to do anything with it that, without 37 | permission, would make you directly or secondarily liable for 38 | infringement under applicable copyright law, except executing it on a 39 | computer or modifying a private copy. Propagation includes copying, 40 | distribution (with or without modification and with or without charging 41 | a redistribution fee), making available to the public, and in some 42 | countries other activities as well. 43 | 44 | PERMISSION & CONDITIONS 45 | This licence does not grant any rights under trademark law and all such 46 | rights are reserved. 47 | 48 | Permission is hereby granted, free of charge, to any person obtaining a 49 | copy of the Font Software, to propagate the Font Software, subject to 50 | the below conditions: 51 | 52 | 1) Each copy of the Font Software must contain the above copyright 53 | notice and this licence. These can be included either as stand-alone 54 | text files, human-readable headers or in the appropriate machine- 55 | readable metadata fields within text or binary files as long as those 56 | fields can be easily viewed by the user. 57 | 58 | 2) The font name complies with the following: 59 | (a) The Original Version must retain its name, unmodified. 60 | (b) Modified Versions which are Substantially Changed must be renamed to 61 | avoid use of the name of the Original Version or similar names entirely. 62 | (c) Modified Versions which are not Substantially Changed must be 63 | renamed to both (i) retain the name of the Original Version and (ii) add 64 | additional naming elements to distinguish the Modified Version from the 65 | Original Version. The name of such Modified Versions must be the name of 66 | the Original Version, with "derivative X" where X represents the name of 67 | the new work, appended to that name. 68 | 69 | 3) The name(s) of the Copyright Holder(s) and any contributor to the 70 | Font Software shall not be used to promote, endorse or advertise any 71 | Modified Version, except (i) as required by this licence, (ii) to 72 | acknowledge the contribution(s) of the Copyright Holder(s) or (iii) with 73 | their explicit written permission. 74 | 75 | 4) The Font Software, modified or unmodified, in part or in whole, must 76 | be distributed entirely under this licence, and must not be distributed 77 | under any other licence. The requirement for fonts to remain under this 78 | licence does not affect any document created using the Font Software, 79 | except any version of the Font Software extracted from a document 80 | created using the Font Software may only be distributed under this 81 | licence. 82 | 83 | TERMINATION 84 | This licence becomes null and void if any of the above conditions are 85 | not met. 86 | 87 | DISCLAIMER 88 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 89 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 90 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF 91 | COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 92 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 93 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 94 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 95 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER 96 | DEALINGS IN THE FONT SOFTWARE. 97 | -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Bold.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-BoldItalic.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Italic.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Light.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-LightItalic.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Medium.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-MediumItalic.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/Ubuntu-Regular.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-Bold.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-BoldItalic.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-Italic.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/14-grunt-jsdoc-ng/docs/fonts/UbuntuMono-Regular.ttf -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/fonts/fonts.min.css: -------------------------------------------------------------------------------- 1 | @font-face{font-family:'Ubuntu';font-style:normal;font-weight:300;src:local('Ubuntu Light'),local('Ubuntu-Light'),url(Ubuntu-Light.ttf) format('truetype')}@font-face{font-family:'Ubuntu';font-style:normal;font-weight:400;src:local('Ubuntu'),url(Ubuntu-Regular.ttf) format('truetype')}@font-face{font-family:'Ubuntu';font-style:normal;font-weight:700;src:local('Ubuntu Bold'),local('Ubuntu-Bold'),url(Ubuntu-Bold.ttf) format('truetype')}@font-face{font-family:'Ubuntu';font-style:italic;font-weight:300;src:local('Ubuntu Light Italic'),local('Ubuntu-LightItalic'),url(Ubuntu-LightItalic.ttf) format('truetype')}@font-face{font-family:'Ubuntu';font-style:italic;font-weight:400;src:local('Ubuntu Italic'),local('Ubuntu-Italic'),url(Ubuntu-Italic.ttf) format('truetype')}@font-face{font-family:'Ubuntu';font-style:italic;font-weight:700;src:local('Ubuntu Bold Italic'),local('Ubuntu-BoldItalic'),url(Ubuntu-BoldItalic.ttf) format('truetype')}@font-face{font-family:'Ubuntu Mono';font-style:normal;font-weight:400;src:local('Ubuntu Mono'),local('UbuntuMono-Regular'),url(UbuntuMono-Regular.ttf) format('truetype')}@font-face{font-family:'Ubuntu Mono';font-style:normal;font-weight:700;src:local('Ubuntu Mono Bold'),local('UbuntuMono-Bold'),url(UbuntuMono-Bold.ttf) format('truetype')}@font-face{font-family:'Ubuntu Mono';font-style:italic;font-weight:400;src:local('Ubuntu Mono Italic'),local('UbuntuMono-Italic'),url(UbuntuMono-Italic.ttf) format('truetype')}@font-face{font-family:'Ubuntu Mono';font-style:italic;font-weight:700;src:local('Ubuntu Mono Bold Italic'),local('UbuntuMono-BoldItalic'),url(UbuntuMono-BoldItalic.ttf) format('truetype')} -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/index.html: -------------------------------------------------------------------------------- 1 | Automatically create beautiful html documentation from your source code documentation (v. 0.0.1)
-------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/jsdoc-ng.data.js: -------------------------------------------------------------------------------- 1 | !function(){angular.module("jsDocNG-Data",[]).constant("$title","Automatically create beautiful html documentation from your source code documentation (v. 0.0.1)").constant("$readme",'

Blog post

Grunt jsdoc-ng is an awesome grunt plugin that allows you to create documentation automatically from your javascript source code in your build process itself.\nBonus point is that the docs which are generated is a single page web app based on angular-js for faster navigation.

\n
\n

We wont be using grunt-jsdoc because of this issue

\n
\n

jsdoc is a javascript documentation generation framework used to build custom documentation based on your source code comments. Using its block tags you can have a beautiful documentation of your code/API.\nBy making use of grunt jsdoc you are removing the work of maintaining your code documentation. It is extremely important to keep your source code documented and an easy to use API.

\n
\n

For more information on how to use jsdoc please visit jsdoc

\n
\n

sublime-jsdoc

\n
\n

If you are using sublime then there\'s an awesome plugin to create comments for your code:

\n
\n

Getting it all set up

To install grunt-jsdoc-ng:

\n

npm install --save-dev grunt-jsdoc-ng

\n

Lets consider a simple javascript file area.js which encompasses the @Area constructor and its methods and properties.\nIt has got getters like fetching its width, its height, its total area and setters for setting its width or height.

\n

Here\'s the corresponding section in Gruntfile.js

\n
 grunt.initConfig({\n    \'jsdoc-ng\' : {\n      dist : {\n        src: [\'src/*.js\', \'README.md\' ],\n        dest: \'docs\',\n        template : \'jsdoc-ng\',\n        options: {\n        }\n      }\n    }\n  });

Here\'s the source code for area.js:

\n
(function () {\n  "use strict";\n  /**\n   * Creates a new geometrical Area Block\n   * @param {int} width  the width of the area\n   * @param {int} height the height of the area\n   */\n  function Area(width, height) {\n    this.width = width;\n    this.height = height;\n\n    /**\n     * Returns the width of the area\n     * @return {int}      the width of the area\n     */\n    this.getWidth = function() {\n      return this.width;\n    };\n\n    /**\n     * Returns the height of the area\n     * @return {int}      the height of the area\n     */\n    this.getHeight = function() {\n      return this.height;\n    };\n\n    /**\n     * Returns the 2D area of the object\n     * @return {int} height x width\n     */\n    this.getTotalArea = function() {\n      return this.height * this.width;\n    };\n\n    /**\n     * Returns whether height or width is greater\n     * @return {string}\n     */\n    this.getGreater = function() {\n      var greater = this.height > this.width ? "height" : "width";\n      return greater;\n    };\n\n    /**\n     * Changes the Height of the area\n     * @param {int} ht new height\n     */\n    this.setHeight = function(ht) {\n      this.height = ht;\n      return ht;\n    };\n\n    /**\n     * Changes the Width of the area\n     * @param {int} wd new width\n     */\n    this.setWidth = function(wd) {\n      this.width = wd;\n      return wd;\n    };\n  }\n})();
').constant("$doclets",[{kind:"class",name:"Area",longname:"Area",scope:"global",$href:"Area",$id:"T000002R000002"},{description:"Width of the area",type:{names:["int"]},name:"width",longname:"Area#width",kind:"member",memberof:"Area",scope:"instance",$href:"Area#width",$id:"T000002R000003"},{description:"Height of the area",type:{names:["int"]},name:"height",longname:"Area#height",kind:"member",memberof:"Area",scope:"instance",$href:"Area#height",$id:"T000002R000004"},{description:"Returns the width of the area",returns:[{type:{names:["int"]},description:"the width of the area"}],name:"getWidth",longname:"Area#getWidth",kind:"function",memberof:"Area",scope:"instance",$href:"Area#getWidth",$id:"T000002R000005"},{description:"Returns the height of the area",returns:[{type:{names:["int"]},description:"the height of the area"}],name:"getHeight",longname:"Area#getHeight",kind:"function",memberof:"Area",scope:"instance",$href:"Area#getHeight",$id:"T000002R000006"},{description:"Returns the 2D area of the object",returns:[{type:{names:["int"]},description:"height x width"}],name:"getTotalArea",longname:"Area#getTotalArea",kind:"function",memberof:"Area",scope:"instance",$href:"Area#getTotalArea",$id:"T000002R000007"},{description:"Returns whether height or width is greater",returns:[{type:{names:["string"]}}],name:"getGreater",longname:"Area#getGreater",kind:"function",memberof:"Area",scope:"instance",$href:"Area#getGreater",$id:"T000002R000008"},{description:"Changes the Height of the area",params:[{type:{names:["int"]},description:"new height",name:"ht"}],name:"setHeight",longname:"Area#setHeight",kind:"function",memberof:"Area",scope:"instance",$href:"Area#setHeight",$id:"T000002R000010"},{description:"Changes the Width of the area",params:[{type:{names:["int"]},description:"new width",name:"wd"}],name:"setWidth",longname:"Area#setWidth",kind:"function",memberof:"Area",scope:"instance",$href:"Area#setWidth",$id:"T000002R000012"}])}(); -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/jsdoc-ng.min.css: -------------------------------------------------------------------------------- 1 | html,body{font-family:'Ubuntu','Helvetica','Arial',sans-serif;font-size:14px;font-weight:400;height:100%;margin:0px;padding:0px}div.nav{position:fixed;overflow:scroll;top:0px;bottom:0px;left:0px;width:250px;padding:10px 10px 50px 10px;margin:0px}div.content{margin-left:270px;padding:10px 30px 10px 20px}pre,code{font-family:'Ubuntu Mono','Courier New','Courier',monospace}pre code{border:none}.nojsdoc{display:none}.jsdoc-ng-link{text-align:center;color:#666;margin-top:30px;font-size:0.8em}.jsdoc-ng-link:before{content:"\A0";border-top:1px solid #ccc;margin:50px 30% 10px 30%;display:block}a{color:#669;text-decoration:none}a:hover{text-decoration:underline}a:visited{color:#669}a code{color:#339}code{background-color:#eee;border:1px solid #ccc;border-radius:4px;padding:1px 4px;color:#333}pre{border:1px solid #999;background-color:#eee;padding:10px;overflow:scroll;line-height:1.1em}div.nav{background-color:#333;font-weight:300;color:#666}div.nav a{color:#ccc;text-decoration:none}div.nav a:hover{text-decoration:underline}div.nav a:visited{color:#ccc}div.nav .title{font-size:16px;font-weight:700;padding-bottom:10px;border-bottom:1px solid #444}div.nav .kind-function::after{content:'(\2026)';padding-left:0.2em}div.nav ul.nav{list-style:none;padding:0px 0px 0px 10px;margin:0px}div.nav ul.nav.top{padding-left:0px}div.nav ul.nav.top>li{margin-top:20px}div.nav ul.nav.top .header.module::after{content:"module";font-size:0.8em;padding-left:1em}div.nav ul.nav.group{border-left:1px solid #444;margin:10px 0px 10px 5px}div.nav ul.nav.group>li{margin-left:10px;padding:2px 0px 2px 10px}div.nav ul.nav.group>li.expanded{background-color:rgba(0,0,0,0.1);border-radius:4px;margin-right:10px}div.nav ul.nav.group>li.header{margin:5px 0px;text-transform:uppercase;font-weight:bold;font-size:10px;color:#888}div.nav ul.nav.expanded{padding:0px 0px 10px 10px}div.nav ul.nav.expanded .static{position:relative}div.nav ul.nav.expanded .static:before{content:"S";display:block;position:absolute;text-align:center;width:10px;min-width:10px;max-width:10px;height:10px;min-height:10px;max-height:10px;overflow:hide;top:2px;left:-16px;font-size:7px;padding:1px 0px 0px 0px;font-weight:bold;font-style:normal;background-color:rgba(255,255,255,0.1);border:1px solid rgba(255,255,255,0.2);border-radius:3px;color:#999;opacity:0.5}div.nav ul.nav.expanded>li{margin:2px 0px 2px 20px}div.nav ul.nav.expanded>li.header{margin:5px 0px 5px 10px;text-transform:uppercase;font-weight:bold;font-size:10px;color:#888}div.content h1{font-size:36px}div.content h2{font-size:24px;padding-top:20px;margin-top:20px}div.content h2:before{content:"\A0";border-top:1px solid #ccc;margin:0px 30% 10px 30%;display:block}div.content h3{font-size:18px;margin-top:30px;padding:10px;background-color:#eee;border:1px solid #ccc;border-radius:4px}div.content h3 .extra{position:relative;top:-2px;font-size:10px;font-weight:300;border:1px solid #aaa;background-color:#bbb;border-radius:4px;margin-left:10px;color:#fff;padding:2px}div.content h3 .types{margin-left:10px;margin-right:0px;font-size:12px;position:relative;top:-1px}div.content h4{color:#666}div.content h1.literal,div.content h3.literal{font-family:'Ubuntu Mono','Courier New','Courier',monospace;color:#999;font-weight:300}div.content h1.literal .kind,div.content h3.literal .kind{font-family:'Ubuntu','Helvetica','Arial',sans-serif;font-size:0.6em;font-style:italic}div.content h1.literal .prefix,div.content h3.literal .prefix{font-family:'Ubuntu','Helvetica','Arial',sans-serif;font-size:0.6em;font-weight:300}div.content h1.literal .name,div.content h3.literal .name{color:#000;font-weight:700;font-style:normal}div.content h1.literal .param,div.content h3.literal .param{color:#444;font-weight:400;font-style:normal}div.content .details{margin-left:10px;padding-left:10px;border-left:1px solid #ccc}div.content ul.parameters li,div.content ul.returns li,div.content ul.types li{margin:6px 0px;line-height:20px;text-indent:-50px;padding-left:50px}div.content ul.parameters li p,div.content ul.returns li p,div.content ul.types li p{display:inline}div.content ul.parameters .name,div.content ul.returns .name,div.content ul.types .name{font-family:'Ubuntu Mono','Courier New','Courier',monospace;background-color:#eee;border:1px solid #ccc;border-radius:4px;padding:1px 4px;margin-right:10px}div.content ul.parameters .extra,div.content ul.returns .extra,div.content ul.types .extra{text-transform:uppercase;background-color:#eef;border:1px solid #ccf;color:#99f;font-style:italic;font-weight:300;font-size:10px;border-radius:4px;padding:3px 4px 2px 3px;margin-right:10px;position:relative;top:-1px}div.content .types{font-family:'Ubuntu Mono','Courier New','Courier',monospace;background-color:#fee;border:1px solid #fcc;border-radius:10px;padding:1px 10px;margin-right:10px}div.content .types .type{color:#944;margin-left:5px;border-left:1px solid #fbb;padding-left:5px}div.content .types .type:first-child{margin:0px;padding:0px;border:none}div.content .types .type a{color:#944}div.content .types .type a.visited{color:#944}div.content .example .container{position:relative}div.content .example .container .language{position:absolute;font-size:12px;padding:3px 6px 4px 6px;border-left:1px solid #999;border-right:1px solid #999;border-bottom:1px solid #999;border-bottom-left-radius:4px;border-bottom-right-radius:4px;background-color:#aaa;font-weight:300;color:#fff;right:10px;top:1px} -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/docs/libs/highlight.min.css: -------------------------------------------------------------------------------- 1 | .hljs{display:block;overflow-x:auto;padding:.5em;background:#f0f0f0;-webkit-text-size-adjust:none}.hljs,.hljs-subst,.hljs-tag .hljs-title,.nginx .hljs-title{color:#000}.hljs-string,.hljs-title,.hljs-constant,.hljs-parent,.hljs-tag .hljs-value,.hljs-rules .hljs-value,.hljs-preprocessor,.hljs-pragma,.haml .hljs-symbol,.ruby .hljs-symbol,.ruby .hljs-symbol .hljs-string,.hljs-template_tag,.django .hljs-variable,.smalltalk .hljs-class,.hljs-addition,.hljs-flow,.hljs-stream,.bash .hljs-variable,.apache .hljs-tag,.apache .hljs-cbracket,.tex .hljs-command,.tex .hljs-special,.erlang_repl .hljs-function_or_atom,.asciidoc .hljs-header,.markdown .hljs-header,.coffeescript .hljs-attribute{color:#800}.smartquote,.hljs-comment,.hljs-annotation,.hljs-template_comment,.diff .hljs-header,.hljs-chunk,.asciidoc .hljs-blockquote,.markdown .hljs-blockquote{color:#888}.hljs-number,.hljs-date,.hljs-regexp,.hljs-literal,.hljs-hexcolor,.smalltalk .hljs-symbol,.smalltalk .hljs-char,.go .hljs-constant,.hljs-change,.lasso .hljs-variable,.makefile .hljs-variable,.asciidoc .hljs-bullet,.markdown .hljs-bullet,.asciidoc .hljs-link_url,.markdown .hljs-link_url{color:#080}.hljs-label,.hljs-javadoc,.ruby .hljs-string,.hljs-decorator,.hljs-filter .hljs-argument,.hljs-localvars,.hljs-array,.hljs-attr_selector,.hljs-important,.hljs-pseudo,.hljs-pi,.haml .hljs-bullet,.hljs-doctype,.hljs-deletion,.hljs-envvar,.hljs-shebang,.apache .hljs-sqbracket,.nginx .hljs-built_in,.tex .hljs-formula,.erlang_repl .hljs-reserved,.hljs-prompt,.asciidoc .hljs-link_label,.markdown .hljs-link_label,.vhdl .hljs-attribute,.clojure .hljs-attribute,.asciidoc .hljs-attribute,.lasso .hljs-attribute,.coffeescript .hljs-property,.hljs-phony{color:#88f}.hljs-keyword,.hljs-id,.hljs-title,.hljs-built_in,.css .hljs-tag,.hljs-javadoctag,.hljs-phpdoc,.hljs-dartdoc,.hljs-yardoctag,.smalltalk .hljs-class,.hljs-winutils,.bash .hljs-variable,.apache .hljs-tag,.hljs-type,.hljs-typename,.tex .hljs-command,.asciidoc .hljs-strong,.markdown .hljs-strong,.hljs-request,.hljs-status{font-weight:bold}.asciidoc .hljs-emphasis,.markdown .hljs-emphasis{font-style:italic}.nginx .hljs-built_in{font-weight:normal}.coffeescript .javascript,.javascript .xml,.lasso .markup,.tex .hljs-formula,.xml .javascript,.xml .vbscript,.xml .css,.xml .hljs-cdata{opacity:.5} -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "14-grunt-jsdoc", 3 | "version": "0.0.1", 4 | "description": "Automatically create beautiful html documentation from your source code documentation", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "keywords": "grunt, jsdoc, grunt-jsdoc, documentation", 15 | "license": "ISC", 16 | "devDependencies": { 17 | "grunt": "^0.4.5", 18 | "load-grunt-tasks": "^3.1.0", 19 | "grunt-jsdoc-ng": "0.0.3" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /14-grunt-jsdoc-ng/src/area.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /** 3 | * @constructor 4 | */ 5 | function Area(width, height) { 6 | 7 | /** 8 | * Width of the area 9 | * @type {int} 10 | */ 11 | this.width = width; 12 | 13 | /** 14 | * Height of the area 15 | * @type {int} 16 | */ 17 | this.height = height; 18 | 19 | /** 20 | * Returns the width of the area 21 | * @return {int} the width of the area 22 | */ 23 | this.getWidth = function() { 24 | return this.width; 25 | }; 26 | 27 | /** 28 | * Returns the height of the area 29 | * @return {int} the height of the area 30 | */ 31 | this.getHeight = function() { 32 | return this.height; 33 | }; 34 | 35 | /** 36 | * Returns the 2D area of the object 37 | * @return {int} height x width 38 | */ 39 | this.getTotalArea = function() { 40 | return this.height * this.width; 41 | }; 42 | 43 | /** 44 | * Returns whether height or width is greater 45 | * @return {string} 46 | */ 47 | this.getGreater = function() { 48 | var greater = this.height > this.width ? "height" : "width"; 49 | return greater; 50 | }; 51 | 52 | /** 53 | * Changes the Height of the area 54 | * @param {int} ht new height 55 | */ 56 | this.setHeight = function(ht) { 57 | this.height = ht; 58 | return ht; 59 | }; 60 | 61 | /** 62 | * Changes the Width of the area 63 | * @param {int} wd new width 64 | */ 65 | this.setWidth = function(wd) { 66 | this.width = wd; 67 | return wd; 68 | }; 69 | } -------------------------------------------------------------------------------- /15-grunt-remove-logging-calls/.gitignore: -------------------------------------------------------------------------------- 1 | dist/* -------------------------------------------------------------------------------- /15-grunt-remove-logging-calls/.tmp/concat/js/script.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $("#submit").on("click", function() { 3 | console.log("Submit Button Clicked"); 4 | }); 5 | }); -------------------------------------------------------------------------------- /15-grunt-remove-logging-calls/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | copy: { 7 | generated: { 8 | src: 'index.html', 9 | dest: 'dist/index.html' 10 | } 11 | }, 12 | filerev: { 13 | options: { 14 | encoding: 'utf8', 15 | algorithm: 'md5', 16 | length: 20 17 | }, 18 | source: { 19 | files: [{ 20 | src: [ 21 | 'dist/js/*.js', 22 | 'dist/css/*.css' 23 | ] 24 | }] 25 | } 26 | }, 27 | useminPrepare: { 28 | html: 'index.html', 29 | options: { 30 | dest: 'dist' 31 | } 32 | }, 33 | usemin: { 34 | html: 'dist/index.html', 35 | options: { 36 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 37 | } 38 | }, 39 | removeLoggingCalls: { 40 | files: ['dist/js/*.js'], 41 | options: { 42 | methods: ['log', 'info', 'assert'], 43 | strategy: function(consoleStatement) { 44 | return 'if(window.DEBUG){' + consoleStatement + '}debugVar'; 45 | } 46 | } 47 | } 48 | }); 49 | 50 | grunt.registerTask('default', [ 51 | 'copy:generated', 52 | 'useminPrepare', 53 | 'concat', 54 | 'uglify', 55 | 'cssmin', 56 | 'filerev', 57 | 'usemin', 58 | 'removeLoggingCalls' 59 | ]); 60 | }; -------------------------------------------------------------------------------- /15-grunt-remove-logging-calls/css/mystyle.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/15-grunt-remove-logging-calls/css/mystyle.css -------------------------------------------------------------------------------- /15-grunt-remove-logging-calls/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt Remove Logging 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /15-grunt-remove-logging-calls/js/myscript.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $("#submit").on("click", function() { 3 | console.log("Submit Button Clicked"); 4 | }); 5 | }); -------------------------------------------------------------------------------- /15-grunt-remove-logging-calls/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "15-grunt-remove-logging", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to remove console.log statements", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-concat": "^0.5.0", 18 | "grunt-contrib-copy": "^0.7.0", 19 | "grunt-contrib-cssmin": "^0.11.0", 20 | "grunt-contrib-uglify": "^0.7.0", 21 | "grunt-filerev": "^2.1.2", 22 | "grunt-remove-logging": "^0.2.0", 23 | "grunt-remove-logging-calls": "^0.1.0", 24 | "grunt-usemin": "^3.0.0", 25 | "load-grunt-tasks": "^3.1.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /16-grunt-csscomb/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | csscomb: { 7 | dist: { 8 | files: { 9 | 'css/style.comb.css': ['css/style.css'] 10 | } 11 | } 12 | } 13 | }); 14 | 15 | grunt.registerTask('default', [ 16 | 'csscomb' 17 | ]); 18 | }; -------------------------------------------------------------------------------- /16-grunt-csscomb/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-css-comb/ "grunt css comb") 2 | 3 | Grunt Css Comb is a grunt plugin that helps you beautify your css by arranging and formatting the properties as well as the selectors for more maintainable stylesheets. 4 | It even helps to keep a *consistent* css coding style across all projects. The coding style might include naming, organizing,order in which selectors are defined, the way and order in which properties are defined. 5 | 6 | Some other benefits also include: 7 | 8 | - Maintainable and easier debuggable code 9 | - Reading and tweaking css becomes easier 10 | - Will also prevent unknown or accidental syntax errors. 11 | 12 | There is a great [post](http://www.smashingmagazine.com/2012/10/02/csscomb-tool-sort-css-properties/ "csscomb") explaining the algorithms and csscomb in more detail. 13 | 14 | ## Getting Started 15 | 16 | Depending upon your use case, To install this in your project, run 17 | `npm install grunt-csscomb --save-dev` 18 | 19 | We are going to consider a very basic html file and its css file. 20 | Heres the [codepen](http://codepen.io/kanakiyajay/pen/gbZZbb) for the demo index.html 21 | The grunt task should create a new file `css/style.comb.css` and apply all the configurations to it. 22 | 23 | Here's the grunt task: 24 | 25 | ```js 26 | csscomb: { 27 | dist: { 28 | files: { 29 | 'css/style.comb.css': ['css/style.css'] 30 | } 31 | } 32 | } 33 | ``` 34 | There are many css style guidelines that companies use, according to which you can different csscomb configurations. 35 | In your project root folder, you can have `.csscomb.json` where you can define your csscomb properties. 36 | Here's is the config file I use: 37 | 38 | ```js 39 | { 40 | "exclude": [ 41 | ".git/**", 42 | "node_modules/**", 43 | "bower_components/**" 44 | ], 45 | "remove-empty-rulesets": true, 46 | "always-semicolon": true, 47 | "color-case": "lower", 48 | "block-indent": " ", 49 | "element-case": "lower", 50 | "eof-newline": true, 51 | "leading-zero": true, 52 | "quotes": "single", 53 | "sort-order-fallback": "abc", 54 | "space-before-colon": " ", 55 | "space-after-colon": " ", 56 | "space-before-combinator": " ", 57 | "space-after-combinator": " ", 58 | "space-between-declarations": "\n", 59 | "space-before-opening-brace": " ", 60 | "space-after-opening-brace": "\n", 61 | "space-after-selector-delimiter": "\n", 62 | "space-before-selector-delimiter": "", 63 | "space-before-closing-brace": "\n", 64 | "strip-spaces": true, 65 | "tab-size": true, 66 | "unitless-zero": true, 67 | "vendor-prefix-align": true, 68 | "sort-order": "..." 69 | } 70 | ``` 71 | 72 | You will find the whole csscomb.json file [here](https://github.com/kanakiyajay/grunt-tasks/blob/master/16-grunt-csscomb/.csscomb.json) 73 | 74 | There's is an awesome builder for this available [online](http://csscomb.com/config "csscomb config") 75 | 76 | Below is the css properties before applying codepen: 77 | 78 | ```css 79 | body { 80 | max-width: 960px; 81 | margin: 0 auto; 82 | font-family: "Verdana", sans-serif, Arial; 83 | } 84 | 85 | h1 { 86 | margin-bottom: 2em; 87 | margin-top: 2em; 88 | text-align: center; 89 | } 90 | 91 | .para { 92 | margin-bottom: 10px; 93 | font-size: 1.1em; 94 | } 95 | 96 | blockquote { 97 | font-family: 1.3em; 98 | padding: 10px; 99 | margin: 10px; 100 | background-color: #ccc; 101 | padding-left: 20px; 102 | } 103 | 104 | #submit { 105 | cursor: pointer; 106 | padding: 10px; 107 | border: 0; 108 | margin: 0; 109 | font-size: 1.1em; 110 | color: darkgray; 111 | } 112 | 113 | #list { 114 | list-style-type: none; 115 | } 116 | 117 | label { 118 | padding-left: 10px; 119 | } 120 | 121 | #list li { 122 | margin: 5px; 123 | font-size: 1.1em; 124 | padding-left: 10px; 125 | border-left: 1px solid gray; 126 | } 127 | 128 | #txt, #txta { 129 | margin: 10px; 130 | font-size: 1.1em; 131 | } 132 | ``` 133 | 134 | After running grunt: 135 | 136 | ``` 137 | $ grunt 138 | Running "csscomb:dist" (csscomb) task 139 | >> Using custom config file "H:\grunt-tasks.com\github\16-grunt-csscomb\.csscomb.json"... 140 | >> Sorting file "css/style.css"... 141 | 142 | Done, without errors. 143 | ``` 144 | 145 | Here is final output css. 146 | 147 | ```css 148 | body { 149 | font-family : 'Verdana', sans-serif, Arial; 150 | max-width : 960px; 151 | margin : 0 auto; 152 | } 153 | 154 | h1 { 155 | margin-top : 2em; 156 | margin-bottom : 2em; 157 | text-align : center; 158 | } 159 | 160 | .para { 161 | font-size : 1.1em; 162 | margin-bottom : 10px; 163 | } 164 | 165 | blockquote { 166 | font-family : 1.3em; 167 | margin : 10px; 168 | padding : 10px; 169 | padding-left : 20px; 170 | background-color : #ccc; 171 | } 172 | 173 | #submit { 174 | font-size : 1.1em; 175 | margin : 0; 176 | padding : 10px; 177 | cursor : pointer; 178 | color : darkgray; 179 | border : 0; 180 | } 181 | 182 | #list { 183 | list-style-type : none; 184 | } 185 | 186 | label { 187 | padding-left : 10px; 188 | } 189 | 190 | #list li { 191 | font-size : 1.1em; 192 | margin : 5px; 193 | padding-left : 10px; 194 | border-left : 1px solid gray; 195 | } 196 | 197 | #txt, 198 | #txta { 199 | font-size : 1.1em; 200 | margin : 10px; 201 | } 202 | ``` 203 | 204 | The above css properties have been sorted perfectly according to our configuration, indentation has only been changed to match what was in our project. This leads to a cleaner, more maintainable css. 205 | 206 | If you have any other use cases regarding css comb or a better way to use in grunt, please leave a comment below. -------------------------------------------------------------------------------- /16-grunt-csscomb/css/style.comb.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family : 'Verdana', sans-serif, Arial; 3 | max-width : 960px; 4 | margin : 0 auto; 5 | } 6 | 7 | h1 { 8 | margin-top : 2em; 9 | margin-bottom : 2em; 10 | text-align : center; 11 | } 12 | 13 | .para { 14 | font-size : 1.1em; 15 | margin-bottom : 10px; 16 | } 17 | 18 | blockquote { 19 | font-family : 1.3em; 20 | margin : 10px; 21 | padding : 10px; 22 | padding-left : 20px; 23 | background-color : #ccc; 24 | } 25 | 26 | #submit { 27 | font-size : 1.1em; 28 | margin : 0; 29 | padding : 10px; 30 | cursor : pointer; 31 | color : darkgray; 32 | border : 0; 33 | } 34 | 35 | #list { 36 | list-style-type : none; 37 | } 38 | 39 | label { 40 | padding-left : 10px; 41 | } 42 | 43 | #list li { 44 | font-size : 1.1em; 45 | margin : 5px; 46 | padding-left : 10px; 47 | border-left : 1px solid gray; 48 | } 49 | 50 | #txt, 51 | #txta { 52 | font-size : 1.1em; 53 | margin : 10px; 54 | } 55 | -------------------------------------------------------------------------------- /16-grunt-csscomb/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | max-width: 960px; 3 | margin: 0 auto; 4 | font-family: "Verdana", sans-serif, Arial; 5 | } 6 | 7 | h1 { 8 | margin-bottom: 2em; 9 | margin-top: 2em; 10 | text-align: center; 11 | } 12 | 13 | .para { 14 | margin-bottom: 10px; 15 | font-size: 1.1em; 16 | } 17 | 18 | blockquote { 19 | font-family: 1.3em; 20 | padding: 10px; 21 | margin: 10px; 22 | background-color: #ccc; 23 | padding-left: 20px; 24 | } 25 | 26 | #submit { 27 | cursor: pointer; 28 | padding: 10px; 29 | border: 0; 30 | margin: 0; 31 | font-size: 1.1em; 32 | color: darkgray; 33 | } 34 | 35 | #list { 36 | list-style-type: none; 37 | } 38 | 39 | label { 40 | padding-left: 10px; 41 | } 42 | 43 | #list li { 44 | margin: 5px; 45 | font-size: 1.1em; 46 | padding-left: 10px; 47 | border-left: 1px solid gray; 48 | } 49 | 50 | #txt, #txta { 51 | margin: 10px; 52 | font-size: 1.1em; 53 | } -------------------------------------------------------------------------------- /16-grunt-csscomb/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt CssComb 6 | 7 | 8 | 9 |

A tutorial on how to use Grunt Css Comb

10 |

Some random paragraph describing how to use grunt css comb

11 | 12 | 19 |
20 | "An awesome quote by a famous personality" 21 |
22 |
23 | 24 | 25 |
26 | 27 |
28 | 29 | -------------------------------------------------------------------------------- /16-grunt-csscomb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "16-grunt-csscomb", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to make your css more beautiful", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-csscomb": "^3.0.0", 18 | "load-grunt-tasks": "^3.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /17-grunt-jsonlint/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | jsonlint: { 7 | sample: { 8 | src: ['data/cities.json', 'config/config.json'] 9 | } 10 | } 11 | }); 12 | 13 | grunt.registerTask('default', ['jsonlint']); 14 | }; -------------------------------------------------------------------------------- /17-grunt-jsonlint/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-jsonlint/ "grunt jsonlint") 2 | 3 | Grunt-jsonlint is a small yet a very useful tool for validating your project json files which might be some static data, some configuration file through the task-runner grunt. 4 | 5 | ## Getting Started 6 | 7 | You have the below project folder structure: 8 | 9 | ``` 10 | ├── config 11 | │   └── config.json 12 | ├── data 13 | │   └── cities.json 14 | ├── Gruntfile.js 15 | ├── package.json 16 | └── README.md 17 | ``` 18 | 19 | Inside the data folder, you have some contants json list inside data for example cities.json, countries.json, currencies.json while inside config folder you will have a json folder containing the credentials/configurations for your project. 20 | Now multiple people might be colloborating on the constants and the config files and you need to make sure all your json files are validated. 21 | This grunt plugin will validate all your json files so that you dont run into issues in production. 22 | 23 | From your command line run: 24 | 25 | `npm install grunt-jsonlint --save-dev` 26 | 27 | Lets say you have this config.json: 28 | 29 | ```js 30 | { 31 | "configkey1": "configvalue1", 32 | "configkey2": "configvalue2", 33 | "configkey3": "configvalue3", 34 | } 35 | ``` 36 | 37 | After you run `grunt` from the command line: 38 | 39 | ``` 40 | $ grunt 41 | Running "jsonlint:sample" (jsonlint) task 42 | >> File "config/config.json" failed JSON validation. 43 | Warning: Parse error on line 4: 44 | ...3": "configvalue3",} 45 | ----------------------^ 46 | Expecting 'STRING', got '}' Use --force to continue. 47 | 48 | Aborted due to warnings. 49 | ``` 50 | 51 | Oops! A typo over there on line3, Lets fix it. 52 | 53 | ```js 54 | { 55 | "configkey1": "configvalue1", 56 | "configkey2": "configvalue2", 57 | "configkey3": "configvalue3" 58 | } 59 | ``` 60 | 61 | Running grunt now: 62 | 63 | ``` 64 | $ grunt 65 | Running "jsonlint:sample" (jsonlint) task 66 | >> 2 files lint free. 67 | 68 | Done, without errors. 69 | ``` 70 | 71 | You just got saved hours from debugging this in production. 72 | if you have any json files inside your project you should integrate this plugin. 73 | 74 | Would love to know your thoughts in the comments below: -------------------------------------------------------------------------------- /17-grunt-jsonlint/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "configkey1": "configvalue1", 3 | "configkey2": "configvalue2", 4 | "configkey3": "configvalue3" 5 | } -------------------------------------------------------------------------------- /17-grunt-jsonlint/data/cities.json: -------------------------------------------------------------------------------- 1 | { 2 | "london": { 3 | "lat": 51.5, 4 | "lon": -0.117, 5 | "wikipedia": "London", 6 | "city": "London" 7 | }, 8 | "melbourne": { 9 | "lat": -37.8, 10 | "lon": 144.95, 11 | "wikipedia": "Melbourne", 12 | "city": "Melbourne" 13 | }, 14 | "sanfrancisco": { 15 | "lat": 37.767, 16 | "lon": -122.417, 17 | "wikipedia": "San_Francisco", 18 | "city": "San Francisco" 19 | }, 20 | "tokyo": { 21 | "lat": 35.683, 22 | "lon": 139.767, 23 | "wikipedia": "Tokyo", 24 | "city": "Tokyo" 25 | } 26 | } -------------------------------------------------------------------------------- /17-grunt-jsonlint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "17-grunt-jsonline", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to make sure your json files are linted", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-jsonlint": "^1.0.4", 18 | "load-grunt-tasks": "^3.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /18-grunt-exec/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | exec: { 7 | removeLogs: { 8 | cmd: 'rm *.log', 9 | stderr: false 10 | }, 11 | removeTmp: { 12 | cmd: 'rm -rf .tmp', 13 | stderr: false 14 | } 15 | } 16 | }); 17 | 18 | grunt.registerTask('default', ['exec:removeLogs', 'exec:removeTmp']); 19 | }; 20 | -------------------------------------------------------------------------------- /18-grunt-exec/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-exec/ "grunt exec") 2 | 3 | Grunt Exec is a powerful grunt plugin which provides a wrapper over shell (cmd) commands and which can be modified from your Gruntfile.js. 4 | 5 | ## Getting Started 6 | 7 | `npm install grunt-exec --save-dev` 8 | 9 | You want to execute a very simple shell command that just outputs hello 10 | `echo hello` 11 | 12 | So Here is the Gruntfile.js for that: 13 | 14 | ```js 15 | module.exports = function(grunt) { 16 | 17 | require('load-grunt-tasks')(grunt); 18 | 19 | grunt.initConfig({ 20 | exec: { 21 | list_files: { 22 | cmd: 'echo hello' 23 | } 24 | } 25 | }); 26 | 27 | grunt.registerTask('default', ['exec:list_files']); 28 | }; 29 | ``` 30 | 31 | Heres what you get when you run this from the command line: 32 | 33 | ``` 34 | $ grunt 35 | Running "exec:sayHello" (exec) task 36 | hello 37 | 38 | Done, without errors. 39 | ``` 40 | 41 | ## More advanced working 42 | 43 | Lets say you have a more advanced working environment and when pushing to production you want to delete the temporary files or folders that might have been created. 44 | > You might also want to delete npm-debug.log or some other log files that was useful for debuggind but you want it cleaned before pushing to production. 45 | 46 | By using grunt-exec removing unnecessary files becomes very easy and you reduce one manual step. 47 | 48 | For our example, we will consider a case where you have both a .tmp folder and npm-debug.log file which you want to delete before producionizing. 49 | 50 | Here's the project tree before running the task 51 | 52 | ``` 53 | . 54 | ├── Gruntfile.js 55 | ├── npm-debug.log 56 | ├── .tmp 57 | ├── package.json 58 | └── README.md 59 | 60 | ``` 61 | 62 | After executing grunt from the command line: 63 | 64 | 65 | ``` 66 | Running "exec:removeLogs" (exec) task 67 | 68 | Running "exec:removeTmp" (exec) task 69 | 70 | Done, without errors. 71 | ``` 72 | 73 | Heres the project tree after running the task 74 | 75 | ``` 76 | . 77 | ├── Gruntfile.js 78 | ├── package.json 79 | └── README.md 80 | ``` 81 | 82 | Here is the corresponding Gruntfile.js 83 | 84 | ```js 85 | module.exports = function(grunt) { 86 | 87 | require('load-grunt-tasks')(grunt); 88 | 89 | grunt.initConfig({ 90 | exec: { 91 | removeLogs: { 92 | cmd: 'rm *.log', 93 | stderr: false 94 | }, 95 | removeTmp: { 96 | cmd: 'rm -rf .tmp', 97 | stderr: false 98 | } 99 | } 100 | }); 101 | 102 | grunt.registerTask('default', ['exec:removeLogs', 'exec:removeTmp']); 103 | }; 104 | 105 | ``` 106 | 107 | See how easy it is 108 | Every project might have some manual steps, if they can be executed from the shell, you should consider shifting them to grunt-exec. 109 | It might save you a good deal of time by automating those small yet important tasks. 110 | 111 | I will love to hear about your cool hacks around grunt-exec in the comments below 112 | -------------------------------------------------------------------------------- /18-grunt-exec/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "18-grunt-exec", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to easily execute cmd shell commands via an easy to use api", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "load-grunt-tasks": "^3.1.0", 18 | "grunt-exec": "^0.4.6" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /19-grunt-wiredep/.bowerrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/19-grunt-wiredep/.bowerrc -------------------------------------------------------------------------------- /19-grunt-wiredep/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | grunt.loadNpmTasks('grunt-wiredep'); 4 | grunt.loadNpmTasks('grunt-contrib-watch'); 5 | 6 | grunt.initConfig({ 7 | wiredep: { 8 | task: { 9 | src: ['index.html'] 10 | } 11 | }, 12 | watch: { 13 | files: ['bower_components/*'], 14 | tasks: ['wiredep'] 15 | } 16 | }); 17 | 18 | grunt.registerTask('default', ['wiredep']); 19 | grunt.registerTask('changes', ['watch']); 20 | }; 21 | -------------------------------------------------------------------------------- /19-grunt-wiredep/README.md: -------------------------------------------------------------------------------- 1 | ## [Blog post](http://grunt-tasks.com/grunt-wiredep/ "grunt wiredep") 2 | 3 | Grunt wiredep is a quick grunt plugin that helps you inject bower packagers, i.e., links to your dependencies in your front-end source code. 4 | 5 | For example, if you have a jade templating system in your project and every time you install a bower module you want to update that in your source code, this is the grunt plugin to use. 6 | 7 | The way this works is you define in your html/jade/ the wrapper where you want to include dependencies 8 | 9 | ```html 10 | 11 | This is the place where your script tags will be inserted 12 | 13 | ``` 14 | 15 | ## Using Bower 16 | 17 | You will have to make sure you have bower installed on your machine before starting. 18 | If not, it can be installed using: 19 | 20 | `npm install -g bower` 21 | 22 | Initiate bower by running: 23 | 24 | `bower init` 25 | 26 | Follow the command line tutorial and it will generate your bower.json for your project. 27 | 28 | ## Getting started 29 | 30 | From the command line in your project folder run the following: 31 | 32 | `npm install grunt-wiredep --save-dev` 33 | 34 | This will make sure that grunt-wiredep is installed a development dependency in your package.json. 35 | Here is your Gruntfile.js: 36 | ```js 37 | module.exports = function(grunt) { 38 | 39 | grunt.loadNpmTasks('grunt-wiredep'); 40 | grunt.loadNpmTasks('grunt-contrib-watch'); 41 | 42 | grunt.initConfig({ 43 | wiredep: { 44 | task: { 45 | src: ['index.html'] 46 | } 47 | } 48 | }); 49 | 50 | grunt.registerTask('default', ['wiredep']); 51 | }; 52 | ``` 53 | 54 | Here is your index.html, you can have configuration in multiple files: 55 | 56 | ```html 57 | 58 | 59 | 60 | 61 | How to use Grunt Wirdep 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | ``` 71 | 72 | Now install bootstrap via bower: 73 | 74 | `bower install bootstrap --save` 75 | `grunt` 76 | 77 | Now after running grunt wiredep, the bootstrap components will appear in your index.html: 78 | 79 | ```html 80 | 81 | 82 | 83 | 84 | How to use Grunt Wirdep 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | ``` 97 | 98 | ## Automating 99 | 100 | Grunt is all about automating, its become redundant to run two commands of bower install and grunt wiredep everytime we want to install any dependency. 101 | The solution is to use [grunt-watch](http://grunt-tasks.com/grunt-contrib-watch/) to moniter changes over bower_components and run grunt-wiredep everytime something changes. 102 | 103 | You will first need to install grunt-watch 104 | `npm install grunt-contrib-watch --save-dev` 105 | 106 | And Change your Gruntfile.js to include the watch task: 107 | ```js 108 | watch: { 109 | files: ['bower_components/*'], 110 | tasks: ['wiredep'] 111 | } 112 | 113 | grunt.registerTask('changes', ['watch']); 114 | ``` 115 | 116 | The above 'watch' task will moniter for any changes in bower_components folder and will run the grunt tasks specified in the 'tasks' option. 117 | 118 | ``` 119 | $ grunt changes 120 | Running "watch" task 121 | Waiting... 122 | ``` 123 | 124 | Now open the same project folder in another tab in your terminal and install angular-js 125 | `bower install angular --save` 126 | 127 | Now go back to the original tab which is running the grunt watch task. You will observe the following output: 128 | 129 | ``` 130 | >> File "bower_components\angular" added. 131 | Running "wiredep:task" (wiredep) task 132 | 133 | Done, without errors. 134 | ``` 135 | 136 | Our grunt-wiredep task has run after angular folder in bower_components has been created and if you looked at your index.html: 137 | 138 | ```html 139 | 140 | 141 | 142 | ``` 143 | 144 | The angular depedency was automatically included. 145 | 146 | Found something wrong in the above article, send a pull request in the [github repo](http://github.com/kanakiyajay/grunt-tasks/19-grunt-wiredep/) or notify in the comments below. 147 | I will also love to hear about your cool hacks around grunt-wiredep. 148 | -------------------------------------------------------------------------------- /19-grunt-wiredep/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "19-grunt-wiredep", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/kanakiyajay/grunt-tasks", 5 | "authors": [ 6 | "Jay Kanakiya " 7 | ], 8 | "moduleType": [ 9 | "globals" 10 | ], 11 | "license": "MIT", 12 | "private": true, 13 | "ignore": [ 14 | "**/.*", 15 | "node_modules", 16 | "bower_components", 17 | "test", 18 | "tests" 19 | ], 20 | "dependencies": { 21 | "jquery": "~2.1.3", 22 | "bootstrap": "~3.3.4", 23 | "angular": "~1.3.15" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /19-grunt-wiredep/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | How to use Grunt Wirdep 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /19-grunt-wiredep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "19-grunt-wiredep", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to inject links hrefs and script srcs in your html via bower install", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-watch": "^0.6.1", 18 | "grunt-wiredep": "^2.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /20-grunt-contrib-htmlmin/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | copy: { 7 | generated: { 8 | src: 'index.html', 9 | dest: 'dist/index.html' 10 | }, 11 | html: { 12 | files: [{ 13 | expand: true, 14 | cwd: '.tmp', 15 | src: ['*.html'], 16 | dest: 'dist/' 17 | }] 18 | } 19 | }, 20 | filerev: { 21 | options: { 22 | encoding: 'utf8', 23 | algorithm: 'md5', 24 | length: 20 25 | }, 26 | source: { 27 | files: [{ 28 | src: [ 29 | 'dist/js/*.js', 30 | 'dist/css/*.css' 31 | ] 32 | }] 33 | } 34 | }, 35 | useminPrepare: { 36 | html: 'index.html', 37 | options: { 38 | dest: 'dist' 39 | } 40 | }, 41 | usemin: { 42 | html: 'dist/index.html', 43 | options: { 44 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 45 | } 46 | }, 47 | htmlmin: { 48 | dist: { 49 | options: { 50 | removeComments: true, 51 | collapseWhitespace: true 52 | }, 53 | files: [{ 54 | expand: true, 55 | cwd: 'dist/', 56 | src: ['*.html'], 57 | dest: '.tmp/' 58 | }] 59 | } 60 | } 61 | }); 62 | 63 | grunt.registerTask('default', [ 64 | 'copy:generated', 65 | 'useminPrepare', 66 | 'concat', 67 | 'uglify', 68 | 'cssmin', 69 | 'filerev', 70 | 'usemin', 71 | 'htmlmin', 72 | 'copy:html' 73 | ]); 74 | }; 75 | -------------------------------------------------------------------------------- /20-grunt-contrib-htmlmin/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Grunt-contrib-htmlmin is an official plugin from the grunt-js team to minify your project's html source code files before pushing to production with options to remove whitespace and comments. 4 | 5 | ## Getting Started 6 | 7 | You can install it from the command line: 8 | `npm install grunt-contrib-htmlmin --save-dev` 9 | The flag --save-dev will get it installed in your project's package.json as well. 10 | 11 | For the first example we will consider a simple html file which you need to copy and then minify to dist folder. 12 | The index file contains some comments, some paragraphs and some buttons. 13 | 14 | Heres the Gruntfile.js for that: 15 | ```js 16 | module.exports = function(grunt) { 17 | 18 | require('load-grunt-tasks')(grunt); 19 | 20 | grunt.initConfig({ 21 | htmlmin: { 22 | dist: { 23 | options: { 24 | removeComments: true, 25 | collapseWhitespace: true 26 | }, 27 | files: { 28 | 'dist/index.html': 'index.html' 29 | } 30 | } 31 | } 32 | }); 33 | 34 | grunt.registerTask('default', ['htmlmin:dist']); 35 | }; 36 | ``` 37 | 38 | On running grunt from the command line, a new index.html is generated in the dist folder. 39 | 40 | Original index.html: 2.00 Kb, 41 | Minified dist/index.html: 1.43Kb, 42 | Savings: 0.57 Kb = 28.5% compression 43 | 44 | ## Using it with grunt usemin 45 | 46 | We have earlier covered [grunt-usemin](http://grunt-tasks.com/grunt-usemin/) which concatenates your css and js files based on comments in your html files. 47 | Note that grunt-contrib-htmlmin uses [html-minifier](http://github.com/kangax/html-minifier) in the background for compressing your html files. 48 | 49 | You will also need to install the following grunt plugins: 50 | 51 | `npm install grunt-contrib-copy grunt-contrib-uglify grunt-contrib-concat grunt-contrib-cssmin grunt-usemin grunt-filerev --save-dev` 52 | 53 | Using the previous grunt usemin Gruntfile.js and adding the grunt-htmlmin task to it: 54 | 55 | ```js 56 | module.exports = function(grunt) { 57 | 58 | require('load-grunt-tasks')(grunt); 59 | 60 | grunt.initConfig({ 61 | copy: { 62 | generated: { 63 | src: 'index.html', 64 | dest: 'dist/index.html' 65 | } 66 | }, 67 | filerev: { 68 | options: { 69 | encoding: 'utf8', 70 | algorithm: 'md5', 71 | length: 20 72 | }, 73 | source: { 74 | files: [{ 75 | src: [ 76 | 'dist/js/*.js', 77 | 'dist/css/*.css' 78 | ] 79 | }] 80 | } 81 | }, 82 | useminPrepare: { 83 | html: 'index.html', 84 | options: { 85 | dest: 'dist' 86 | } 87 | }, 88 | usemin: { 89 | html: 'dist/index.html', 90 | options: { 91 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 92 | } 93 | }, 94 | htmlmin: { 95 | dist: { 96 | options: { 97 | removeComments: true, 98 | collapseWhitespace: true 99 | }, 100 | files: { 101 | 'dist/index.html': 'dist/index.html' 102 | } 103 | } 104 | } 105 | }); 106 | 107 | grunt.registerTask('default', [ 108 | 'copy:generated', 109 | 'useminPrepare', 110 | 'concat', 111 | 'uglify', 112 | 'cssmin', 113 | 'filerev', 114 | 'usemin', 115 | 'htmlmin' 116 | ]); 117 | }; 118 | ``` 119 | 120 | > The above grunt-task will concat, uglify, compress, revision your css.js files, change dependencies in your html, then minify your html files, and then copy those files to your dist folder. 121 | 122 | On running grunt: 123 | 124 | ``` 125 | $ grunt 126 | Running "copy:generated" (copy) task 127 | Copied 1 file 128 | 129 | Running "useminPrepare:html" (useminPrepare) task 130 | Configuration changed for concat, uglify, cssmin 131 | 132 | Running "concat:generated" (concat) task 133 | File .tmp\concat\css\minified.css created. 134 | File .tmp\concat\js\minified.js created. 135 | 136 | Running "uglify:generated" (uglify) task 137 | >> 1 file created. 138 | 139 | Running "cssmin:generated" (cssmin) task 140 | 141 | Running "filerev:source" (filerev) task 142 | Revved 2 files 143 | 144 | Running "usemin:html" (usemin) task 145 | Replaced 1 reference to assets 146 | 147 | Running "htmlmin:dist" (htmlmin) task 148 | Minified 1 files 149 | 150 | Done, without errors. 151 | ``` 152 | 153 | From the comments: 154 | 155 | It might become cumbersome to specify multiple html files for compressing, 156 | Here's the way to automatically do that. Because grunt-contrib-htmlmin doesn't support replacing [issue], we first copy it to `.tmp` and from there to `dist/` 157 | 158 | Inside htmlmin task: 159 | ```js 160 | files: [{ 161 | expand: true, 162 | cwd: 'dist/', 163 | src: ['*.html'], 164 | dest: '.tmp/' 165 | }] 166 | ``` 167 | 168 | Inside copy task 169 | ```js 170 | html: { 171 | files: [{ 172 | expand: true, 173 | cwd: '.tmp', 174 | src: ['*.html'], 175 | dest: 'dist/' 176 | }] 177 | } 178 | ``` 179 | 180 | You will also have to append `copy:html` as a task in your default task list. 181 | 182 | Now, the index.html in dist/ folder will contain no whitespaces and comments. 183 | Heres the link to the [gist](https://gist.github.com/kanakiyajay/e7117037ae1d1f820947) for Gruntfile.js and package.json 184 | 185 | Found something wrong in the above article, send a pull request in the [github repo](http://github.com/kanakiyajay/grunt-tasks/20-grunt-contrib-htmlmin/) or notify in the comments below. 186 | I will also love to hear about your cool hacks around grunt-htmlmin. 187 | -------------------------------------------------------------------------------- /20-grunt-contrib-htmlmin/css/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 10px; 3 | } -------------------------------------------------------------------------------- /20-grunt-contrib-htmlmin/dist/index.html: -------------------------------------------------------------------------------- 1 | How to use Grunt Htmlmin
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab.
-------------------------------------------------------------------------------- /20-grunt-contrib-htmlmin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | How to use Grunt Htmlmin 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 |
17 |
18 |
19 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 20 |
21 |
22 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 23 |
24 |
25 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 26 |
27 |
28 | 31 |
32 |
33 | 36 | 39 |
40 |
41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /20-grunt-contrib-htmlmin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "20-grunt-contrib-htmlmin", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to minify html files easily", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-concat": "^0.5.1", 18 | "grunt-contrib-copy": "^0.8.0", 19 | "grunt-contrib-cssmin": "^0.12.2", 20 | "grunt-contrib-htmlmin": "^0.4.0", 21 | "grunt-contrib-uglify": "^0.9.1", 22 | "grunt-filerev": "^2.3.1", 23 | "grunt-usemin": "^3.0.0", 24 | "load-grunt-tasks": "^3.1.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /21-time-grunt/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | require('time-grunt')(grunt); 5 | 6 | grunt.initConfig({ 7 | copy: { 8 | generated: { 9 | src: 'index.html', 10 | dest: 'dist/index.html' 11 | } 12 | }, 13 | filerev: { 14 | options: { 15 | encoding: 'utf8', 16 | algorithm: 'md5', 17 | length: 20 18 | }, 19 | source: { 20 | files: [{ 21 | src: [ 22 | 'dist/js/*.js', 23 | 'dist/css/*.css' 24 | ] 25 | }] 26 | } 27 | }, 28 | useminPrepare: { 29 | html: 'index.html', 30 | options: { 31 | dest: 'dist' 32 | } 33 | }, 34 | usemin: { 35 | html: 'dist/index.html', 36 | options: { 37 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 38 | } 39 | }, 40 | htmlmin: { 41 | dist: { 42 | options: { 43 | removeComments: true, 44 | collapseWhitespace: true 45 | }, 46 | files: { 47 | 'dist/index.html': 'dist/index.html' 48 | } 49 | } 50 | } 51 | }); 52 | 53 | grunt.registerTask('default', [ 54 | 'copy:generated', 55 | 'useminPrepare', 56 | 'concat', 57 | 'uglify', 58 | 'cssmin', 59 | 'filerev', 60 | 'usemin', 61 | 'htmlmin' 62 | ]); 63 | }; 64 | -------------------------------------------------------------------------------- /21-time-grunt/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | time-grunt is a utility grunt plugin from Sindre Sorhus for calculating the time it took for each task in executing your grunt build setup. Additionally it can be used to pass the timing stats for your own analysis. 4 | 5 | ## Getting Started 6 | 7 | Lets consider Gruntfile.js from the previous [post](http://grunt-tasks.com/grunt-htmlmin/) which utilizes grunt-usemin and grunt-contrib-html to minify, concat, revision your static assets as well as minify html file. 8 | First you will need to install it 9 | 10 | `npm install time-grunt --save-dev` 11 | 12 | All you need is to add the below line to get time statistics: 13 | 14 | `require('time-grunt')(grunt);` 15 | 16 | On running `grunt` from the command line: 17 | ``` 18 | Execution Time (2015-05-09 08:33:15 UTC) 19 | uglify:generated 16.2s █████████████████████████████████████████████████████████████ 91% 20 | cssmin:generated 1s ████ 6% 21 | Total 17.7s 22 | ``` 23 | 24 | You might find out that tasks that less than 1% are hidden to reduce the clutter. 25 | 26 | On running `grunt --verbose` you will get the whole output: 27 | ``` 28 | Execution Time (2015-05-09 08:34:53 UTC) 29 | loading tasks 20ms 0% 30 | copy:generated 90ms █ 1% 31 | useminPrepare:html 100ms █ 1% 32 | concat:generated 90ms █ 1% 33 | uglify:generated 8.8s ███████████████████████████████████████████████████████████ 91% 34 | cssmin:generated 490ms ████ 5% 35 | filerev:source 30ms 0% 36 | usemin:html 50ms █ 1% 37 | htmlmin:dist 30ms 0% 38 | Total 9.7s 39 | ``` -------------------------------------------------------------------------------- /21-time-grunt/css/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 100%; 7 | } 8 | .CodeMirror-scroll { 9 | /* Set scrolling behaviour here */ 10 | overflow: auto; 11 | } 12 | 13 | /* PADDING */ 14 | 15 | .CodeMirror-lines { 16 | padding: 4px 0; /* Vertical padding around content */ 17 | } 18 | .CodeMirror pre { 19 | padding: 0 4px; /* Horizontal padding of content */ 20 | } 21 | 22 | .CodeMirror-scrollbar-filler { 23 | background-color: white; /* The little square between H and V scrollbars */ 24 | } 25 | 26 | /* GUTTER */ 27 | 28 | .CodeMirror-gutters { 29 | border-right: 1px solid #ddd; 30 | background-color: #f7f7f7; 31 | } 32 | .CodeMirror-linenumbers {} 33 | .CodeMirror-linenumber { 34 | padding: 0 3px 0 5px; 35 | min-width: 20px; 36 | text-align: right; 37 | color: #999; 38 | } 39 | 40 | /* CURSOR */ 41 | 42 | .CodeMirror pre.CodeMirror-cursor { 43 | border-left: 1px solid black; 44 | } 45 | /* Shown when moving in bi-directional text */ 46 | .CodeMirror pre.CodeMirror-secondarycursor { 47 | border-left: 1px solid silver; 48 | } 49 | .cm-keymap-fat-cursor pre.CodeMirror-cursor { 50 | width: auto; 51 | border: 0; 52 | background: transparent; 53 | background: rgba(0, 200, 0, .4); 54 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); 55 | } 56 | /* Kludge to turn off filter in ie9+, which also accepts rgba */ 57 | .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) { 58 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 59 | } 60 | /* Can style cursor different in overwrite (non-insert) mode */ 61 | .CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} 62 | 63 | /* DEFAULT THEME */ 64 | 65 | .cm-s-default .cm-keyword {color: #708;} 66 | .cm-s-default .cm-atom {color: #219;} 67 | .cm-s-default .cm-number {color: #164;} 68 | .cm-s-default .cm-def {color: #00f;} 69 | .cm-s-default .cm-variable {color: black;} 70 | .cm-s-default .cm-variable-2 {color: #05a;} 71 | .cm-s-default .cm-variable-3 {color: #085;} 72 | .cm-s-default .cm-property {color: black;} 73 | .cm-s-default .cm-operator {color: black;} 74 | .cm-s-default .cm-comment {color: #a50;} 75 | .cm-s-default .cm-string {color: #a11;} 76 | .cm-s-default .cm-string-2 {color: #f50;} 77 | .cm-s-default .cm-meta {color: #555;} 78 | .cm-s-default .cm-error {color: #f00;} 79 | .cm-s-default .cm-qualifier {color: #555;} 80 | .cm-s-default .cm-builtin {color: #30a;} 81 | .cm-s-default .cm-bracket {color: #997;} 82 | .cm-s-default .cm-tag {color: #170;} 83 | .cm-s-default .cm-attribute {color: #00c;} 84 | .cm-s-default .cm-header {color: blue;} 85 | .cm-s-default .cm-quote {color: #090;} 86 | .cm-s-default .cm-hr {color: #999;} 87 | .cm-s-default .cm-link {color: #00c;} 88 | 89 | .cm-negative {color: #d44;} 90 | .cm-positive {color: #292;} 91 | .cm-header, .cm-strong {font-weight: bold;} 92 | .cm-em {font-style: italic;} 93 | .cm-emstrong {font-style: italic; font-weight: bold;} 94 | .cm-link {text-decoration: underline;} 95 | 96 | .cm-invalidchar {color: #f00;} 97 | 98 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 99 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 100 | 101 | /* STOP */ 102 | 103 | /* The rest of this file contains styles related to the mechanics of 104 | the editor. You probably shouldn't touch them. */ 105 | 106 | .CodeMirror { 107 | line-height: 1; 108 | position: relative; 109 | overflow: hidden; 110 | } 111 | 112 | .CodeMirror-scroll { 113 | /* 30px is the magic margin used to hide the element's real scrollbars */ 114 | /* See overflow: hidden in .CodeMirror, and the paddings in .CodeMirror-sizer */ 115 | margin-bottom: -30px; margin-right: -30px; 116 | padding-bottom: 30px; padding-right: 30px; 117 | height: 100%; 118 | outline: none; /* Prevent dragging from highlighting the element */ 119 | position: relative; 120 | } 121 | .CodeMirror-sizer { 122 | position: relative; 123 | } 124 | 125 | /* The fake, visible scrollbars. Used to force redraw during scrolling 126 | before actuall scrolling happens, thus preventing shaking and 127 | flickering artifacts. */ 128 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler { 129 | position: absolute; 130 | z-index: 6; 131 | display: none; 132 | } 133 | .CodeMirror-vscrollbar { 134 | right: 0; top: 0; 135 | overflow-x: hidden; 136 | overflow-y: scroll; 137 | } 138 | .CodeMirror-hscrollbar { 139 | bottom: 0; left: 0; 140 | overflow-y: hidden; 141 | overflow-x: scroll; 142 | } 143 | .CodeMirror-scrollbar-filler { 144 | right: 0; bottom: 0; 145 | z-index: 6; 146 | } 147 | 148 | .CodeMirror-gutters { 149 | position: absolute; left: 0; top: 0; 150 | height: 100%; 151 | z-index: 3; 152 | } 153 | .CodeMirror-gutter { 154 | height: 100%; 155 | display: inline-block; 156 | /* Hack to make IE7 behave */ 157 | *zoom:1; 158 | *display:inline; 159 | } 160 | .CodeMirror-gutter-elt { 161 | position: absolute; 162 | cursor: default; 163 | z-index: 4; 164 | } 165 | 166 | .CodeMirror-lines { 167 | cursor: text; 168 | } 169 | .CodeMirror pre { 170 | /* Reset some styles that the rest of the page might have set */ 171 | -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0; 172 | border-width: 0; 173 | background: transparent; 174 | font-family: inherit; 175 | font-size: inherit; 176 | margin: 0; 177 | white-space: pre; 178 | word-wrap: normal; 179 | line-height: inherit; 180 | color: inherit; 181 | z-index: 2; 182 | position: relative; 183 | overflow: visible; 184 | } 185 | .CodeMirror-wrap pre { 186 | word-wrap: break-word; 187 | white-space: pre-wrap; 188 | word-break: normal; 189 | } 190 | .CodeMirror-linebackground { 191 | position: absolute; 192 | left: 0; right: 0; top: 0; bottom: 0; 193 | z-index: 0; 194 | } 195 | 196 | .CodeMirror-linewidget { 197 | position: relative; 198 | z-index: 2; 199 | } 200 | 201 | .CodeMirror-wrap .CodeMirror-scroll { 202 | overflow-x: hidden; 203 | } 204 | 205 | .CodeMirror-measure { 206 | position: absolute; 207 | width: 100%; height: 0px; 208 | overflow: hidden; 209 | visibility: hidden; 210 | } 211 | .CodeMirror-measure pre { position: static; } 212 | 213 | .CodeMirror pre.CodeMirror-cursor { 214 | position: absolute; 215 | visibility: hidden; 216 | border-right: none; 217 | width: 0; 218 | } 219 | .CodeMirror-focused pre.CodeMirror-cursor { 220 | visibility: visible; 221 | } 222 | 223 | .CodeMirror-selected { background: #d9d9d9; } 224 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 225 | 226 | .CodeMirror-searching { 227 | background: #ffa; 228 | background: rgba(255, 255, 0, .4); 229 | } 230 | 231 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */ 232 | .CodeMirror span { *vertical-align: text-bottom; } 233 | 234 | @media print { 235 | /* Hide the cursor when printing */ 236 | .CodeMirror pre.CodeMirror-cursor { 237 | visibility: hidden; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /21-time-grunt/css/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 10px; 3 | } -------------------------------------------------------------------------------- /21-time-grunt/dist/index.html: -------------------------------------------------------------------------------- 1 | How to use Grunt Htmlmin
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab.
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab.
-------------------------------------------------------------------------------- /21-time-grunt/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | How to use Grunt Htmlmin 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 |
17 |
18 |
19 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 20 |
21 |
22 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 23 |
24 |
25 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 26 |
27 |
28 | 31 |
32 |
33 | 36 | 39 |
40 |
41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /21-time-grunt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "21-time-grunt", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to display timing stats", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-concat": "^0.5.1", 18 | "grunt-contrib-copy": "^0.8.0", 19 | "grunt-contrib-cssmin": "^0.12.2", 20 | "grunt-contrib-htmlmin": "^0.4.0", 21 | "grunt-contrib-uglify": "^0.9.1", 22 | "grunt-filerev": "^2.3.1", 23 | "grunt-usemin": "^3.0.0", 24 | "load-grunt-tasks": "^3.1.0", 25 | "time-grunt": "^1.2.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /22-grunt-image-embed/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | imageEmbed: { 7 | dist: { 8 | files: [{ 9 | expand: true, 10 | cwd: '.tmp/concat', 11 | src: ['css/*.css'], 12 | dest: '.tmp/concat' 13 | }] 14 | } 15 | }, 16 | copy: { 17 | generated: { 18 | files: [{ 19 | src: 'index.html', 20 | dest: 'dist/index.html' 21 | }, { 22 | cwd: 'images/', 23 | src: '**/*', 24 | dest: 'dist/images', 25 | expand: true 26 | }, { 27 | cwd: 'images/', 28 | src: '**/*', 29 | dest: '.tmp/concat/images', 30 | expand: true 31 | }] 32 | } 33 | }, 34 | filerev: { 35 | options: { 36 | encoding: 'utf8', 37 | algorithm: 'md5', 38 | length: 20 39 | }, 40 | source: { 41 | files: [{ 42 | src: [ 43 | 'dist/js/*.js', 44 | 'dist/css/*.css' 45 | ] 46 | }] 47 | } 48 | }, 49 | useminPrepare: { 50 | html: 'index.html', 51 | options: { 52 | dest: 'dist' 53 | } 54 | }, 55 | usemin: { 56 | html: 'dist/index.html', 57 | options: { 58 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 59 | } 60 | }, 61 | htmlmin: { 62 | dist: { 63 | options: { 64 | removeComments: true, 65 | collapseWhitespace: true 66 | }, 67 | files: { 68 | 'dist/index.html': 'dist/index.html' 69 | } 70 | } 71 | } 72 | }); 73 | 74 | grunt.registerTask('default', [ 75 | 'copy:generated', 76 | 'useminPrepare', 77 | 'concat', 78 | 'imageEmbed', 79 | 'uglify', 80 | 'cssmin', 81 | 'filerev', 82 | 'usemin', 83 | 'htmlmin', 84 | ]); 85 | }; 86 | -------------------------------------------------------------------------------- /22-grunt-image-embed/css/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 10px; 3 | } 4 | 5 | .grunt { 6 | width: 128px; 7 | height: 128px; 8 | background: url('../images/grunt-logo.png') no-repeat; 9 | } 10 | 11 | .jquer { 12 | width: 57px; 13 | height: 57px; 14 | background: url('http://jquer.in/favicons/apple-touch-icon-57x57.png') no-repeat; 15 | } -------------------------------------------------------------------------------- /22-grunt-image-embed/images/grunt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/22-grunt-image-embed/images/grunt-logo.png -------------------------------------------------------------------------------- /22-grunt-image-embed/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | How to use Grunt Htmlmin 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /22-grunt-image-embed/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "22-grunt-image-embed", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to convert images into data URIs", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-concat": "^0.5.1", 18 | "grunt-contrib-copy": "^0.8.0", 19 | "grunt-contrib-cssmin": "^0.12.2", 20 | "grunt-contrib-htmlmin": "^0.4.0", 21 | "grunt-contrib-uglify": "^0.9.1", 22 | "grunt-filerev": "^2.3.1", 23 | "grunt-usemin": "^3.0.0", 24 | "grunt-image-embed": "^0.3.3", 25 | "load-grunt-tasks": "^3.1.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /23-grunt-browser-sync/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | browserSync: { 7 | bsFiles: { 8 | src: 'css/*.css' 9 | }, 10 | options: { 11 | proxy: 'localhost:80' 12 | } 13 | } 14 | }); 15 | 16 | grunt.registerTask('default', ['browserSync']); 17 | }; 18 | -------------------------------------------------------------------------------- /23-grunt-browser-sync/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Grunt-Browser-Sync is the official grunt-js plugin from BrowserSync to reload your browser on any css file changes. It can create its own server or hook into an existing server. 4 | BrowserSync also automatically reloads all tabs which are dependent on that css file which enables you to work seamlessly with multiple devices. If you haven't started using [browsersync](http://www.browsersync.io/) its recommended you should. 5 | 6 | In this tutorial I am going to demonstrate its usage with Grunt. 7 | 8 | ## Getting Started 9 | 10 | You can install it from the command line: 11 | `npm install grunt-browser-sync --save-dev` 12 | The flag --save-dev will get it installed in your project's package.json as well. 13 | 14 | For the first example we will consider a very basic html webpage linked to to 2 css files. 15 | On making a change inside the css file, all tabs with that html file open should refresh enabling us to quickly change properties. 16 | 17 | Heres the Gruntfile.js for that: 18 | 19 | ```js 20 | module.exports = function(grunt) { 21 | 22 | require('load-grunt-tasks')(grunt); 23 | 24 | grunt.initConfig({ 25 | browserSync: { 26 | bsFiles: { 27 | src: 'css/*.css' 28 | }, 29 | options: { 30 | server: { 31 | baseDir: './' 32 | } 33 | } 34 | } 35 | }); 36 | 37 | grunt.registerTask('default', ['browserSync']); 38 | }; 39 | ``` 40 | 41 | On running grunt from the command line: 42 | 43 | ``` 44 | $ grunt 45 | Running "browserSync:bsFiles" (browserSync) task 46 | [BS] Access URLs: 47 | ------------------------------------- 48 | Local: http://localhost:3000 49 | External: http://192.168.1.33:3000 50 | ------------------------------------- 51 | UI: http://localhost:3001 52 | UI External: http://192.168.1.33:3001 53 | ------------------------------------- 54 | [BS] Serving files from: ./ 55 | [BS] Watching files... 56 | ``` 57 | 58 | Now you can open up the same url in multiple browsers as well as visit 192.168.1.33:3000 from your smartphone. 59 | Once you change anything inside custom.css all the tabs will reload. 60 | BrowserSync also has the ability to sync scroll, form, refresh actions and also provides you with a control panel UI. 61 | ![screenshot](https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/master/23-grunt-browser-sync/images/browsersync.jpg) 62 | 63 | ## External Server 64 | 65 | Many a times we will have an external server built on express / php / django / rails and we want to use BrowserSync and grunt with it. 66 | Sweat not! BrowserSync has this support built-in using its proxy featured. 67 | 68 | This is the only option that you need to change: 69 | 70 | ```js 71 | options: { 72 | proxy: 'localhost:80' 73 | } 74 | ``` 75 | 76 | You can even add port, logs watchOptions and middlewares. 77 | 78 | Here is the [full list](http://www.browsersync.io/docs/options/) of options. 79 | 80 | Found something wrong in the above article, send a pull request in the [github repo](http://github.com/kanakiyajay/grunt-tasks/23-grunt-browser-sync/) or notify in the comments below. 81 | I will also love to hear about your cool hacks around grunt-image-embed. 82 | -------------------------------------------------------------------------------- /23-grunt-browser-sync/css/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 20px; 3 | } 4 | 5 | .jquer { 6 | width: 57px; 7 | height: 57px; 8 | background: url('http://jquer.in/favicons/apple-touch-icon-57x57.png') no-repeat; 9 | } -------------------------------------------------------------------------------- /23-grunt-browser-sync/images/browsersync.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/23-grunt-browser-sync/images/browsersync.jpg -------------------------------------------------------------------------------- /23-grunt-browser-sync/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Using Grunt Browsersync to keep multiple tabs in sync 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /23-grunt-browser-sync/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "23-grunt-browser-sync", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to reload browser on css changes", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-browser-sync": "^2.1.3", 18 | "load-grunt-tasks": "^3.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /24-grunt-contrib-compress/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | compress: { 7 | main: { 8 | options: { 9 | archive: 'project.zip' 10 | }, 11 | files: [{ 12 | cwd: 'assets/css/', 13 | expand: true, 14 | src: ['**/*'], 15 | dest: 'styles' 16 | }, { 17 | cwd: 'assets/js/', 18 | expand: true, 19 | src: ['**/*'], 20 | dest: 'scripts' 21 | }] 22 | } 23 | } 24 | }); 25 | 26 | grunt.registerTask('default', ['compress']); 27 | }; 28 | -------------------------------------------------------------------------------- /24-grunt-contrib-compress/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Grunt-contrib-compress is the official grunt-js plugin from Grunt Team to zip or tar your whole project or a part of your project file and folders. 4 | In this short tutorial I am going to demonstrate its usage: 5 | 6 | ## Getting Started 7 | 8 | You can install it from the command line: 9 | `npm install grunt-contrib-compress --save-dev` 10 | The flag --save-dev will get it installed in your project's package.json as well. 11 | 12 | Lets consider a very basic example where we have to just zip the project folder. 13 | 14 | ``` 15 | assets 16 | ├── css 17 | │   ├── bootstrap.css 18 | │   └── custom.css 19 | ├── images 20 | │   └── browsersync.jpg 21 | ├── index.html 22 | └── js 23 | ├── angular.min.js 24 | ├── bootstrap.min.js 25 | └── jquery.js 26 | ``` 27 | 28 | Heres our Gruntfile.js 29 | 30 | ```js 31 | module.exports = function(grunt) { 32 | 33 | require('load-grunt-tasks')(grunt); 34 | 35 | grunt.initConfig({ 36 | compress: { 37 | main: { 38 | options: { 39 | archive: 'project.zip', 40 | pretty: true 41 | }, 42 | expand: true, 43 | cwd: 'assets/', 44 | src: ['**/*'], 45 | dest: '/' 46 | } 47 | } 48 | }); 49 | 50 | grunt.registerTask('default', ['compress']); 51 | }; 52 | ``` 53 | 54 | On running grunt:- 55 | 56 | ``` 57 | $ grunt 58 | Running "compress:main" (compress) task 59 | Created project.zip (278018 bytes) 60 | 61 | Done, without errors. 62 | ``` 63 | 64 | You will find a project.zip folder in your main directory which when unzipped will contain the css, js and images folder same as in the original. 65 | 66 | ## Configurations 67 | 68 | Lets say you wanted to configure the way the zip folder is created or you want to create a tar, all these options are available in grunt-contrib-compress. 69 | 70 | One of the things that you can configure is the name of the zip folder that is being generated. 71 | archive option also accepts functions which returns strings. 72 | ```js 73 | options: { 74 | archive: function() { 75 | return 'project' + (new Date()).getTime() + '.zip' 76 | } 77 | } 78 | ``` 79 | 80 | Lets consider a case where we want to only compress only the javascript and the css files and you have a server that handles CDN and only accepts folder names of 'scripts' and 'styles'. 81 | 82 | You can use this the Globbing patterns for files available in this grunt plugin. 83 | 84 | Below is the configuration that will be required in order to do that. 85 | The `dest` parameter controls the destination folder for the zipped files, `expand` makes sure the file folder structure is preserved. 86 | 87 | ```js 88 | compress: { 89 | main: { 90 | options: { 91 | archive: 'project.zip' 92 | }, 93 | files: [{ 94 | cwd: 'assets/css/', 95 | expand: true, 96 | src: ['**/*'], 97 | dest: 'styles' 98 | }, { 99 | cwd: 'assets/js/', 100 | expand: true, 101 | src: ['**/*'], 102 | dest: 'scripts' 103 | }] 104 | } 105 | } 106 | ``` 107 | 108 | On unzipping, this is the project structure: 109 | ``` 110 | project 111 | ├── scripts 112 | │   ├── angular.min.js 113 | │   ├── bootstrap.min.js 114 | │   └── jquery.js 115 | └── styles 116 | ├── bootstrap.css 117 | └── custom.css 118 | ``` 119 | Found something wrong in the above article, send a pull request in the [github repo](http://github.com/kanakiyajay/grunt-tasks/24-grunt-contrib-compress/) or notify in the comments below. 120 | I will also love to hear about your usage of grunt-contrib-compress in your projects. 121 | -------------------------------------------------------------------------------- /24-grunt-contrib-compress/assets/css/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 20px; 3 | } 4 | 5 | .jquer { 6 | width: 57px; 7 | height: 57px; 8 | background: url('http://jquer.in/favicons/apple-touch-icon-57x57.png') no-repeat; 9 | } -------------------------------------------------------------------------------- /24-grunt-contrib-compress/assets/images/browsersync.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/24-grunt-contrib-compress/assets/images/browsersync.jpg -------------------------------------------------------------------------------- /24-grunt-contrib-compress/assets/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Using Grunt Browsersync to keep multiple tabs in sync 6 | 7 | 8 | 9 | 10 |
11 |
12 |
13 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus sapiente tempora eligendi officia reiciendis cumque quaerat aspernatur! Iste fuga, expedita voluptas molestiae error velit laboriosam minima amet, dolore perspiciatis, ab. 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 | -------------------------------------------------------------------------------- /24-grunt-contrib-compress/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "24-grunt-contrib-compress", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin to compress folders and files", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-compress": "^0.13.0", 18 | "load-grunt-tasks": "^3.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /24-grunt-contrib-compress/project.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/24-grunt-contrib-compress/project.zip -------------------------------------------------------------------------------- /24-grunt-contrib-compress/project/styles/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 20px; 3 | } 4 | 5 | .jquer { 6 | width: 57px; 7 | height: 57px; 8 | background: url('http://jquer.in/favicons/apple-touch-icon-57x57.png') no-repeat; 9 | } -------------------------------------------------------------------------------- /25-grunt-purifycss/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | clean: ['dist'], 7 | copy: { 8 | generated: { 9 | src: 'src/index.html', 10 | dest: 'dist/index.html' 11 | } 12 | }, 13 | filerev: { 14 | options: { 15 | encoding: 'utf8', 16 | algorithm: 'md5', 17 | length: 20 18 | }, 19 | source: { 20 | files: [{ 21 | src: [ 22 | 'dist/js/*.js', 23 | 'dist/css/*.css' 24 | ] 25 | }] 26 | } 27 | }, 28 | useminPrepare: { 29 | html: 'src/index.html', 30 | options: { 31 | dest: 'dist' 32 | } 33 | }, 34 | purifycss: { 35 | options: { 36 | 37 | }, 38 | target: { 39 | src: ['src/index.html', '.tmp/concat/js/*.js'], 40 | css: ['.tmp/concat/css/*.css'], 41 | dest: '.tmp/concat/css/styles.css' 42 | } 43 | }, 44 | usemin: { 45 | html: 'dist/index.html', 46 | options: { 47 | assetsDirs: ['dist', 'dist/css', 'dist/js', 'css', 'js'] 48 | } 49 | }, 50 | htmlmin: { 51 | dist: { 52 | options: { 53 | removeComments: true, 54 | collapseWhitespace: true 55 | }, 56 | files: { 57 | 'dist/index.html': 'dist/index.html' 58 | } 59 | } 60 | } 61 | }); 62 | 63 | grunt.registerTask('default', [ 64 | 'clean', 65 | 'copy:generated', 66 | 'useminPrepare', 67 | 'concat', 68 | 'purifycss', 69 | 'uglify', 70 | 'cssmin', 71 | 'filerev', 72 | 'usemin', 73 | 'htmlmin' 74 | ]); 75 | }; 76 | -------------------------------------------------------------------------------- /25-grunt-purifycss/dist/index.html: -------------------------------------------------------------------------------- 1 | Grunt Purify CSS

Hello, world!

Learn more

  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Porta ac consectetur ac
  • Vestibulum at eros
Some more information

Example heading New

$ .00
-------------------------------------------------------------------------------- /25-grunt-purifycss/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "25-grunt-purifycss", 3 | "version": "0.0.1", 4 | "description": "Grunt plugin remove unused css", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-clean": "^0.6.0", 18 | "grunt-contrib-concat": "^0.5.1", 19 | "grunt-contrib-copy": "^0.8.0", 20 | "grunt-contrib-cssmin": "^0.12.3", 21 | "grunt-contrib-htmlmin": "^0.4.0", 22 | "grunt-contrib-uglify": "^0.9.1", 23 | "grunt-filerev": "^2.3.1", 24 | "grunt-purifycss": "^0.1.0", 25 | "grunt-usemin": "^3.0.0", 26 | "load-grunt-tasks": "^3.1.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /25-grunt-purifycss/src/css/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 20px; 3 | } 4 | 5 | .m-2t { 6 | margin-top: 40px; 7 | } 8 | 9 | .jquer { 10 | width: 57px; 11 | height: 57px; 12 | background: url('http://jquer.in/favicons/apple-touch-icon-57x57.png') no-repeat; 13 | } -------------------------------------------------------------------------------- /25-grunt-purifycss/src/images/browsersync.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/25-grunt-purifycss/src/images/browsersync.jpg -------------------------------------------------------------------------------- /25-grunt-purifycss/src/images/css.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/25-grunt-purifycss/src/images/css.jpg -------------------------------------------------------------------------------- /25-grunt-purifycss/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt Purify CSS 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |

Hello, world!

17 | 18 |

Learn more

19 |
20 |
21 |
22 |
    23 |
  • Cras justo odio
  • 24 |
  • Dapibus ac facilisis in
  • 25 |
  • Morbi leo risus
  • 26 |
  • Porta ac consectetur ac
  • 27 |
  • Vestibulum at eros
  • 28 |
29 |
30 | Some more information 31 |
32 |
33 |

Example heading New

34 |
35 | $ 36 | 37 | .00 38 |
39 |
40 |
41 |
42 | 43 | 44 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /26-grunt-open/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | open: { 7 | dev: { 8 | path: 'http://localhost/' 9 | } 10 | } 11 | }); 12 | 13 | grunt.registerTask('default', [ 14 | 'open:dev' 15 | ]); 16 | }; 17 | -------------------------------------------------------------------------------- /26-grunt-open/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Grunt open is a simple to use plugin for opening a file or urls in a browser. 4 | This is a plugin that is generally used in conjunction with grunt-connect or any static server for more automation by opening localhost after starting the server. 5 | In this short tutorial I am going to demonstrate its usage: 6 | 7 | ## Getting Started 8 | 9 | You can install it from the command line: 10 | `npm install grunt-open --save-dev` 11 | The flag --save-dev will get it installed in your project's package.json as well. 12 | 13 | In the below very basic example I will have a simple task that will open up a particular url / file. 14 | 15 | Gruntfile.js 16 | 17 | ```js 18 | module.exports = function(grunt) { 19 | 20 | require('load-grunt-tasks')(grunt); 21 | 22 | grunt.initConfig({ 23 | open: { 24 | dev: { 25 | path: 'http://localhost/' 26 | } 27 | } 28 | }); 29 | 30 | grunt.registerTask('default', [ 31 | 'open:dev' 32 | ]); 33 | }; 34 | ``` 35 | 36 | The above task will open up localhost in your default browser. 37 | 38 | Found something wrong in the above article, send a pull request in the [github repo](http://github.com/kanakiyajay/grunt-tasks/26-grunt-open/) or notify in the comments below. 39 | I will also love to hear about your usage of grunt-purifycss in your projects. 40 | -------------------------------------------------------------------------------- /26-grunt-open/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "26-grunt-open", 3 | "version": "0.0.1", 4 | "description": "Opens Urls and files from a grunt task", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/kanakiyajay/grunt-tasks.git" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "Jay Kanakiya", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "grunt": "^0.4.5", 17 | "grunt-contrib-clean": "^0.6.0", 18 | "grunt-contrib-concat": "^0.5.1", 19 | "grunt-contrib-copy": "^0.8.0", 20 | "grunt-contrib-cssmin": "^0.12.3", 21 | "grunt-contrib-htmlmin": "^0.4.0", 22 | "grunt-contrib-uglify": "^0.9.1", 23 | "grunt-filerev": "^2.3.1", 24 | "grunt-open": "^0.2.3", 25 | "grunt-purifycss": "^0.1.0", 26 | "grunt-usemin": "^3.0.0", 27 | "load-grunt-tasks": "^3.1.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /26-grunt-open/src/css/custom.css: -------------------------------------------------------------------------------- 1 | .m-t { 2 | margin-top: 20px; 3 | } 4 | 5 | .m-2t { 6 | margin-top: 40px; 7 | } 8 | 9 | .jquer { 10 | width: 57px; 11 | height: 57px; 12 | background: url('http://jquer.in/favicons/apple-touch-icon-57x57.png') no-repeat; 13 | } -------------------------------------------------------------------------------- /26-grunt-open/src/images/browsersync.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/26-grunt-open/src/images/browsersync.jpg -------------------------------------------------------------------------------- /26-grunt-open/src/images/css.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kanakiyajay/grunt-tasks/944013f2e30375c6d1928bc4f30564275b8adc2a/26-grunt-open/src/images/css.jpg -------------------------------------------------------------------------------- /26-grunt-open/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Grunt Purify CSS 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |

Hello, world!

19 | 20 |

Learn more

21 |
22 |
23 |
24 |
    25 |
  • Cras justo odio
  • 26 |
  • Dapibus ac facilisis in
  • 27 |
  • Morbi leo risus
  • 28 |
  • Porta ac consectetur ac
  • 29 |
  • Vestibulum at eros
  • 30 |
31 |
32 | Some more information 33 |
34 |
35 |

Example heading New

36 |
37 | $ 38 | 39 | .00 40 |
41 |
42 |
43 |
44 | 45 | 46 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## [Grunt Tasks](http://grunt-tasks.com/ "Grunt") 2 | 3 | This is the central github repository which contains all the grunt files as explained in grunt-tasks.com. 4 | [I](http://jaykanakiya.com/ "Jay Kanakiya") have used a simple configutation to sync my blog posts and github repository so that I can git push and change my blog posts at the same time. 5 | 6 | Also makes development work easier by only maintaining the Readme at only one place, while also getting the easier publishing of wordpress. 7 | 8 | ## Getting Started 9 | 10 | You can read this [blog post](http://grunt-tasks.com/start-using-grunt-js/) for getting started. The code and the blog post live in this git repository. 11 | 12 | You can find the initial templates for any plugin in this repository itself. 13 | 14 | `git clone https://github.com/kanakiyajay/grunt-tasks.git` 15 | 16 | cd to that folder and run 17 | 18 | `npm install` 19 | 20 | Following are the Blog posts that have been published 21 | 22 | - [Grunt Contrib Compress](http://grunt-tasks.com/grunt-contrib-compress/ "grunt contrib compress") 23 | - [Grunt Browser Sync](http://grunt-tasks.com/grunt-browser-sync/ "grunt browser sync") 24 | - [Grunt Image Embed](http://grunt-tasks.com/grunt-image-embed/ "image embed") 25 | - [time-grunt](http://grunt-tasks.com/time-grunt/ "time grunt") 26 | - [Grunt Contrib Htmlmin](http://grunt-tasks.com/grunt-htmlmin/ "grunt contrib htmlmin") 27 | - [Grunt Wiredep](http://grunt-tasks.com/grunt-wiredep/ "grunt wiredep") 28 | - [Grunt Jsonlint](http://grunt-tasks.com/grunt-jsonlint/ "grunt jsonlint") 29 | - [Grunt Remove logging calls](http://grunt-tasks.com/grunt-remove-logging-calls/ "grunt remove logging") 30 | - [Grunt csscomb](http://grunt-tasks.com/grunt-csscomb/ "grunt beautiful css") 31 | - [Grunt jsdoc](http://grunt-tasks.com/grunt-jsdoc-ng/ "Grunt Document generator") 32 | - [Grunt Responsive Images](http://grunt-tasks.com/responsive-images/ "grunt responsive images") 33 | - [AutoPrefixer](http://grunt-tasks.com/12-autoprefixer/ "autoprefixer") 34 | - [load grunt tasks](http://grunt-tasks.com/load-grunt-tasks/) 35 | - [Grunt newer](http://grunt-tasks.com/grunt-newer/) 36 | - [Grunt usemin](http://grunt-tasks.com/grunt-usemin/) 37 | - [Grunt concurrent](http://grunt-tasks.com/grunt-concurrent/) 38 | - [Grunt contrib copy](http://grunt-tasks.com/grunt-contrib-copy/) 39 | - [Grunt jscs](http://grunt-tasks.com/grunt-jscs/) 40 | - [Grunt contrib watch](http://grunt-tasks.com/grunt-contrib-watch/) 41 | - [Grunt contrib uglify](http://grunt-tasks.com/grunt-contrib-uglify/) 42 | - [How to start using Grunt](http://grunt-tasks.com/start-using-grunt-js/) --------------------------------------------------------------------------------