Running tasks configured across multiple grunt.js files - javascript

I have a node app that includes multiple unpublished modules. My app's package.json includes a few git dependencies:
"module-a": "git+ssh://git#github.com:me/module-a.git",
"module-b": "git+ssh://git#github.com:me/module-b.git"
and each of those have their own grunt config. Eg in node_modules/module-a/grunt.js:
module.exports = function(grunt) {
grunt.initConfig({
lint: {
files: ['server/**/*.js', 'test/**/*.js']
},
jshint: {
options: require('./lint-ci')
}
});
grunt.registerTask('default', 'lint');
};
(they also run tests, etc, but I'm keeping it simple here)
Is there a built-in way to do this with grunt? Note that I want to keep the dependent grunt.js files for convenience when I've only changed something within that dependency.
The only solutions I have found are
build up my main grunt.js programmatically (eg, iterating over my dependencies in package.json to build the lint and test config)
call grunt multiple times using --config node_modules/module-a/grunt.js
Neither seems ideal. Is there a better way?

Just a thought but have you looked at grunt-hub?
https://github.com/shama/grunt-hub

Related

How to read and parse gruntfile programatically so I can modify it and save again?

I am creating a complex Yeoman Generator and I need to read an existing gruntfile and modify it.
Any javascript way of parsing a gruntfile is enought.
Any help will be appreciated.
imo i dont think you can achieve that by parsing js files and generating a new gruntfile.
instead of doing that you can try creating template files ex. .jade (or another template engine) so , you can produce the final gruntfile, you can look into grunt configuration object grunt.config and eventually read information, interpolate data into your template(s) and produce the final gruntfile.js.
Here's a modular approach to grunt that you can use without having to modify gruntfile.js every time you add new tasks, plugin or custom.
Add load-grunt-tasks npm module as a dev dependency: npm install load-grunt-tasks --save-dev. This plugin allows you to load all your grunt dependencies using one line of code.
Specify a folder in your project to hold all your modular configuration files. This example uses the path grunt/configs/. Each json file's name should match the it's property name in the grunt config. For example, the config for grunt-copy-config should be grunt/configs/copy.json
Copy the gruntfile.js I've posted as a public gist (stack overflow wasn't formatting the code properly). This gruntfile will automatically load your plugins and compile a config object using the project's package.json file and every .json file found in grunt/configs/. The gruntfile also loads any custom tasks I've saved into grunt/tasks/
As an alternate option - you can host your modular config objects in JavaScript files instead of json files (that's what I do). This provides me with the capability to dynamically compile my config objects if I need to. If that's something that interests you, I can share that code as well.
Thank you guys for the tips, great ideas, with your guidance I came up using a json file for each configuration:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: grunt.file.readJSON('browserify.json'),
uglify: grunt.file.readJSON('uglify.json'),
sass: grunt.file.readJSON('sass.json'),
cssmin: grunt.file.readJSON('cssmin.json'),
});
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask('default', ['browserify', 'sass']);
grunt.registerTask('production', ['browserify', 'sass', 'uglify', 'cssmin']);
};
Now I can easily modify the configuration

GruntJS setup: No targets found

The code
My latest commit is in a repo on GitHub.
The problem...
I am setting up a project (link above) using GruntJS. While trying to run any Grunt task, I'm getting a No "<insert-taskname>" targets found; a few examples:
No "browserSync" targets found.
Warning: Task "browserSync" failed. Use --force to continue.
No "jshint" targets found.
Warning: Task "jshint" failed. Use --force to continue.
No "sass" targets found.
Warning: Task "sass" failed. Use --force to continue.
What I'm doing
I am using external .js Grunt config files using the load-grunt-configs plugin. I have used a very similar setup in other projects without problems. I'm passing the shared Grunt variables which were initialized in the Gruntfile.js to each of the grunt-configs files using the options object that is a part of the load-grunt-configs plugin.
What I've tried so far...
I've tried checking my Grunt variables that are being used in the external config files, double checking my syntax and bracket matching, and searching through other stack overflow questions with no luck.
Any help would be greatly appreciated! Thank you.
I recommend using the idiomatic and built-in methods of breaking up your Gruntfile instead. 3rd party solutions tend to stray far from the Grunt APIs.
Create a folder named tasks/ and within that folder add files similar to what you're currently doing now.
Load all of those files in your main Gruntfile using grunt.loadTasks():
// Gruntfile.js
module.exports = function(grunt) {
// Initialize config.
grunt.initConfig({
pkg: require('./package.json'),
});
// Load per-task config from separate files.
grunt.loadTasks('tasks');
};
Each of those files are formatted like mini Gruntfiles. Here is an example for jshint:
// tasks/jshint.js
module.exports = function(grunt) {
grunt.config('jshint', {
app: {
options: {jshintrc: 'app/.jshintrc'},
src: ['app/**/*.js'],
},
});
grunt.loadNpmTasks('grunt-contrib-jshint');
};
Here is a full example of this solution from the creator of Grunt himself: https://github.com/cowboy/wesbos
your problem is inside your config tasks.
you are doing
module.exports = {
you need to do:
module.exports.tasks = {
other than that i recommend following kyle's answer, as it is much cleaner to use grunt's built in features!

Node.js/Grunt - Can't run Grunt's watch - why?

I am trying to use the autoprefixer css post-processor. I am following a tutorial and have installed npm. Using a npm, I then installed grunt and autoprefixer inside my project root using that package.json file: https://github.com/nDmitry/grunt-autoprefixer/blob/master/package.json
Following the tutorial, I then created this Gruntfile.js inside my project root:
module.exports = function (grunt) {
grunt.initConfig({
autoprefixer: {
dist: {
files: {
'build/style.css': 'style.css'
}
}
},
watch: {
styles: {
files: ['style.css'],
tasks: ['autoprefixer']
}
}
});
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.loadNpmTasks('grunt-contrib-watch');
};
After that the tutorial advises to use Grunt Watch using
./node_modules/.bin/grunt watch
Which results in
-bash: ./node_modules/.bin/grunt: No such file or directory
I also tried to navigate to the grunt folder inside my project, then it says
-bash: node_modules/grunt: is a directory
I also have a node_modules folder directly in my local user folder, but addressing that folder grunt also just tells me that its a folder.
Pleaser help me, why is this not working? I am willing to really learn grunt, but I am not even able to get started using the getting started guide...
Have you installed the grunt-cli? (npm install grunt-cli -g) What happens when you run grunt in your project root? The command you should be running is simply grunt watch, in your project root.
Edit: Your project root must also have a package.json file in which you define your development dependencies; e.g.
{
"name":"yourprojectname",
"version":"0.0.1",
"devDependencies":{
"grunt":"*",
"grunt-contrib-watch":"*",
"grunt-autoprefixer":"*"
}
}
if there is acutally a space in the executable name you need to put it in quotes
"./node_modules/.bin/grunt watch"
otherwise linux will run "./node_modules/.bin/grunt" with watch as a flag.
if that still doesn't work,
could be a few problems, either your ldconfig isn't updated, the files aren't set to executable, or the user you are trying to execute the command with doesn't have permission.
first try running "ldconfig" (just type and run it)
more info here
http://www.cyberciti.biz/tips/linux-shared-library-management.html
chmod -x the files to make them executable.
any luck?

Grunt template task

In my index.html file, I would like to include a different javascript source file in production than I use in development. I am using requirejs in development and would like to use the single minified file in production.
The project
https://github.com/CaryLandholt/AngularFun
does exactly what I would like.
In my project, I am trying to get grunt to run the template task but I am running into problems with it knowing how to complete the task: "Task 'template' not found".
I don't see anything obvious in the AngularFun project's dependencies that would allow grunt to correctly process the template task, but the project builds correctly. What am I missing?
I am asking here because I have seen several questions dealing with different files in prod/dev and the AngularFun project looks like a nice way to do it.
I have a Gruntfile with the following in the initConfig:
template: {
dev: {
files: {
"index.html": "index.template"
},
environment: "dev"
},
prod: {
files: "<% template.dev.files %>",
environment: "prod"
}
}
I also have the following as my grunt default:
grunt.registerTask("default", ["template:dev"]);
The template task is located in grunt-hustler, an npm package, which must be listed as a dependency in the package.json file in order for npm install to locate it and make it available for your project.
My documentation for grunt-hustler is seriously lacking.

Working project structure that uses grunt.js to combine JavaScript files using RequireJS?

I have some projects that use RequireJS to load individual JavaScript modules in the browser, but I haven't optimized them yet. In both development and production, the app makes a separate request for each JavaScript file, and now I would like to fix that using Grunt.
I have tried to put together a simple project structure to no avail, so I'm wondering if someone can provide a working example for me. My goals are the following:
In development mode, everything works in the browser by issuing a separate request for each required module. No grunt tasks or concatenation are required in development mode.
When I'm ready, I can run a grunt task to optimize (combine) all of the JavaScript files using r.js and test that out locally. Once I'm convinced the optimized application runs correctly, I can deploy it.
Here's a sample structure for the sake of this conversation:
grunt-requirejs-example/
grunt.js
main.js (application entry point)
index.html (references main.js)
lib/ (stuff that main.js depends on)
a.js
b.js
requirejs/
require.js
text.js
build/ (optimized app goes here)
node_modules/ (necessary grunt tasks live here)
Specifically, I'm looking for a working project structure that I can start from. My main questions are:
If this project structure is flawed, what do you recommend?
What exactly needs to be in my grunt.js file, especially to get the r.js optimizer working?
If all of this isn't worth the work and there's a way to use the grunt watch task to automatically build everything in development mode every time I save a file, then I'm all ears. I want to avoid anything that slows down the loop from making a change to seeing it in the browser.
I use the grunt-contrib-requirejs task to build project based on require.js. Install it inside your project directory with:
npm install grunt-contrib-requirejs --save-dev
BTW: --save-dev will add the package to your development dependencies in your package.json. If you're not using a package.json in your project, ignore it.
Load the task in your grunt file with:
grunt.loadNpmTasks('grunt-contrib-requirejs');
And add the configuration to your grunt.initConfig
requirejs: {
production: {
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js",
out: "path/to/optimized.js"
}
}
}
Now you're able to build your require.js stuff into a single file that will be minimized with uglifyjs by running grunt requirejs
You can bundle a set of different tasks into some sort of main task, by adding this to your grunt file
grunt.registerTask('default', ['lint', 'requirejs']);
With this, you can simply type grunt and grunt will automatically run the default task with the two 'subtasks': lint and requirejs.
If you need a special production task: define it like the above
grunt.registerTask('production', ['lint', 'requirejs', 'less', 'copy']);
and run it with
grunt production
If you need different behaviors for 'production' and 'development' inside i.e. the requirejs task, you can use so called targets. In the configuration example above it's already defined as production. You can add another target if you need (BTW, you can define a global config for all targets by adding a options object on the same level)
requirejs: {
// global config
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js"
},
production: {
// overwrites the default config above
options: {
out: "path/to/production.js"
}
},
development: {
// overwrites the default config above
options: {
out: "path/to/development.js",
optimize: none // no minification
}
}
}
Now you can run them both at the same time with grunt requirejs or individually with grunt requirejs:production, or you define them in the different tasks with:
grunt.registerTask('production', ['lint', 'requirejs:production']);
grunt.registerTask('development', ['lint', 'requirejs:development']);
Now to answer your questions:
I would definitely use a subfolder in your project. In my case I use a 'src' folder for development that is build into a 'htdocs' folder for production. The project layout I prefere is:
project/
src/
js/
libs/
jquery.js
...
appname/
a.js
b.js
...
main.js // require.js starter
index.html
...
build/
... //some tmp folder for the build process
htdocs/
... // production build
node_modules/
...
.gitignore
grunt.js
package.json
see above
You can do so, but I wouldn't recommend to add requirejs to the watch task, it's a resource hungry task and it will slow down your machine noticeable.
Last but not least: Be very cautious when playing around with r.js. Especially when you want to optimize the whole project with r.js by adding a modules directive to your config. R.js will delete the output directory without asking. If it happens that it is accidentally configured to be your system root, r.js will erase your HDD. Be warned, I erased my whole htdocs folder permanently some time ago while setting up my grunt task... Always add keepBuildDir:true to your options when playing around with the r.js config.

Categories