Grunt: how to concat a .CSS file onto my compiled .SCSS files? - css

I'm learning grunt and it's wonderful!
background:
My project is built using SASS (.scss), and I use grunt's compass plugin to compile multiple .scss into a single .CSS on output.
problem:
I am using a jQuery plugin which has a .css file associated with it. I want my Grunt to do as follows:
Compile *.SCSS into frontend.css
when done, concat plugin.css onto the end of frontend.css
minify frontend.css.
I have tried adding a concat rule for my CSS, which runs after the grunt compass compiling. The concat rule is shown below.
concat: {
css: {
src: ['www/assets/css/frontend.css',
'bower_components/bootstrap-datepicker/css/plugin.css'],
dest: 'www/assets/css/frontend.css'
}
}
Here is what the grunt task looks like:
grunt.registerTask('default', ['newer:concat:vendors', 'copy', 'uglify', 'compass:dist', 'newer:concat:css', 'newer:cssmin', 'newer:imagemin']);
Here are a list of the Grunt plugins I am using:
// Load Grunt Tasks
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-compass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-newer');
if I call concat:css, plugin.css is concatenated, however each time I run the task it is added on again, again, and again, so multiple copies of the same CSS are being inserted into the file.
if I call newer:concat:css, the file is not ever concatenated onto frontend.css.
Any help much appreciated!

The easiest solution would be to use grunt-contrib-clean, which can simply delete the file on every build:
clean: {
css: ['www/assets/css/frontend.css']
}
Or without installing a plugin:
grunt.registerTask('clean:css', function () {
grunt.file.delete('www/assets/css/frontend.css');
});

Related

Is there a tool for front end developers to see changes on the browser LIVE while coding css?

Usually when I code css/scss/less and make a change, I need to refresh the browser to see the latest changes, I have a dual monitor setup and I think it would be very handy to configure the browser or a specific tool/IDE to see the changes live on the browser, without having to refresh the page.
Gulp example
var gulp = require('gulp'),
less = require('gulp-less');
browsersync = require('browser-sync');
gulp.task('less', function() {
return gulp.src('./src/*.less')
.pipe(less())
.pipe(gulp.dest('./css'));
});
gulp.task('bs', function() {
browsersync({
proxy: 'localhost:9000'
});
});
gulp.task('default', ['less','bs'], function(){
gulp.watch('./src/*.less', ['less']);
gulp.watch('./dest/*', browsersync.reload);
})
if you are using sublime as your text editor you can use livereload
there are some tools will do the job for you like
CodeKit for mac
Prepros for windows
Im using prepros on windows and its very cool
You can use Easy Auto Refresh if you have Chrome.
You can also setup Grunt/Gulp to watch your changes and livesync your browser.
Looks to me like #Rahul's list of tools is going to include what you're looking for, but #JustinRvt mentioned that you can use Gulp… I currently use Gulp in my typical workflow, so here's the most basic example of how that would work.
To understand really what's going on here, and to get Gulp installed on your computer, you'll need read a Gulp guide (I recommend "Gulp for Beginners"; gulp-less documentation is here, gulp-sass documentation here, and Browsersync documentation here).
The way it works is you use Browsersync to run a your site on a local server, have gulp watch for changes to your stylesheet(s), and tell Browsersync to reload the page every time gulp detects a change in one of them.
This demo supports a folder structure like
project
package.json
gulpfile.js
app
index.html
styles-less.less // any of these three < v vv
styles-scss.scss
styles-css.css
where index.html has
<head>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="styles-less.css">
<link rel="stylesheet" href="styles-sass.css">
</head>
The gulpfile.js:
var gulp = require('gulp'),
less = require('gulp-less'), // remove if you aren't using LESS
sass = require('gulp-sass'), // remove if you aren't using Sass
browserSync = require('browser-sync');
// this gulpfile assumes
// - the simplest flat folder structure, where index.html and all stylesheets are in a directory "app" in the top level of the project directory
// if the actual folder structure is different,
// - adjust the src, dest, and watch globs
// - and use `browserSync.init({server: {baseDir: 'yourbasedirectory'}});`
// - that your html files `<link>`s one or more css files
// for every .less file, output a .css file with the original file's base name. Remove this task if you aren't using LESS
gulp.task('less', function() {
return gulp.src('./app/**/*.less')
.pipe(less())
.pipe(gulp.dest('./app'))
});
// for every .scss file, output a .css file with the original file's base name. Remove this task if you aren't using Sass
gulp.task('sass', function() {
return gulp.src('./app/**/*.scss')
.pipe(sass())
.pipe(gulp.dest('./app'))
});
// initial compilation of the stylesheets, followed by initial set up Browsersync (which will handle the auto-reloading)
gulp.task('compile-and-serve', ['less', 'sass'], function() { // adjust (or remove) the prerequisite tasks if you're only using one (or neither) of LESS or Sass
browserSync.init({
server: {
baseDir: './app'
}
});
});
// this happens when you run `gulp`
gulp.task('default', ['compile-and-serve'], function() { // first compile LESS files, Sass files, and start Browsersync
gulp.watch('./app/**/*.less', ['less']); // if a change is made to a LESS file, recompile it. Remove this task if you aren't using LESS
gulp.watch('./app/**/*.scss', ['sass']); // if a change is made to a Sass file, recompile it Remove this task if you aren't using Sass
gulp.watch(['./app/**/*', '!./app/**/*.{less,scss}'], browserSync.reload); // adjust (or remove) the ! glob if you're only using one (or neither) of LESS or Sass
})

Foundation 6 CSS not working

i just installed Foundation 6 through:
foundation new
I chose Foundation for Sites. The file structure is created ann all look ok.
then i run
foundation watch
everything looks fine. The gulp runs and watches the changes.
i then created _custom.scss and imported it into app.scss with:
#import 'custom';
i even put the command to the end of the file to see if this changes anything.
I write some css in the custom file then i save.
I can see the custom css created inside scss/app.scss file but the custom CSS does not appear.
Also even if i change a parametter in _settings.scss like
$body-background: $black;
it has no effect.
All the above changes are reflected in the
foundation watch
terminal window though. I can see the sass compiler updating without errors.
thanks
Maybe it's cache, you should check that. I don't know how foundation new is working, but it's watching the foundation source code right? Maybe there is a conflict between foundation tool and gulp. What I mean by that is that maybe foundations is compiling, then gulp is recompiling without your file.
I suggest you to check:
Maybe there is some cache provided either by foundation or by gulp-cache or other plugin
It is possible some kind of rewrite, so check that too
Make sure there are no errors in your file, otherwise the changes won't be made
Your custom file should be included last, so it can overwrite other classes
If this didn't help, try a different approach with gulp and bower. Make these changes to your gulpfile:
var gulp = require('gulp'),
...,
connect = require('gulp-connect'),
sass = require('gulp-sass');
var paths = {
css: [
'bower_components/foundation-6/css/foundation.min.css',
'src/sass/*.scss',
'src/sass/**/*.scss'
],
...
}
gulp.task('connect', function() {
connect.server({
root: 'dist',
livereload: true,
host: '0.0.0.0',
port: '8080'
});
});
gulp.task('css', function() {
gulp.src(paths.css)
.pipe(sass())
...
.pipe(gulp.dest('dist/css'))
.pipe(connect.reload());
});
gulp.task('watch', function() {
gulp.watch(paths.css, ['css']);
});
gulp.task('default', ['connect', 'css', 'watch']);
Basically I am suggesting to download foundation scss with bower, and include it in gulp.

Grunt watch/Bower link: What is the most appropriate way to use Grunt watch with Bower link when developing a bower component?

Problem
I'm currently working on a project where we have a parent web application (happens to be an AngularJS application) and multiple child Bower modules (containing Javascript, SASS, images, etc.) that are included in the parent using Bower.
For example the parent bower.json looks like this:
{
"name": "parent-app",
"version": "1.0.0",
"dependencies": {
"child-1-module": "1.0.0",
"child-2-module": "1.0.0"
}
}
When performing 'bower install' on the parent the child modules will get installed to:
bower_components/child-1-module
bower_components/child-2-module
We then use 'bower link' for each of the child modules.
Then 'bower link child-1-module' and 'bower link child-2-module' on the parent to create local soft links such as:
bower_components/child-1-module -> /some/where/else/child-1-module
bower_components/child-2-module -> /some/where/else/child-2-module
This allows us to make changes locally to the individual child modules and see the results in the parent app.
We then also use Grunt with grunt-contrib-watch in the parent to watch the parent app for changes and then to perform other Grunt tasks, or to perform a 'livereload' to refresh the browser being used to view the app.
A cut down Gruntfile.js example which watches .js files and then performs a 'jshint' task and a 'livereload' is below:
grunt.initConfig({
// Watches files for changes and runs tasks based on the changed files
watch: {
js: {
files: [
'scripts/{,*/}*.js',
],
tasks: ['newer:jshint:all'],
options: {
livereload: true
}
}
}
}
This works well for watching the parent app for changes, but we would also like to know when files in the child modules change. There are currently a number of solutions I have thought of/investigated with mixed results.
Potential Solution 1: Add bower_components to grunt watch in parent
So I could just modify the Gruntfile to additionally also watch .js files in the bower_components folder, like so:
grunt.initConfig({
// Watches files for changes and runs tasks based on the changed files
watch: {
js: {
files: [
'scripts/**/*.js',
'bower_components/**/*.js'
],
tasks: ['newer:jshint:all'],
options: {
livereload: true
}
}
}
}
However there could be many child modules (containing many .js files), so the performance suffers dramatically and often does not even run due to 'EMFILE: Too many opened files' issues (see here).
Additionally child modules are added dynamically, so we can't specify up front in the Gruntfile only specific ones, for example:
'bower_components/child-1-module/**/*.js'
Potential Solution 2: Add grunt watch in child modules and in parent
We could instead add a Gruntfile.js in each child module that contains a watch to watch their own files.
When a file changes in the child module we can update a specific 'livereload' file, then in the parent we can then only watch for those specific files.
The example 'Gruntfile.js' in child-module-1
grunt.initConfig({
watch: {
js: {
files: ['scripts/**/*.js'],
tasks: ['livereloadEvent:js', 'newer:jshint:all']
}
}
}
grunt.registerTask('livereloadEvent', function() {
// create a 'livereload/livereload.{arg}' file for the event specified
grunt.file.mkdir('livereload');
for(var i = 0; i < this.args.length; i++) {
// contents of the file is the current timestamp
grunt.file.write('livereload/livereload.'+ this.args[i], new Date());
}
});
Then in the parent we can add the following folder to our watch:
'bower_components/**/livereload/livereload.js'
This works OK. The parent now doesn't have to watch too many files, it is now down to the child to perform its own watching and basically notify the parent.
The drawback is that every child has to be aware of this and implement this in the same way.
Other Potential Solutions...
How else have others handled this? Is there an accepted and widely used pattern for handling this?
The way we handle this is very much like your proposed solution 2.
When a developer is working on a child component, he sets up a bower link from the child to the parent Angular app.
He opens two terminal windows. One with a grunt watch task running on the child, and another with a grunt watch task running on the parent.
When he makes changes to the child component, it triggers the grunt task to build the concatenated version of the file into the component's /dist folder.
The parent is watching the /dist folder for changes, and when the build task in the child component is done, it triggers its task to build in the parent app.
In order to minimize the number of files the parent application is watching, we use a prefix in all our bower components, so the watch config looks like this:
watch: {
bower_components: {
files: ['./bower_components/orgname-*/dist/*.js'],
tasks: ['newer:copy']
}
}
I don't know if this is an accepted "best practice," but it does work.

Problems generating source map files with current Gulp setup

I have set up a gulpfile.js in my project. It's working pretty nicely mostly, except when it comes to generating source maps, especially for the LESS files it compiles to CSS.
I have put together a gist which contains all the files in my gulp setup. Please note that other than the gulp file.js itself, all the other files are inside a directory called tasks.
The problems I am having are that
I had to disable the autoprefixer in development because the source maps that were being generated were invalid as the autoprefixer modified the original CSS file after the source maps were generated. To compensate, I have added mixins that add the vendor prefixes during development, and I have to disable those for development and enable the autoprefixer for the production environment.
I am unable to generate a minified CSS file at all if I want source maps. The minification breaks the source maps.
Although I have LiveReload set up, and the associated browser plugins, I cannot get the CSS to get auto-injected into the page as I am making changes.
If anyone can help me structure my gulp file.js to work more efficiently and more effectively, I would appreciate it.
Again, my gulpfile.js and associated tasks are in this gist.
I had to disable the autoprefixer in development because the source maps that were being generated
The docs at https://www.npmjs.com/package/gulp-autoprefixer describe how to use the autoprefixer with gulp-sourcemaps:
gulp.task('default', function () {
return gulp.src('src/**/*.css')
.pipe(sourcemaps.init())
.pipe(autoprefixer())
.pipe(concat('all.css'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'));
});
The above create a new source map for all.css. So you should load the sourcemap generated by the less compiler first, see https://github.com/floridoo/gulp-sourcemaps#load-existing-source-maps
The docs of gulp-minify-css do not describe such an usage, but possible you can do:
gulp.task('minify-css', function() {
gulp.src('./static/css/*.css')
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(minifyCSS({keepBreaks:true}))
.pipe(sourcemaps.write())
.pipe(gulp.dest('./dist/'))
});
Notice that in most cases you minify only your code for production. Development code, which has source maps should not have to be minified.
Since version 2 of Less you can use plugins for the Less compiler. Also gulp-less allows you to use these plugins (programmatic) see also http://lesscss.org/usage/#plugins-using-a-plugin-in-code
Documentation of gulp-less describes how to use the clean-css and autoprefix plugin at https://github.com/plus3network/gulp-less#plugins. Notice that gulp-minify-css is leveraging clean-css's code too.
Also the usage of gulp-less with gulp-sourcemaps to create sourcemaps has been described at https://github.com/plus3network/gulp-less#source-maps
So you should be able to use:
var LessPluginCleanCSS = require("less-plugin-clean-css"),
cleancss = new LessPluginCleanCSS({advanced: true});
var LessPluginAutoPrefix = require('less-plugin-autoprefix'),
autoprefix= new LessPluginAutoPrefix({browsers: ["last 2 versions"]});
gulp.src('./less/**/*.less')
.pipe(sourcemaps.init())
.pipe(less({
plugins: [autoprefix, cleancss]
}))
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('./public/css'));
The above should generate the autoprefixed and minified CSS of your Less source, with CSS sourcemaps written into ./public/css/maps

How to make grunt not minify certain js files

My grunt script generated by yeoman concats and minifies js files through useminPrepare, concat, and uglifyjs.
This is working great, but there is one js script that I do not want it to minify. How do I specify that in the grunt file?
What you can do it's to put the files you don't want to minify outside of the build script, for example:
<!-- build:js js/app.js -->
<script src="js/app.js"></script>
<script src="js/minifythis.js"></script>
<script src="js/models/minifythis.js"></script>
<!-- endbuild -->
<script src="js/do-not-minify-this.js"></script>
I spent days looking for a solution to a problem similar to yours, and then I found a different question that has a answer that may fit solve your problem, as it solved mine: https://stackoverflow.com/a/24819171/785985
The solution is to define custom blocks to be processed by Grunt. Then you can specify one block with ['concat'] and another with ['concat', 'uglifyjs'].
If you choose to exclude the files from the minification tag per the item from John Locke, don't forget to manually copy those files to the 'dist' dir. Normally, when you minify files the resultant minified library is copied to the dist dir. But since you're not minifying them, you have to copy them yourself.
For example, I didn't want to compress the user scripts in my app to make it easier for people to examine the code online. After editing my 'index.html' to remove them from the tag:
'<!-- build:js({.tmp,app}) scripts/scripts.js -->'
I had to add the following to the copy step of my Gruntfile:
copy: {
dist: {
files: [
...
{ // manually copy all the files you are not minimizing:
expand: true,
cwd: '<%= yeoman.app %>/scripts/',
src:"{,*/}*.js",
dest:"<%= yeoman.dist %>/scripts/"
}
]
},
...
},
The syntax for copying files is very prickly in Grunt. It took me a couple of tries to get it right.
Just need to set a minimize option of that script to false in Gruntfile.js.
optimization: {
minimize: false
}

Resources