I started with an empty project generated by yeoman, and tried to edit the Gruntfile.js to fit my needs.
The grunt build task reads my index.html file, and concatenates my bower dependencies and generates a .vendor.js file.
I broke something in the workflow, and now usemin does not replace markups in my index.html file, even if the .vendor.js file is generated.
Here is my Gruntfile.js
'use strict';
module.exports = function (grunt) {
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Define the configuration for all the tasks
grunt.initConfig({
// Project settings
yeoman: {
// configurable paths
app: require('./bower.json').appPath || 'app',
dist: 'dist',
},
express: {
options: {
port: process.env.PORT || 9000
},
dev: {
options: {
script: 'server.js',
debug: true
}
},
prod: {
options: {
script: 'dist/server.js',
node_env: 'production'
}
}
},
open: {
server: {
url: 'http://localhost:<%= express.options.port %>'
}
},
// Watches files for changes and runs tasks based on the changed files
watch: {
js: {
files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
tasks: ['newer:jshint:all'],
options: {
livereload: true
}
},
jsTest: {
files: ['test/spec/{,*/}*.js'],
tasks: ['newer:jshint:test', 'karma']
},
compass: {
files: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer']
},
gruntfile: {
files: ['Gruntfile.js']
},
livereload: {
files: [
'<%= yeoman.app %>/views/{,*//*}*.{html,handlebars}',
'{.tmp,<%= yeoman.app %>}/styles/{,*//*}*.css',
'{.tmp,<%= yeoman.app %>}/scripts/{,*//*}*.js',
'<%= yeoman.app %>/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.app %>/data/{,*/}*.{png,jpg,jpeg,gif,webp,svg,json,pdf}'
],
options: {
livereload: true
}
},
express: {
files: [
'server.js',
'lib/**/*.{js,json}'
],
tasks: ['newer:jshint:server', 'express:dev'],
options: {
livereload: true,
nospawn: true //Without this option specified express won't be reloaded
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
server: {
options: {
jshintrc: 'lib/.jshintrc'
},
src: [ 'lib/{,*/}*.js']
},
all: [
'<%= yeoman.app %>/scripts/{,*/}*.js'
],
test: {
options: {
jshintrc: 'test/.jshintrc'
},
src: ['test/spec/{,*/}*.js']
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/views/*',
'<%= yeoman.dist %>/public/*',
'!<%= yeoman.dist %>/public/.git*',
]
}]
},
heroku: {
files: [{
dot: true,
src: [
'heroku/*',
'!heroku/.git*',
'!heroku/Procfile'
]
}]
},
server: '.tmp'
},
// Add vendor prefixed styles
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
// Automatically inject Bower components into the app
'bower-install': {
app: {
html: '<%= yeoman.app %>/views/edit/index.html',
ignorePath: '<%= yeoman.app %>/'
}
},
// Compiles Sass to CSS and generates necessary files if requested
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: '<%= yeoman.app %>/bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/styles/fonts',
relativeAssets: false,
assetCacheBuster: false,
raw: 'Sass::Script::Number.precision = 10\n'
},
dist: {
options: {
generatedImagesDir: '<%= yeoman.dist %>/public/images/generated'
}
},
server: {
options: {
debugInfo: true
}
}
},
// Renames files for browser caching purposes
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/public/scripts/{,*/}*.js',
'<%= yeoman.dist %>/public/styles/{,*/}*.css',
//'<%= yeoman.dist %>/public/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/public/styles/fonts/*'
]
}
}
},
// The following *-min tasks produce minified files in the dist folder
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.{png,jpg,jpeg,gif}',
dest: '<%= yeoman.dist %>/public/images'
}]
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: ['<%= yeoman.app %>/views/edit/index.html'
//'<%= yeoman.app %>/../views/index.handlebars'
],
options: {
dest: '<%= yeoman.dist %>/public'
}
},
// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/views/edit/index.html',
'<%= yeoman.dist %>/views/{,*/}*.handlebars'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>/public', '<%= yeoman.dist %>/public/images']
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/images',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/public/images'
}]
}
},
htmlmin: {
dist: {
options: {
//collapseWhitespace: true,
//collapseBooleanAttributes: true,
//removeCommentsFromCDATA: true,
//removeOptionalTags: true
},
files: {
'<%= yeoman.dist %>/public/views/edit/index.html': '<%= yeoman.app %>/views/edit/index.html'
}
//files: [{
// expand: true,
// cwd: '<%= yeoman.app %>/views/edit',
// src: ['*.html', 'partials/*.html'],
// dest: '<%= yeoman.dist %>/public/views/edit'
//}]
}
},
// Allow the use of non-minsafe AngularJS files. Automatically makes it
// minsafe compatible so Uglify does not destroy the ng references
ngmin: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/scripts',
src: '*.js',
dest: '.tmp/concat/scripts'
}]
}
},
// Replace Google CDN references
cdnify: {
dist: {
html: ['<%= yeoman.dist %>/public/views/edit/*.html']
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>/public',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
//'views/edit/{,*/}*.html',
//'templates/{,*/}*.html',
'bower_components/**/*',
'images/{,*/}*.{webp}',
'data/{,*/}*.*',
'fonts/**/*'
]
},
//{
// expand: true,
// dot: true,
// cwd: '<%= yeoman.app %>/views',
// dest: '<%= yeoman.dist %>/views',
// src: '**/*.handlebars'
//},
{
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/public/images',
src: ['generated/*']
}, {
expand: true,
dest: '<%= yeoman.dist %>',
src: [
'package.json',
'server.js',
'lib/**/*'
]
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// Run some tasks in parallel to speed up the build process
concurrent: {
server: [
'compass:server'
],
test: [
'compass'
],
dist: [
'compass:dist',
'imagemin',
'svgmin',
'htmlmin'
]
},
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin: {
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= yeoman.app %>/styles/{,*/}*.css'
// ]
// }
// }
// },
// uglify: {
// dist: {
// files: {
// '<%= yeoman.dist %>/scripts/scripts.js': [
// '<%= yeoman.dist %>/scripts/scripts.js'
// ]
// }
// }
// },
//concat: {
// dist: {}
//},
// Test settings
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
}
});
grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
this.async();
});
grunt.registerTask('serve', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'express:prod', 'open', 'express-keepalive']);
}
grunt.task.run([
'clean:server',
'bower-install',
'concurrent:server',
'autoprefixer',
'express:dev',
'open',
'watch'
]);
});
grunt.registerTask('server', function () {
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run(['serve']);
});
grunt.registerTask('test', [
'clean:server',
'concurrent:test',
'autoprefixer',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'bower-install',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngmin',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'rev',
'usemin'
]);
grunt.registerTask('heroku', function () {
grunt.log.warn('The `heroku` task has been deprecated. Use `grunt build` to build for deployment.');
grunt.task.run(['build']);
});
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
};
And here is what is generated when I run grunt:
tree dist/public/scripts/
dist/public/scripts/
├── 434e7b5e.scripts-edit.js
└── ad5d9b7c.vendor-edit.js
index.html:
<!-- build:js(app) scripts/vendor-edit.js -->
<!-- bower:js-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap.js"></script>
<script src="bower_components/angular-resource/angular-resource.js"></script>
<script src="bower_components/angular-cookies/angular-cookies.js"></script>
<script src="bower_components/angular-sanitize/angular-sanitize.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="bower_components/angular-animate/angular-animate.js"></script>
<script src="bower_components/angular-http-auth/src/http-auth-interceptor.js"></script>
<script src="bower_components/angular-translate/angular-translate.js"></script>
<script src="bower_components/angular-translate-storage-cookie/angular-translate-storage-cookie.js"></script>
<script src="bower_components/angular-translate-storage-local/angular-translate-storage-local.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
<script src="bower_components/moment/moment.js"></script>
<script src="bower_components/angular-moment/angular-moment.js"></script>
<script src="bower_components/bootstrap/dist/js/bootstrap.js"></script>
<script src="bower_components/AngularJS-Toaster/toaster.js"></script>
<!-- endbower -->
<!-- endbuild -->
And finaly, here is the grunt output
Running "compass:dist" (compass) task
directory .tmp/styles/
create .tmp/styles/edit.css (16.644s)
create .tmp/styles/webicons.css (0.156s)
create .tmp/styles/main.css (10.947s)
Compilation took 27.77s
Done, without errors.
Execution Time (2014-03-19 13:47:21 UTC)
compass:dist 29.1s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 100%
Total 29.2s
Running "htmlmin:dist" (htmlmin) task
File dist/public/views/edit/index.html created.
Done, without errors.
Execution Time (2014-03-19 13:47:51 UTC)
loading tasks 13ms ▇▇▇▇▇▇▇▇▇▇▇▇ 25%
htmlmin 2ms ▇▇ 4%
htmlmin:dist 35ms ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 67%
Total 52ms
Running "autoprefixer:dist" (autoprefixer) task
Prefixed file ".tmp/styles/edit.css" created.
Prefixed file ".tmp/styles/main.css" created.
Prefixed file ".tmp/styles/webicons.css" created.
Running "concat:generated" (concat) task
File ".tmp/concat/styles/edit.css" created.
File ".tmp/concat/scripts/vendor-edit.js" created.
File ".tmp/concat/scripts/scripts-edit.js" created.
Running "ngmin:dist" (ngmin) task
ngminifying .tmp/concat/scripts/scripts-edit.js, .tmp/concat/scripts/vendor-edit.js
Running "copy:dist" (copy) task
Created 125 directories, copied 907 files
Running "cdnify:dist" (cdnify) task
Going through dist/public/views/edit/index.html to update script refs
Running "cssmin:generated" (cssmin) task
File dist/public/styles/edit.css created.
Running "uglify:generated" (uglify) task
File "dist/public/scripts/vendor-edit.js" created.
File "dist/public/scripts/scripts-edit.js" created.
Running "rev:dist" (rev) task
dist/public/scripts/scripts-edit.js >> 434e7b5e.scripts-edit.js
dist/public/scripts/vendor-edit.js >> ad5d9b7c.vendor-edit.js
dist/public/styles/edit.css >> 9d137efe.edit.css
Running "usemin:html" (usemin) task
Running "usemin:css" (usemin) task
Execution Time (2014-03-19 13:46:43 UTC)
concurrent:test 20.7s ▇▇▇▇▇▇▇ 15%
karma:unit 3.8s ▇▇ 3%
concurrent:dist 41.9s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 31%
ngmin:dist 44.5s ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 33%
copy:dist 2.2s ▇ 2%
uglify:generated 18.1s ▇▇▇▇▇▇ 14%
Total 133.9s
Any help understanding this would be appreciated.
I'll answer my own question:
I had a difference between my useminprepare configuration and my usemin configuration.
useminprepare was writing to <%= yeoman.dist %>/public/views/edit/index.html
and usemin was reading from <%= yeoman.dist %>/views/edit/index.html