{"id":244074,"date":"2016-08-04T05:24:25","date_gmt":"2016-08-04T12:24:25","guid":{"rendered":"http:\/\/css-tricks.com\/?p=244074"},"modified":"2016-08-04T05:24:25","modified_gmt":"2016-08-04T12:24:25","slug":"organizing-grunt-tasks","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/organizing-grunt-tasks\/","title":{"rendered":"Organizing Your Grunt Tasks"},"content":{"rendered":"<p>The idea of breaking up your code into smaller bite sized chunks creates an environment that is easy to work in and maintain. That&#8217;s often thought of as <em>module<\/em> design, and is a standard for web development these days. I&#8217;m going to show you a way you can use module design to better organize your Grunt tasks.<\/p>\n<p><!--more--><\/p>\n<p>I&#8217;m going to assume that you already know the basics of using Grunt. If you don&#8217;t, here&#8217;s an article by Chris to get you going: <a href=\"https:\/\/24ways.org\/2013\/grunt-is-not-weird-and-hard\/\" rel=\"noopener\">Grunt for People Who Think Things Like Grunt are Weird and Hard<\/a>.<\/p>\n<p>If you use Grunt, you&#8217;re probably used to seeing your Gruntfile looking something like this.<\/p>\n<pre rel=\"JavaScript (Gruntfile.js)\"><code class=\"language-javascript\">module.exports = function(grunt) {\r\n  grunt.initConfig({\r\n    pkg: grunt.file.readJSON('package.json'),\r\n    sass: {\r\n      dist: {\r\n        options: {\r\n          style: 'expanded',\r\n          sourcemap: 'none'\r\n        },\r\n        files: {\r\n          'style.css': 'sass\/global.scss',      \r\n          'css\/dev.style.css': 'sass\/global.scss',\r\n          'css\/ie9.style.css': 'sass\/ie9.scss',\r\n        }\r\n      }\r\n    },\r\n    postcss: {\r\n      options: {\r\n        processors: [\r\n          require('autoprefixer')(),\r\n          require('rucksack-css')({ fallbacks: true })\r\n        ]\r\n      },\r\n      dist: {\r\n        src: 'style.css',\r\n        dest: 'style.css'\r\n      },\r\n      dev: {\r\n        src: 'css\/dev.style.css',\r\n        dest: 'css\/dev.style.css'\r\n      },\r\n    },\r\n    cssmin: {\r\n      target: {\r\n        files: {\r\n          'style.css': 'style.css'\r\n        }\r\n      }\r\n    },\r\n    concat: {\r\n      dist: {\r\n        src: [\r\n          'js\/lib\/no-conflict.js',\r\n          'js\/lib\/skip-navigation.js',\r\n        ],\r\n        dest: 'js\/scripts.js'\r\n      },\r\n    },\r\n    jshint: {\r\n      files: [\r\n        'js\/scripts.js',\r\n        'js\/ie.js',\r\n      ],\r\n      options: {\r\n        scripturl: true,\r\n        globals: {\r\n          jQuery: true\r\n        }\r\n      }\r\n    },\r\n    uglify: {\r\n      options: {\r\n        mangle: false,\r\n        compress: true,\r\n        quoteStyle: 3\r\n      },\r\n      dist: {\r\n        files: {\r\n          'js\/head.min.js': 'js\/head.js',\r\n          'js\/scripts.min.js': 'js\/scripts.js',\r\n          'js\/ie.min.js'     : 'js\/ie.js',\r\n        }\r\n      }\r\n    },\r\n    watch: {\r\n      scripts: {\r\n        files: ['js\/**\/*.js'],\r\n        tasks: ['concat', 'uglify'],\r\n        options: {\r\n          spawn: false\r\n        }\r\n      },\r\n      css: {\r\n        files: ['sass\/**\/*.scss'],\r\n        tasks: ['sass', 'postcss', 'cssmin']\r\n      }\r\n    },\r\n  });\r\n  grunt.loadNpmTasks('grunt-postcss');\r\n  grunt.loadNpmTasks('grunt-contrib-concat');\r\n  grunt.loadNpmTasks('grunt-contrib-cssmin');\r\n  grunt.loadNpmTasks('grunt-contrib-jshint');\r\n  grunt.loadNpmTasks('grunt-jsvalidate');\r\n  grunt.loadNpmTasks('grunt-contrib-uglify');\r\n  grunt.loadNpmTasks('grunt-contrib-watch');\r\n  grunt.loadNpmTasks('grunt-contrib-sass');\r\n  grunt.registerTask('default', ['watch']);\r\n};<\/code><\/pre>\n<p>This is pretty normal looking Gruntfile. Actually this is a pretty small one. I&#8217;ve seen Gruntfiles that have been three time this size. Looking at those large Gruntfiles gives me a headache. I&#8217;ve had module design drilled into me so much that seeing a Gruntfile that large throws me off my game. Why can&#8217;t my Gruntfile look more like this?<\/p>\n<pre rel=\"JavaScript\"><code class=\"language-javascript\">module.exports = function(grunt) {\r\n  var tasks = {scope: ['devDependencies', 'dependencies' ]};\r\n  var options = {config: { src: \"grunt\/*.js\" }};\r\n  var configs = require('load-grunt-configs')(grunt, options);\r\n  require('load-grunt-tasks')(grunt, tasks);\r\n  grunt.initConfig(configs);\r\n  grunt.registerTask('default', ['watch']);\r\n};<\/code><\/pre>\n<p>It can! I&#8217;m going to show you how. <\/p>\n<p>To accomplish this, we&#8217;re going to install two Grunt packages. <\/p>\n<ol>\n<li><a href=\"https:\/\/github.com\/sindresorhus\/load-grunt-tasks\" rel=\"noopener\">load-grunt-tasks<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/creynders\/load-grunt-configs\" rel=\"noopener\">load-grunt-configs<\/a><\/li>\n<\/ol>\n<p>Go ahead, and install these packages as you would any other Grunt package.<\/p>\n<pre rel=\"Command Line\"><code>$ npm install --save-dev load-grunt-tasks<\/code><\/pre>\n<pre rel=\"Command Line\"><code>$ npm install --save-dev load-grunt-configs<\/code><\/pre>\n<p>Now your `package.json` file should include the two packages like this.<\/p>\n<pre rel=\"JSON (package.json)\"><code class=\"language-javascript\">{\r\n  \"name\": \"your-project\",\r\n  \"version\": \"1.0.0\",\r\n  \"description\": \"\",\r\n  \"main\": \"Gruntfile.js\",\r\n  \"scripts\": {\r\n    \"test\": \"echo \"Error: no test specified\" &amp;&amp; exit 1\"\r\n  },\r\n  \"author\": \"\",\r\n  \"license\": \"ISC\",\r\n  \"devDependencies\": {\r\n    \"grunt-contrib-cssmin\": \"^1.0.1\",\r\n    \"load-grunt-configs\": \"^1.0.0\",\r\n    \"load-grunt-tasks\": \"^3.5.0\"\r\n  }\r\n}<\/code><\/pre>\n<p>For the sake of this article, I also included grunt-contrib-cssmin. Your `package.json` file should have any Grunt packages you&#8217;ll need for your project.<\/p>\n<p>Now, let&#8217;s start with a fresh `Gruntfile.js`. Create a new `Gruntfile.js` file and add the following.<\/p>\n<pre rel=\"JavaScript (Gruntfile)\"><code>module.exports = function(grunt) {\r\n\r\n}<\/code><\/pre>\n<p>The first thing we&#8217;ll do is set up load-grunt-tasks. What load-grunt-tasks does is it creates all of your <code>grunt.loadNpmTasks()<\/code> for you. This removes the need to having to write out each <code>grunt.loadNpmTasks()<\/code> by hand.<\/p>\n<p>Let&#8217;s create a variable <code>tasks<\/code> that will define the options for the load-grunt-tasks package. All we&#8217;re going to do is define the scope and tell it to create a <code>grunt.loadNpmTasks()<\/code> for all the <code>devDependencies<\/code> and <code>dependencies<\/code> packages defined in the `package.json` file.<\/p>\n<pre rel=\"JavaScript (Gruntfile)\"><code class=\"language-javascript\">module.exports = function(grunt) {\r\n  var tasks = {scope: ['devDependencies', 'dependencies']};\r\n}<\/code><\/pre>\n<p>We&#8217;ll need to require() it and add the <code>tasks<\/code> variable to it as the second parameter. Let&#8217;s also add two more variables <strong>options<\/strong> and <strong>configs<\/strong> for load-grunt-configs.<\/p>\n<pre rel=\"JavaScript (Gruntfile)\"><code class=\"language-javascript\">module.exports = function(grunt) {\r\n  var tasks = {scope: ['devDependencies', 'dependencies' ]};\r\n  var options = {config: { src: \"grunt\/*.js\" }};\r\n  var configs = require('load-grunt-configs')(grunt, options);\r\n  require('load-grunt-tasks')(grunt, tasks);\r\n}<\/code><\/pre>\n<p>In the <strong>options<\/strong> variable we telling load-grunt-configs where to look for the files that will contain the grunt task options. The <strong>configs<\/strong> variable is simply requiring load-grunt-configs and adding the <strong>options<\/strong> as the second variable. <\/p>\n<p>Finally, we&#8217;ll add the <code>configs<\/code> variable to the <code>grunt.initConfig()<\/code> function and register a basic task that will run grunt-contrib-cssmin.<\/p>\n<pre rel=\"JavaScript (Gruntfile)\"><code class=\"language-javascript\">module.exports = function(grunt) {\r\n  var tasks = {scope: ['devDependencies', 'dependencies' ]};\r\n  var options = {config: { src: \"grunt\/*.js\" }};\r\n  var configs = require('load-grunt-configs')(grunt, options);\r\n  require('load-grunt-tasks')(grunt, tasks);\r\n  grunt.initConfig(configs);\r\n  grunt.registerTask('default', ['cssmin']);\r\n}<\/code><\/pre>\n<p>That&#8217;s all we&#8217;ll be putting into the Gruntfile. The only other things you may want to add would be additional tasks you want to register. Like a <strong>watch<\/strong> task or a <strong>build<\/strong> task.<\/p>\n<p>In the <code>options<\/code> variable we defined the <em>src<\/em> as <code>grunt\/*.js<\/code>. This tells load-grunt-configs to look in a directory named <strong>grunt<\/strong> and include all JavaScript files within it.<\/p>\n<p>Let&#8217;s create a directory named <strong>grunt<\/strong> and add the task options for cssmin by creating a file named `cssmin.js`. Your project&#8217;s directory structure should look similar to this now.<\/p>\n<figure id=\"post-244104\" class=\"align-none media-244104\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2016\/08\/directory-structure.png?ssl=1\" alt=\"\" \/><\/figure>\n<p>Let&#8217;s add the cssmin options to the `cssmin.js` file. The first thing you want to add is the Grunt module.exports variable just like in the Gruntfile, so that Grunt knows this file is to be loaded when you run your Grunt task. Then add the options for cssmin:<\/p>\n<pre rel=\"JavaScript (Gruntfile)\"><code class=\"language-javascript\">module.exports = {\r\n  target: {\r\n    files: {\r\n      'style.css': 'styles.css'\r\n    }\r\n  }\r\n};<\/code><\/pre>\n<p>If you noticed I didn&#8217;t add the <code>'cssmin: {}'<\/code> wrapper like you would in a basic Gruntfile. This is because load-grunt-configs uses the file&#8217;s name to recognize which task is being run. For example if you&#8217;re using grunt-contrib-uglify the file name would be `uglify.js`. If you&#8217;re using grunt-postcss. That file name will be `postcss.js`. <\/p>\n<p>This is how we&#8217;re adding the module design concept to our grunt tasks. Each task will have its own file containing the task&#8217;s options. This makes to easy to add new tasks, and for multiple developers to makes changes without the worries of accidentally messing up another task in a enormous Gruntfile.<\/p>\n<p>Now when you run your grunt task. Grunt will look in the `grunt` folder find all the task files and run those tasks using the options you defined within each file.<\/p>\n<p>This was a basic example of this technique. The <a href=\"https:\/\/github.com\/sindresorhus\/load-grunt-tasks\" rel=\"noopener\">load-grunt-tasks<\/a> and <a href=\"https:\/\/github.com\/creynders\/load-grunt-configs\" rel=\"noopener\">load-grunt-configs<\/a> packages have more options available that can give you even more control of your Grunt tasks. <\/p>\n<p>I hope this helps you get your Gruntfile under control and add more flexibility to your projects using Grunt. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>The idea of breaking up your code into smaller bite sized chunks creates an environment that is easy to work [&hellip;]<\/p>\n","protected":false},"author":222964,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[4],"tags":[579,762],"class_list":["post-244074","post","type-post","status-publish","format-standard","hentry","category-articles","tag-build-tool","tag-grunt"],"acf":{"show_toc":"No"},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack-related-posts":[{"id":293583,"url":"https:\/\/css-tricks.com\/lets-give-grunt-tasks-the-marie-kondo-organization-treatment\/","url_meta":{"origin":244074,"position":0},"title":"Let&#8217;s Give Grunt Tasks the Marie Kondo Organization Treatment","author":"Serj Lavrin","date":"August 6, 2019","format":false,"excerpt":"We live in an era of webpack and npm scripts. Good or bad, they took the lead for bundling and task running, along with bits of Rollup, JSPM and Gulp. But let's face it. Some of your older projects are still using good ol' Grunt. While it no longer glimmers\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/grunt.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/grunt.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/grunt.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/grunt.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/07\/grunt.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":158177,"url":"https:\/\/css-tricks.com\/grunt-people-think-things-like-grunt-weird-hard\/","url_meta":{"origin":244074,"position":1},"title":"Grunt for People Who Think Things Like Grunt are Weird and Hard","author":"Chris Coyier","date":"December 11, 2013","format":false,"excerpt":"Front-end developers are often told to do certain things: Work in as small chunks of CSS and JavaScript as makes sense to you, then concatenate them together for the production website. Compress your CSS and minify your JavaScript to make their file sizes as small as possible for your production\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":145960,"url":"https:\/\/css-tricks.com\/autoprefixer\/","url_meta":{"origin":244074,"position":2},"title":"Autoprefixer: A Postprocessor for Dealing with Vendor Prefixes in the Best Possible Way","author":"Andrey Sitnik","date":"August 7, 2013","format":false,"excerpt":"The following is a guest post by Andrey Sitnik, the creator of the Autoprefixer tool, a \"postprocessor\" for handling vendor prefixes in CSS. Why use this instead of your preprocessor or another tool? Many reasons. Andrey will explain. Autoprefixer parses CSS files and adds vendor prefixes to CSS rules using\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":257098,"url":"https:\/\/css-tricks.com\/personal-journey-fix-grunt-file-permissions-issue\/","url_meta":{"origin":244074,"position":3},"title":"A Personal Journey to Fix a Grunt File Permissions issue","author":"Geoff Graham","date":"July 31, 2017","format":false,"excerpt":"I was working on a personal project this past week and got a weird error when I tried to compile my Sass files. Unfortunately, I did not screenshot the exact error, but was something along the lines of this: Failed to write to location cssmin: style.css EACCES That EACCES code\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":242681,"url":"https:\/\/css-tricks.com\/component-led-design-patterns-nunjucks-grunt\/","url_meta":{"origin":244074,"position":4},"title":"Component-Led Design Patterns with Nunjucks &#038; Grunt","author":"Morgan feeney","date":"June 14, 2016","format":false,"excerpt":"Recently I was involved with the creation of an in-house system for building HTML prototypes intended to act as a reference point for an eCommerce CMS called Hybris. It started out simple, with PHP. As the team grew, so did the codebase, this eventually made things untidy, giving me sleepless\u2026","rel":"","context":"In &quot;Articles&quot;","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":335901,"url":"https:\/\/css-tricks.com\/through-the-pipeline-an-exploration-of-front-end-bundlers\/","url_meta":{"origin":244074,"position":5},"title":"Through the pipeline: An exploration of front-end bundlers","author":"Chris Coyier","date":"March 4, 2021","format":false,"excerpt":"I really like the kind of tech writing where a fellow developer lays out some specific needs, tries out different tech to fulfill those needs, and documents how it went for them. That's exactly what Andrew Walpole did here. He wanted to try out bundlers in the context of WordPress\u2026","rel":"","context":"In &quot;Links&quot;","block_context":{"text":"Links","link":"https:\/\/css-tricks.com\/category\/links\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/shutterstock_449312359-scaled.jpg?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/shutterstock_449312359-scaled.jpg?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/shutterstock_449312359-scaled.jpg?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/shutterstock_449312359-scaled.jpg?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/03\/shutterstock_449312359-scaled.jpg?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/244074","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/222964"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=244074"}],"version-history":[{"count":9,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/244074\/revisions"}],"predecessor-version":[{"id":244217,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/244074\/revisions\/244217"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=244074"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=244074"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=244074"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}