Grunt: have package.json and Gruntfile.js on different folders - javascript

Im having problems trying to implement grunt on diferent folders, in my root i have:
<root>/package.json
<root>/node_modules
And inside another folder, my gruntfile with diferent subfolders and files wich i work:
<root>/apps/static/Gruntfile.js
If i go to root and execute
grunt --gruntfile /apps/static/Gruntfile.js MyTaskName
I get:
Local Npm module "grunt-contrib-concat" not found. Is it installed?
Local Npm module "grunt-contrib-cssmin" not found. Is it installed?
Local Npm module "grunt-contrib-clean" not found. Is it installed?
Local Npm module "grunt-contrib-watch" not found. Is it installed?
Local Npm module "grunt-contrib-uglify" not found. Is it installed?
And i run several times npm install.
On my gruntfile.js y have
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-uglify');
I triple check and folders are ok (in fact, originally gruntfile and package where in the same folder and everything was working perfect, run several task and everything is ok). I really need to have a common package.json and node_modules on root and the Gruntfile.js on a specific project folder
Any idea whats going on? thanks in advance

Grunt makes certain assumptions regarding the location of gruntfile.js.
When you specify the location of gruntfile.js using the --gruntfile option, Grunt sets the current directory to the directory containing the specified file:
// Change working directory so that all paths are relative to the
// Gruntfile's location (or the --base option, if specified).
process.chdir(grunt.option('base') || path.dirname(gruntfile));
And when Grunt loads NPM tasks, it does so relative to the current directory:
var root = path.resolve('node_modules');
var pkgfile = path.join(root, name, 'package.json');
There is a --base option with which the current directory can be specifed, but whether or not that will solve your problem (without introducing other problems) I do not know. The simplest solution is likely to locate gruntfile.js where it wants and expects to be located.

Sometimes, it may be the need of project to have Gruntfile.js in a different folder than package.json.
I had a very similar use-case where there were multiple submodules each with its own build process, one of them was Grunt. But at the same time I wanted to have a common package.json just to avoid multiple node_modules folders being created, so that common dependencies (including transitive) use to install once. It helped in reducing install time as well as disk usage.
I was expecting a solution in Grunt itself. But as #cartant mentioned, Grunt has made certain assumptions.
So, here is what I did:
In Gruntfile.js,
Define a function:
function loadExternalNpmTasks(grunt, name) {
const tasksdir = path.join(root, 'node_modules', name, 'tasks');
if (grunt.file.exists(tasksdir)) {
grunt.loadTasks(tasksdir);
} else {
grunt.log.error('Npm module "' + name + '" not found. Is it installed?');
}
}
And instead of
grunt.loadNpmTasks('grunt-contrib-concat');
do:
loadExternalNpmTasks(grunt, 'grunt-contrib-concat');
Reference: https://github.com/gruntjs/grunt/blob/master/lib/grunt/task.js#L396

Related

How to set up wiredep with gulp and jade

I am trying to inject bower files into my jade/html using wiredep. The issue is twofold.
If I were to keep the bower_component in the root folder. Being that my server is set up from ./dist and not from root, I am unable to reach bower_compoents
If I were to install bower-components in my ./dist folder(which makes sense, as of now), and create a unique filepath for bower_components, my bower.json(it needs this to pick up proper filepath also), then it adds the extra filepath ./dist to my bower_components. However, being that my server is in ./dist, I need to remove ./dist from my filepath.
I will be answering this one for option #2. I just want to put it out there for others who want to do the same or something similar.
In the future I do want to keep bower_components in my root in order to compile them all into one js file. For now this works, as it is mostly for prototyping reasons. However, definitely interested in finding a way to make #1 work.
I set up a branch in the github here for those interested in seeing the file structure and the full gulpfile.js
What I ended up doing is installing all of the bower_components in my dist folder. I also put my bower.json there.
For the wiredep and jade magic I added the following to my gulpfile.js:
gulp.task('templates', function() {
var YOUR_LOCALS = {};
gulp.src('./app/jade/*.jade')
.pipe(jade({
locals: YOUR_LOCALS,
pretty: true
}))
.pipe(wiredep({
directory: './dist/bower_components',
bowerJson: require('./dist/bower.json'),
ignorePath: '/dist'
}))
.pipe(gulp.dest('./dist'))
});
The magic happens in one real place and that is the ignorePath option for wiredep. I am able to have the directory from the dist folder. However, being that the filepath includes ./dist, and I can't have that being that my server works from ./dist, I was able to ignore ./dist and it outputted the proper file path.
Another note, in order to includes, let's say javascript files in bower for jade, use the following syntax
// bower:js
// endbower
That's it and if this only helped one person there, it was worth it. If you have any questions feel free to leave a comment.

How to load a task using loadNpmTask in gruntfile if module is in different directory

Trying to load module: grunt.loadNpmTasks('grunt-express-server'); from an external directory.
Get an error: task .... does not exist. Have you loaded it?
Directory structure:
client/
node_modules
gruntfile
dev_server/
node_modules/
grunt-express-server
So my question is: how do you run a grunt-task using a node-module which is stored in a external directory?
You will need to use grunt.task.loadtasks pointing it to the task directory which you want to load the tasks.
In your case:
grunt.loadTasks('../dev_server/node_modules/grunt-express-server/tasks');
If you check grunt's master on github, at line 325 of task.js it requires the taskfile (.../tasks/express.js) located in the filepath you passed as parameter.
// Load taskfile.
fn = require(path.resolve(filepath))
Edit
If you're wondering if you can relocate the grunt's path to node_modules, check out this question

How do I include a .gitignore file as part of my npm module?

I am building an npm module that will generate a specific project template for certain software projects. As such, when a developer installs my npm module and runs it, I would like the program to create files and folders in a certain way.
One such file I would like to include in the project template is a .gitignore file because the software project is going to assume it will be tracked via git. However, when I call "npm install" on my module, npm renames all my .gitignore files to .npmignore files. How can I ensure that my .gitignore files are not tampered with by npm when I distribute my module?
Currently npm doesn't allow .gitignore files to be included as part of an npm package and will instead rename it to .npmignore.
A common workaround is to rename the .gitignore to gitignore before publishing. Then as part of an init script, rename the gitignore file to .gitignore. This approach is used in Create React App
Here's how to do it in Node, code from Create React App init script
const gitignoreExists = fs.existsSync(path.join(appPath, '.gitignore'));
if (gitignoreExists) {
// Append if there's already a `.gitignore` file there
const data = fs.readFileSync(path.join(appPath, 'gitignore'));
fs.appendFileSync(path.join(appPath, '.gitignore'), data);
fs.unlinkSync(path.join(appPath, 'gitignore'));
} else {
// Rename gitignore after the fact to prevent npm from renaming it to .npmignore
// See: https://github.com/npm/npm/issues/1862
fs.moveSync(
path.join(appPath, 'gitignore'),
path.join(appPath, '.gitignore'),
[]
);
}
https://github.com/npm/npm/issues/1862
Looks like this is a known issue. The answer at the bottom seems like the recommended approach. In case the issue or link ever gets destroyed:
For us, I think a better solution is going to be clear documentation that if authors wish to use .gitignore in their generators, they will need to name their files .##gitignore##, which will be a value gitignore set to the same string gitignore.
In this way, the file that gets published as a template file to npm is called .##gitignore## and won't get caught by npm, but then later it gets replaced with the string to be .gitignore.
You can see multiple commits dealing with npm issue 1862:
this project adds a rename.json:
lib/init-template/rename.json
{
".npmignore": ".gitignore",
}
this one renames the .gitignore:
templates/default/.gitignore → templates/default/{%=gitignore%}
index.js
## -114,6 +114,10 ## generator._pkgData = function (pkg) {
+ // npm will rename .gitignore to .npmignore:
+ // [ref](https://github.com/npm/npm/issues/1862)
+ pkg.gitignore = '.gitignore';
Edit: even though this answer causes .gitignore to be included in the published package (proven by unpkg), upon running npm install the .gitignore file is simply removed! So even getting NPM to include the file is not enough.
Another solution (simpler imo):
Include both .gitignore and .npmignore in the repo. Add the following to your .npmignore file:
!.gitignore
!.npmignore
Now that .npmignore will already exist in the published package, NPM won't rename .gitignore.

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?

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