I'm working on a Gruntfile for my projects. I've based this Gruntfile on the one included in the generator-webapp Yeoman generator. My Gruntfile looks like this:
'use strict';
var moment = require('moment');
var LIVERELOAD_PORT = 35729;
var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT});
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
module.exports = function (grunt) {
// load all grunt tasks
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
var config = {
src: 'testGrunt',
dest: 'dist'
};
var ftpUrl = "testy";
grunt.initConfig({
config: config,
// configure the files to be watched
watch: {
// if new dependencies are added in bower, add them to the html file
bower :{
files: ['bower.json'],
tasks: ['bowerInstall']
},
// if JS files have changed, re-run jshint
js :{
files: ['<%= config.src %>/js/{,*/}*.js'],
tasks: ['jshint']
},
// if CSS files have changed, re-run autoprefixer
styles: {
files: ['<%= config.src %>/css/{,*/}*.css'],
tasks: ['newer:copy:styles', 'autoprefixer']
},
options: {
nospawn: true,
livereload: LIVERELOAD_PORT
},
livereload: {
files: [
'index.html',
'posts/*.md'
],
tasks: ['build']
}
},
// clean command for different dirs
clean:{
dist: {
files: [{
// allow dot to be present in file name
dot:true,
src:[
// clean the temp and dist folder completely
'.tmp',
'<%= config.dest %>/*',
// ignore hg and git files (do not remove these)
'<!%= config.dest %>/.hg',
'<!%= config.dest %>/.git'
]
}]
}
},
// jshint linting for your javascript
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all :[
// jshint for our own scripts, but let's ignore the lib ones
'<%= config.src %>/js/{,*/}*.js',
'!<%= config.src %>/js/vendor/*'
]
},
autoprefixer: {
options: {
// fetch stuff for any browser with more than 5% marketshare
// WATCHOUT!!!! FORMAT EXACTLY LIKE THIS!
browsers:['> 5%']
},
dist: {
files:[{
expand: true,
// only apply to our own styles and write back to the same tmp folder
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest:'.tmp/styles/'
}]
}
},
// copy any files that aren't automatically copied by other tasks
copy: {
dist: {
files: [
{
expand:true,
dot: true,
cwd: '<%= config.src %>',
dest: '<%= config.dest %>',
src: [
// move any files that we can't optimize with any other tasks
'*.{ico, txt}',
'.htaccess',
'images/{,*/{*.webp',
'{,*/}*.html',
'styles/fonts/{,*/}*.*'
]
}]
},
styles: {
expand: true,
dot: true,
cwd: '<%= config.src %>/css',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
// 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: {
options: {
dest: '<%= config.dest %>'
},
html: '<%= config.src %>/index.html'
},
usemin: {
options: {
assetsDirs: ['<%= config.dest %>', '<%= config.dest %>/images']
},
html: ['<%= config.dest %>/{,*/}*.html'],
css: ['<%= config.dest %>/styles/{,*/}*.css']
},
concurrent: {
dist: [
'copy:styles',
'imagemin',
'svgmin'
]
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.src %>/images',
src: '{,*/}*.{gif, jpeg, jpg, png}',
dest: '<%= config.dest %>/images'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.src %>/images',
src: '{,*/}*.svg',
dest: '<%= config.dest %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
removeCommentsFromCDATA: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
removeRedundantAttributes: true,
useShortDoctype: true
},
files: [{
expand: true,
cwd: '<%= config.dest %>',
src: '{,*/}*.html',
dest: '<%= config.dest %>'
}]
}
},
rev: {
dist: {
files: {
src: [
'<%= config.dest %>/scripts/{,*/}*.js',
'<%= config.dest %>/styles/{,*/}*.css',
'<%= config.dest %>/images/{,*/}*.*',
'<%= config.dest %>/styles/fonts/{,*/}*.*',
'<%= config.dest %>/*.{ico,png}'
]
}
}
},
deploy: {
build: {
auth: {
host: 'something.com',
port: 21,
authKey: 'key1'
},
src: 'dest',
dest: ftpUrl
}
}
});
grunt.registerTask('server', ['build', 'connect:livereload', 'open', 'watch']);
grunt.registerTask('deploy', [
'deploy'
]);
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'cssmin',
'uglify',
'copy:dist',
'rev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'build'
]);
};
My file structure is as follows:
testDirectory/
testGrunt/
js/
css/
libs/
index.html
dist/
styles/
scripts/
index.html
Gruntfile.js
package.json
bower.json
When I run my Gruntfile, all seems to go well, apart from one step. As in the generator-webapp case, the css files are concatenated and written to a .tmp folder. Following this, cssmin is supposed to read these concatenated files, minify them and write them to the desintation folder. However, this doesnt' happen for my main.css. It works for the concatenation of the external files (i.e. libraries that I have included in my HTML). When executing the Gruntfile, the following error shows up:
Running "cssmin:generated" (cssmin) task
File dist/styles/external.css created: 3.31 kB → 1.68 kB
>> Destination not written because minified CSS was empty.
dist/styles/external.css is correctly written. My HTML file, containing the triggers for concat and cssmin (because I'm using usemin):
<html>
<head>
<!-- build:css styles/external.css -->
<!-- bower:css -->
<link rel="stylesheet" type="text/css" href="libs/gridism/gridism.css">
<!-- endbower -->
<!-- endbuild -->
<!-- build:css(.tmp) css/main.css -->
<link rel="stylesheet" type="text/css" href="css/main.css">
<!-- endbuild -->
</head>
<body>
<section class="demo">
<div class="grid">
<div class="unit whole">
<pre>.whole</pre>
</div>
</div>
<div class="grid">
<div class="unit half">
<pre>.half</pre>
</div>
<div class="unit half">
<pre>.half</pre>
</div>
</div>
<div class="grid">
<div class="unit one-third">
<pre>.one-third</pre>
</div>
<div class="unit two-thirds">
<pre>.two-thirds</pre>
</div>
</div>
<div class="grid">
<div class="unit one-quarter">
<pre>.one-quarter</pre>
</div>
<div class="unit three-quarters">
<pre>.three-quarters</pre>
</div>
</div>
<div class="grid">
<div class="unit one-fifth">
<pre>.one-fifth</pre>
</div>
<div class="unit four-fifths">
<pre>.four-fifths</pre>
</div>
</div>
<div class="grid">
<div class="unit two-fifths">
<pre>.two-fifths</pre>
</div>
<div class="unit three-fifths">
<pre>.three-fifths</pre>
</div>
</div>
<div class="grid">
<div class="unit golden-large">
<pre>.golden-large</pre>
</div>
<div class="unit golden-small">
<pre>.golden-small</pre>
</div>
</div>
<div class="grid">
<div class="unit one-quarter align-right center-on-mobiles">
<h2>Nested grids</h2>
<p>Nested grids also work, but the markup gets gnarly pretty quickly.</p>
</div>
<div class="unit three-quarters">
<div class="grid">
<div class="unit whole">
<p class="align-center">Gridception!</p>
</div>
</div>
<div class="grid">
<div class="unit one-third">
<pre>★</pre>
</div>
<div class="unit two-thirds">
<div class="grid">
<div class="unit whole">
<p class="align-center">Gridception!</p>
</div>
</div>
<div class="grid">
<div class="unit two-fifths">
<pre>★</pre>
</div>
<div class="unit three-fifths">
<pre>★</pre>
</div>
</div>
</div>
</div>
<div class="grid">
<div class="unit four-fifths">
<div class="grid">
<div class="unit whole">
<p class="align-center">Gridception!</p>
</div>
</div>
<div class="grid">
<div class="unit one-quarter">
<pre>★</pre>
</div>
<div class="unit one-quarter">
<pre>★</pre>
</div>
<div class="unit one-quarter">
<pre>★</pre>
</div>
<div class="unit one-quarter">
<pre>★</pre>
</div>
</div>
</div>
<div class="unit one-fifth">
<pre>★</pre>
</div>
</div>
</div>
</div>
</section>
<!-- build:js js/external.js -->
<!-- bower:js -->
<script src="libs/jquery/dist/jquery.min.js"></script>
<script src="libs/GA/index.js"></script>
<script src="libs/gmgeo/index.js"></script>
<script src="libs/gmaps/gmaps.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js({testGrunt, .tmp}) js/main.js-->
<script src="js/main.js"></script>
<!-- endbuild -->
</body>
</html>
Because of the similarity with the generator-webapp Gruntfile, I can't understand what is going wrong in my version, as they are almost carbon copies.
I found the problem. The path of the main.css was set incorrectly in the HTML file; it was searching for main.css in .tmp/css/main.css where it couldn't be found. It should have been looking in testGrunt/css/main.css