Question

So i'm pretty new grunt so i'm still trying to fathom a few things out. But what i want to do is setup "development" and "production" configurations for grunt. I think i've worked out the tasks config stuff, however i have a specific requirement which i'm hoping you guys can help me solve.

In my development environment, i want grunt to copy the javascript and css from a source folder (css built from less in a previous task), into my build/public/js folder, then automatically write a html script/link tag for each file it copies into the HTML (i could use usemin or useref but some of the vendor javascripts have 10+ javascript sources, so automating the html write operation would be better).

In a production environment i want grunt to minify and what not the javascript and css, into my public folder as single files, then write the html tag for each compiled script rather than one per source file.

So the result would be a single css file, a single vendor js file and a single "myapp" js file in the production build, with version numbers or random filename assignment for cache-busting, and just loads of original js source files in the development build.

Could someone provide any direction on this, i have found a few plugins that do bits and pieces of what i need, but i can't work out how to string them together (i know i need grunt-contrib-copy for the dev version, but i need to write every file copied to the html e.c.t.)

Note: im using bower for js vendor packages if it makes any difference

Was it helpful?

Solution

I am working on the same solution, and have found pretty good luck with the following tools:

grunt-contrib-concat This can concatenate files from one location into a single file in another. You can either specify specific files like this:

       files: {
         'dist/app.concat.js': ['app/modules/nav.js', 'app/modules/user.js']
       }

or you can use the globbing syntax to select multiple (and even exclude as well) like this:

    files: {
      'dist/app.concat.js': [
                             'app/**/*.js',
                             '!app/vendor/**/*.js'
                            ] // this excludes anything from the vendor folder being added
    }

Here is a full example

concat: {
  dist: { // task name, so you call this with 'grunt concat:dist'. You can have different sections under concat for different builds
    files: {
      'dist/app.concat.js': ['app/**/*.js',
                             '!app/vendor/**/*.js',
                             '!app/test/**/*.js'
                            ], // adds all .js files, but excludes anything in vendor and test
      'dist/vendor.concat.js': ['app/vendor/**/*.js'],
      'dist/app.concat.css': ['app/styles/**/*.css']
  }
}

grunt-contrib-copy This is a simple one that lets you copy from 1 place to another. You can also use globbing if you want to pull an entire directory structure over (src: [app/**/*.*])

copy: {
  dist: {
    files: [
      {
        src: ['app/index.html'],
        dest: 'dist/'
  }
}

grunt-scriptlinker

This is the one that will help you with dynamically filling out your index.html (or whatever) with references to the correct files. It's useage is pretty straight forward: you add some HTML comments to your index.html (or whatever) and tell scriptlinker to look for them. It will then search through whatever set of files you point it to and dynamically add a reference to those files, within the script tags you give it. I'm using it to load CSS files at the top, then .js files at the bottom:

scriptlinker: {
  distCSS: {
    options: {
      startTag: '<!--CSS SCRIPTS-->',
      endTag: '<!--CSS SCRIPTS END-->',
      fileTmpl: '\n<link rel="stylesheet" type="text/css" href="%s" />',
      appRoot: 'app/'
    },
    files: {
      'dev/app/index.html': ['dist/**/*.css']
    }
  },
  distJS: {
    options: {
      startTag: '<!--JS SCRIPTS-->',
      endTag: '<!--JS SCRIPTS END-->',
      fileTmpl: '\n<script src="%s"></script>',
      appRoot: 'app/'
    },
    files: {
      'dev/app/index.html': ['dist/vendor/*.js']
    },
  }
}

So you can see, you tel it what tags to look for, what template to use, and what files or directories to look at. It will turn this:

<html ng-app="ngAD">
  <head>
    <!--CSS SCRIPTS--><!--CSS SCRIPTS END-->
  </head>

  <body>
    <div class="container">... my app stuff...</div>

    <!--JS SCRIPTS--><!--JS SCRIPTS END-->
  </body>
</html>

into this:

    <html ng-app="ngAD">
  <head>
    <!--CSS SCRIPTS-->
      <link rel="stylesheet" type="text/css" href="styles/bootstrap.min.css" />
      <link rel="stylesheet" type="text/css" href="modules/navbar/navbar.css" />
      <link rel="stylesheet" type="text/css" href="styles/jscrollpane.css" />
      <link rel="stylesheet" type="text/css" href="styles/styles.app.css" /><!--CSS SCRIPTS END-->
  </head>

  <body>
    <div class="container">... my app stuff...</div>

    <!--JS SCRIPTS-->
       <script src="vendor/jquery.min.js"></script>
       <script src="vendor/angular.min.js"></script>
       <script src="vendor/vendor.concat.js"></script>
       <script src="common/common.dist.js"></script>
       <script src="modules/modules.dist.js"><!--JS SCRIPTS END-->
  </body>
</html>

For completeness sake, I'll also point you towards grunt-usemin... it is popular and has similar functionality to scriptLinker... you may like that better. I'm still getting cachebusting setup but I'm working with cacheBust (grunt-cache-bust) and so far it seems to be doing what I want. Let me know if you have any specific issues, I may be able to give more specific feedback.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top