30

I am new to Yeoman/Grunt/Bower. I have a bower.json file that defines the following dependencies:

bower.json

{
    "dependencies": {
        "angular": "~1.0.7",
        "jquery": "~1.8.0",
        "bootstrap": "~2.3.2",
        "angular-grid": "~2.0.5"
    }
}

In my html file I am using the non-minified versions of those libraries, which I installed via the command bower install

index.html

<script src="components/jquery/jquery.js"></script>
<script src="components/bootstrap/docs/assets/js/bootstrap.js"></script>
<script src="components/angular/angular.js"></script>
<script src="components/angular-grid/build/ng-grid.js"></script>

How can I configure grunt, so it will:

  1. Copy only the minified versions of the those js files to the build directory
  2. Replace the HTML so it will change e.g. jquery.js to jquery.min.js
  3. When not using CDNs - is it recommend to combine all the files together with the custom application script?

What is the right approach here? Do I have to define each lib in a grunt copy task? Like:

Gruntfile.js:

copy: {
  dist: {
    files: [{
      src: [
        'components/jquery/jquery.min.js',
        'components/bootstrap/docs/assets/js/bootstrap.min.js',
        'components/angular/angular.min.js',
        'components/angular-grid/build/ng-grid.min.js'
      ]
    }]
  }
}
fischermatte
  • 3,327
  • 4
  • 42
  • 52

4 Answers4

35

Minified versions of the JavaScript libraries you're using will eventually not be shipped with Bower modules. Minifying and concatenating is not something the package manager is responsible for, but your build pipeline.

With Yeoman, the recommended way is to use grunt-usemin, which will take care of all the necessary steps. You can see an example of this when scaffolding out a new app with yo webapp and taking a look at the generated Gruntfile.js and index.html.

In your case, you would need to add a comment around your script includes:

<!-- build:js scripts/main.js -->
<script src="components/jquery/jquery.js"></script>
<script src="components/bootstrap/docs/assets/js/bootstrap.js"></script>
<script src="components/angular/angular.js"></script>
<script src="components/angular-grid/build/ng-grid.js"></script>
<!-- endbuild -->

And make sure to have the corresponding usemin tasks in your Grunt pipeline:

useminPrepare: {
    options: {
        dest: 'dist'
    },
    html: 'app/index.html'
},
usemin: {
    options: {
        dirs: ['dist']
    },
    html: ['dist/{,*/}*.html'],
    css: ['dist/styles/{,*/}*.css']
},
Sindre Sorhus
  • 62,972
  • 39
  • 168
  • 232
passy
  • 7,170
  • 5
  • 36
  • 38
  • 7
    @sindre-sorhus minifying an artifact should be the maintainer responsability. You have to know the artifact codebase to use the right minifying options. – Guillaume Massé Aug 08 '13 at 17:51
  • @GuillaumeMassé no it's not. It's the maintainers responsibility to build the artifacts, but not minify them. I've yet to see a built projects that couldn't be run through uglify. I would be happy to be shown otherwise though. – Sindre Sorhus Aug 08 '13 at 19:36
  • 2
    @GuillaumeMassé it's fairly well known Prototype does some awful stuff. Don't let that drag down the rest. – Sindre Sorhus Aug 08 '13 at 20:18
  • 1
    @sindre-sorhus if I develop an artifact and make a release it's just more efficient to release the minified version and spare other developper building the whole thing. – Guillaume Massé Aug 08 '13 at 20:25
  • @GuillaumeMassé they most likely have a build-system anyway which will concat and minify, so it wouldn't really help them much. – Sindre Sorhus Aug 08 '13 at 20:34
  • why would you concat released artifact ? you loose http caching. – Guillaume Massé Aug 08 '13 at 20:36
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/35104/discussion-between-guillaume-masse-and-sindre-sorhus) – Guillaume Massé Aug 08 '13 at 20:39
  • 7
    Claiming that minifying 3rd party atrifacts is user's responsibility is not only odd, but would collide with so many corporate practices it's scares me to even write about. You are not supposed to do that. The sheer blame-war if something goes south... – ZenMaster Oct 10 '13 at 16:16
  • @SindreSorhus From the Angular Team, [Best Practices](https://www.youtube.com/watch?v=ZhfUv0spHCY#t=1118). They specifically recommend using their minified file because they tweaked the settings just right. – Jacob Eggers Jan 28 '14 at 01:59
  • No one's asking bower to minify, just be a pass through. Also, the first slide in "Best Practices" reads: **"Never compile angular.min.js"** :D. – Mrchief Mar 18 '15 at 20:57
2

don't need to change the html, try grunt-contrib-uglify

uglify: {
  libs: {
    files: [
      {
        expand: true,
        cwd: 'components',
        src: '**/*.js',
        dest: 'build/components'
      }
    ]
  }
}

and if the file are requested more the one page, it will be cached by the browser, it will be load faster than the combined larger file.

yao tony
  • 49
  • 4
  • Where did you find out what those parameters mean? I am looking for some documentation that explains `expand` and `cwd`. Thanks – Chris Bier Jan 29 '14 at 19:48
  • Found an example, but no documentation on each option: https://github.com/gruntjs/grunt-contrib-uglify#compiling-all-files-in-a-folder-dynamically – Chris Bier Jan 29 '14 at 20:35
  • just try and it will be clear cwd: the target folder expand: compiling all files in the folder – yao tony Jun 09 '14 at 15:39
0

Another option if you are interested in using minified javascript and also having the package version in the include path is to use grunt-version-copy-bower-components. This grunt plugin handles copying the bower component to a destination directory, includes the component version in the component path, and modifies referencing files (html and css) to use the versioned minified path.

Including the version in the components path can be helpful if the site is hosted with a cache (behind a CDN). It allows you to specify long cache times for the bower components. When switching to a new bower component version the URL will be new and the cache will fetch the new one instead of serving a stale component.

An example configuration:

versionCopyBowerComponents: {
  options: {
    exclude: ['underscore'],
    dest: 'dist/libs',
    filesReferencingComponents: {
      files: ['dist/test.html', 'dist/test.css'],
      useComponentMin: true
    }
  }
}

The plugin will determine the bower components that your project is using and automatically install them to the path specified in dest. The files listed in filesReferencingComponents->files are files that include/source the bower component. Specifying useComponentMin will cause it to choose the minified version of the component.

HypeXR
  • 711
  • 2
  • 6
  • 19
0

It would be a bad practice to minify yourself a library that already exists in a minified version. Fortunately, at least for angularJS, the bower package includes angular.min.js.map file. With this source map, I think it makes no sense to include at any point the non-minified file in the source. Just include the min file, leave it outside Grunt minifier, and let the browser map to the non minified source.

Romain F.
  • 766
  • 10
  • 15