Grunt Watch LESS files in folder and create css when less file is changed - node.js

I am looking for GRUNT automation task which watches the less files in the root directory and gives us the css files of the same name as the less files in the same directory like
Root Folder
package.json
Gruntfile.js
Folder1
file1.less
file2.less
Folder2
file3.less
file4.less
My Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
//our LESS options
less: {
development: {
files: {
"": "" //not able to write this line, how can i mention which file to compile as i am watching the entire folder
}
}
},
watch: {
css: {
files: '**/*.less',
tasks: ['less']
}
}
});
//load our tasks
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
//default tasks to run
grunt.registerTask('default', ['less']);
}
Not able to mention the source less file name and result css file name in less task config, as i am watching the entire folder, i want to create the css file for the corresponding less file in the same path as less, whenever particular css is changed. Want to compile the less file which is changed , not all the less files to be compiled, if one less is changed.
Thanks in advance for any help.

You can use grunt-newer to configure you less task to run with newer files only.
npm install grunt-newer --save-dev
once the plugin is installed, add
grunt.loadNpmTasks('grunt-newer');
edit the watch task:
watch: {
css: {
files: '**/*.less',
tasks: ['newer:less']
}
}

Have a look at the grunt.js docu and see how to build files object dynamically.

Related

Run a shell command that is inside a project folder from Grunt task

I have a shell command ./node_modules/cordova/bin/cordova which is accessible from the project root.
I also have a set of config files for Grunt which are located in ./config folder.
Now I am trying to run cordova from tasks and want to use it as an alias, so in Gruntfile.js I have it like this:
grunt.initConfig({
buildDir: 'build/interim_builds',
publishDir: 'build/publish',
cordovaCommand: './node_modules/cordova/bin/cordova',
...
})
Then, from a task I run it like this:
mobileApp_create: {
cmd: '<%= cordovaCommand %> create <%= mobileAppProjectDir %>'
}
As a result I get this error:
'.' is not recognized as an internal or external command,
If I replace
cordovaCommand: './node_modules/cordova/bin/cordova'
with
cordovaCommand: 'node_modules/cordova/bin/cordova'
Then I see this error:
'node_modules' is not recognized as an internal or external command,
So, I suppose it can be something with relative paths and how Grunt works with them? Where do I dig to fix this issue as I need to use local installation of cordova, not global.
You could try fully resolving the path at runtime, that way there are no relative paths:
var path = require('path');
module.exports = function(grunt) {
grunt.initConfig({
buildDir: 'build/interim_builds',
publishDir: 'build/publish',
cordovaCommand: path.resolve('./node_modules/cordova/bin/cordova'),
// ...
});
// ...
};

jspm bundle code in subdirectory that is served as root

I am trying to create a self-executing bundle of an application, but jspm can't find what it's looking for.
I have the following folder structure
The src directory contains all of the JavaScript, but it is hosted by node as if it were the root. jspm_packages is hosted as if it were inside the root, making normal module import without a path possible (ie import React from 'react')
The app runs just fine, but when I try to build it fails because it doesn't know to look in the src directory and the jspm_packages directory for modules. Is there a way to fix this without changing the folder structure or the root-hosting?
I am ok with moving the system.config.js file into src if that makes this possible)
EDIT
This is easy if you move jspm_packages into src.
in package.json
"jspm": {
"directories": {
"baseURL": "src"
},
"configFile": "src/system.config.js"
}
This will put both system.config.js and jspm_packages in src (don't use a baseUrl in system.config.js), and bundling will work. The major drawback here is the src folder no longer contains only the project code; it now also contains library code. Performing folder searches becomes harder, and I just prefer the idea of a folder with all of my code in it.
EDIT2
After thinking about this problem more, I guess what I am really after is a method to specify an alternate path configuration during bundling. Based on my reading of the docs, this appears to be unsupported.
You can set your baseUrl to be the root (i.e. "/") and then set the path for your source code on the paths property like this:
System.config({
baseURL: "/",
paths: {
"*": "dist/*",
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*"
}
})
Full working example can be seen here.
Furthermore, if you need to change you paths just for bundling you could use the jspm-cli in a gulp task and override your builder configuration like this:
var jspm = require('jspm');
gulp.task('task', function () {
var builder = new jspm.Builder();
builder.loadConfigSync('pathToYourConfigFile');
builder.config({
paths: {
'*': 'pathToYourCode'
}
});
builder.bundle('yourOptionsHere');
}

Uglify or concat a JavaScript file conditionallly

I have in my Scripts folder a "Lib" folder and an "App" folder.
The Lib folder contains 3rd part library JavaScript files. Some of these are minified without the original sources, others we have the original sources for.
The App folder contains all of our own JavaScript files, all of which are not minified.
I'm new to Grunt but I have a gruntfile which does the following:
Uglifies all the JS files in the Lib folder and produces minified versions with sourcemaps.
Uglifies all the JS files in the App folder and produces minified versions with sourcemaps.
Obvious problem: some of the files in the Lib folder are minified, so minifying them again/generating source maps is a bad idea and can fail for various reasons.
My solution: I run Uglify only on .js files in the Lib folder into lib-unmin.min.js. I then concat all the already minified files into a lib-min.min.js file, then I concat both those files together to get lib.min.js.
The new problem
What if I can't concat the already minified scripts to the end of the other minififed scripts without it breaking?
I have a dependency issue like this:
scripts/lib/a.js (required for b to run)
scripts/lib/b.min.js (required for c to run)
scripts/lib/c.js (required for the App scripts to run)
If I have an array of these file paths in my gruntfile, in that order, what's the easiest way of uglifying/concating all the files into a single minified JS file in that order, making sure we don't attempt to minify the minified file?
What do other developers do in similar situations?
Thanks!
I like to concat the files then uglify all of them together. This way uglify makes sure there aren't duplicate variable values overriding each other when it compresses the variable names.
You can bundle as many files as you want in the concats. Make different concat groups to uglify together and maintain the 'first, second, third, ...' order like this:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
app: {
options: {
sourceMap: true,
sourceMapName: 'build/maps/map.map'
},
files: {
'build/app.min.js': ['build/js/app-first-unmin.js', 'build/js/app-second-min.js', 'build/js/app-third-unmin.js']
}
}
},
concat: {
options: {
separator: ';'
},
firstUnminified: {
src: [
'lib/underscore.js'
],
dest: 'build/js/app-first-unmin.js'
},
secondMinified: {
src: [
'lib/moment.min.js'
],
dest: 'build/js/app-second-min.js'
},
thirdUnminified: {
src: [
'lib/favico.js'
],
dest: 'build/js/app-third-unmin.js'
}
},
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['concat:firstUnminified', 'concat:secondMinified', 'concat:thirdUnminified','uglify']);
};

Less won't compile as nodejs middleware

I setup less-middleware for compiling less on the fly, it worked great for quite some time now, but I was changing some packages, doing npm update and so on, but nothing really less-related...
And it stopped working. When I'm requesting for example main.css (it should compile main.less and serve it as css), I get weird error in console:
LESS Syntax error : Object function (deleteValue) {
for (var i = 0; i < this.length; i++) {
if (this[i] == deleteValue) {
this.splice(i, 1);
i--;
}
}
return this;
} has no method 'charAt'
LESS File : /srv/sicy-node/public/css/main.less null:-1
TypeError: Object function (deleteValue) {
for (var i = 0; i < this.length; i++) {
if (this[i] == deleteValue) {
this.splice(i, 1);
i--;
}
}
return this;
} has no method 'charAt'
at Object.Parser.parser.parsers.parsers.ruleProperty (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:1938:37)
at Object.Parser.parser.parsers.parsers.rule (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:1479:48)
at Object.Parser.parser.parsers.parsers.primary (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:721:76)
at Object.Parser.parser.parsers.parsers.block (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:1427:51)
at Object.Parser.parser.parsers.parsers.ruleset (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:1461:48)
at Object.Parser.parser.parsers.parsers.primary (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:721:91)
at Object.Parser.parser.parsers.parsers.block (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:1427:51)
at Object.Parser.parser.parsers.parsers.directive (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:1715:34)
at Object.Parser.parser.parsers.parsers.primary (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:722:64)
at Object.Parser.parser.parse [as parse] (/srv/sicy-node/node_modules/less-middleware/node_modules/less/lib/less/parser.js:498:61)
This is how middleware is set:
app.use(require('less-middleware')({ src: __dirname + '/public' }));
It looks like this is a result of that bug in Less 1.6.1 (basically, Less fails if some other module extends Array.prototype). Updating less-middleware to more recent Less version should help (you can update your installation by changing the version in this file to ~1.6.3 if it does not update automatically).
I might not be solving your exact problem but this is how i do the less compilation using grunt, infact not just i but most of the people do, and i find it very convenient.
grunt provides a great way to automate the process of transmuting LESS into CSS. Initially you'll have to set up a few tools, but once you're done with that, you can easily use the system with all your projects.
Grunt is a JavaScript-based task runner that can be configured to keep an eye on changes made to your LESS files. When the contents change, it automatically compiles the files into a minified CSS file.
Step 1: Install Node.js
Get the installation package from Nodejs.com, and install it. Binaries are available for Mac OS X, Windows, Linux, and SunOS. You can also compile it from source code.
Step 2: Install Grunt
Install Grunt using the Node package manager:
sudo npm install -g grunt
sudo npm install -g grunt-cli
Step 3: Write your Grunt configuration file
Create a Gruntfile.js file in your project directory. Then copy and paste the contents below. You'll just need to change the (commented) lines that define which files you want Grunt to watch, and where to place the compiled CSS file.
module.exports = function(grunt) {
grunt.initConfig({
less: {
development: {
options: {
compress: true,
yuicompress: true,
optimization: 2
},
files: {
// target.css file: source.less file
"sites/all/themes/jiandan/css/main.css": "sites/all/themes /jiandan/less/main.less"
}
}
},
watch: {
styles: {
// Which files to watch (all .less files recursively in the less directory)
files: ['sites/all/themes/jiandan/less/**/*.less'],
tasks: ['less'],
options: {
nospawn: true
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['watch']);
};
Step 4: Configure the package
cd YOUR_PROJECT_DIRECTORY
npm init
The above will prompt you to supply additional information about your project.
When you're done, open the package.json file located in your project directory, and add the following lines of code:
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-less": "~0.5.0",
"grunt-contrib-watch": "~0.4.0"
},
Then issue the following command to install the package dependencies:
npm install
Step 5: Start Grunt
grunt
Well that's it and you can compile all your less in one shot.
I agree that initially it looks complicated but once you get used to it, you are going to find it very simple. All you need to do is create a configuration file for each project, and Grunt will take care of the rest.
It seems as it was problem with permissions. I've just set new permissions and everything works fine again. So if anyone have same problem be sure that less can create new file and that original less is readable by your app.
Sorry for wasting your time.
Edit: Problem can also occur if you are using #import url("something.less"), try dropping url part: #impurt "something.less"

Understanding the mean stack and integrating uglify.js and stylus

I'm just getting started with the MEAN stack (https://github.com/linnovate/mean), so I'm pretty sure my question is going to look very basic to an expert, so my apologies in advance!
While I think it would be a gread addition to what this stack already has to offer, I cannot manage to integrate Uglify.js and stylus
Also someone already asked this, but it would make sense to me to use Jade template for both server and public views, at least for a matter of standardization.
I have tried playing with the grunt file and server.js, renaming some files, but all I managed to achieve so far, is break the original project...
Thanks in advance!
EDIT: Just found a fork of this project which has just added support for jade templates for public views: https://github.com/tutley/mean
This post explains how to integrate Stylus pre-processing to the MEAN stack: http://to-s.tk/integrate-stylus-to-the-mean-stack/
Short version:
Move public/css to a new assets/stylesheets and rename all the .css files to .styl
Install grunt-contrib-stylus through npm's package.json, as both a dev and runtime dependency.
-Configure stylus compilation in your Gruntfile
// ...
grunt.initConfig({
// ...
watch: {
// ...
stylus: {
files: ['assets/stylesheets/**/*.styl'],
tasks: ['stylus']
},
// ...
},
// ...
stylus: {
compile: {
options: {
paths: ['assets/stylesheets/**']
},
files: [{
dest: 'public/css/',
cwd: 'assets/stylesheets/',
src: '*.styl',
ext: '.css',
expand: true
}]
}
},
// ...
});
//...
//Load NPM tasks
// ...
grunt.loadNpmTasks('grunt-contrib-stylus');
// ...
Import views stylus files (or any substylus) in common.styl using #require statements
Remove references to views or other substylesheets in head.jade.
Then all assets/stylesheets/*.styl files should be automatically compiled into public/css/*.css, as long as grunt is running. To trigger a compile without relying on watch, you can run grunt stylus.

Resources