-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 111df6d
Showing
4 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
npm-debug.log | ||
tmp | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
# load-grunt-parent-tasks | ||
|
||
> Loads de-duped grunt tasks from parent or sibling modules. | ||
## TL;DR | ||
|
||
load-grunt-parent-tasks is a Grunt library that allows you to load all of your | ||
Grunt tasks even if they are in a parent folder. This library was heavily inspired | ||
by this StackOverflow post: ["Centralise Node Modules In Project With Subproject"](http://stackoverflow.com/questions/15225865/centralise-node-modules-in-project-with-subproject), and | ||
and utilizes the `gruntcollection` feature of `grunt.loadNpmTasks`. | ||
|
||
## Description | ||
|
||
If Grunt task is loaded as a submodule then create a `grunt-collection` module | ||
in your local `node_modules` folder to trick grunt into loading dependencies | ||
from a parent folder. This might be necessary if project A contains a Gruntfile.js | ||
with dependencies X, Y, and Z, and is loaded as a npm dependency of project B | ||
which contains dependencies A, X and Y. In that scenario Npm will de-dupe | ||
project A's Npm dependencies when executing `npm install` in project B and will | ||
look like this: | ||
|
||
B | ||
├── node_modules | ||
│ ├── A | ||
│ │ ├── Gruntfile.js | ||
│ │ ├── node_modules | ||
│ │ │ └── Z | ||
│ │ └── package.json (has depencencies X,Y,Z) | ||
│ ├── X | ||
│ └── Y | ||
└── package.json (has dependencies A,X,Y) | ||
|
||
If project A's package.json contains an `install` or `postinstall` script that | ||
executes it's Gruntfile.js the Grunt task will throw 2 errors: | ||
|
||
Local Npm module "X" not found. Is it installed? | ||
Local Npm module "Y" not found. Is it installed? | ||
|
||
Project A's Grunt task will not be able to load the de-duped dependencies because | ||
they reside in the parents node_modules folder. This can be fixed by dropping in | ||
a new module which contains project A's package.json with the addition of a | ||
`keywords` property that contains `"gruntcollection"` in it's array. | ||
|
||
B | ||
├── node_modules | ||
│ ├── A | ||
│ │ ├── Gruntfile.js | ||
│ │ ├── node_modules | ||
│ │ │ ├── grunt-collection | ||
│ │ │ │ └── package.json (has dependencies X,Y,Z and 'keywords: ["gruntcollection"]') | ||
│ │ │ └── Z | ||
│ │ └── package.json (has depencencies X,Y,Z) | ||
│ ├── X | ||
│ └── Y | ||
└── package.json (has dependencies A,X,Y) | ||
|
||
Then at the beginning of your Gruntfile.js you call `grunt.loadNpmTasks('grunt-collection')`. | ||
Now Grunt will search up for the current directory to find the modules to load. | ||
|
||
## Features | ||
|
||
- Checks if the main Grunt task is a submodule of another project. | ||
- Creates a `grunt-collection` module in your local `node_modules` folder. | ||
- Creates a `grunt-collection/package.json` that is a mirror of your projects `package.json` file defined by `options.config`. | ||
- Filters out npm modules to load using globbing patterns defined in `options.pattern`. | ||
- Filters out which dependencies key to load from defined by `options.scope`. | ||
|
||
##Installation | ||
|
||
```bash | ||
npm install --save load-grunt-parent-tasks | ||
``` | ||
|
||
##Example | ||
|
||
Basic Gruntfile.js | ||
```javascript | ||
module.exports = function(grunt) { | ||
|
||
require('load-grunt-parent-tasks')(grunt); | ||
|
||
}; | ||
``` | ||
|
||
Creates the following: | ||
|
||
A | ||
├── Gruntfile.js | ||
├── node_modules | ||
│ └── grunt-collection | ||
│ └── package.json | ||
└── package.json | ||
|
||
Gruntfile.js with options | ||
```javascript | ||
module.exports = function(grunt) { | ||
|
||
require('load-grunt-parent-tasks')(grunt, { | ||
config: 'package.json', | ||
pattern: 'grunt-*', | ||
scope: 'dependencies', | ||
module: 'abc-def' | ||
}); | ||
|
||
}; | ||
|
||
// Can also be written as: | ||
module.exports = function(grunt) { | ||
|
||
require('load-grunt-parent-tasks')(grunt, { | ||
config: require('package.json'), | ||
pattern: ['grunt-*'], | ||
scope: ['dependencies'], | ||
module: 'abc-def' | ||
}); | ||
|
||
}; | ||
``` | ||
|
||
Creates the following: | ||
|
||
A | ||
├── Gruntfile.js | ||
├── node_modules | ||
│ └── abc-def | ||
│ └── package.json | ||
└── package.json | ||
|
||
## Options | ||
|
||
### config | ||
|
||
Type: `String`, `Object` | ||
Default: Path to nearest package.json | ||
|
||
### pattern | ||
|
||
Type: `String`, `Array` | ||
Default: `'grunt-*'` ([globbing pattern](https://github.com/isaacs/minimatch)) | ||
|
||
### scope | ||
|
||
Type: `String`, `Array` | ||
Default: `['dependencies', 'optionalDependencies']` | ||
|
||
### module | ||
|
||
Type: `String` | ||
Default: `'grunt-collection'` | ||
|
||
The `module` option can be changed in case `grunt-collection` ever conflicts with any other package name. | ||
|
||
## Contributing | ||
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). | ||
|
||
## License | ||
|
||
[MIT](http://psyrendust.mit-license.org/2014/license.html) © [Larry Gordon](https://github.com/psyrendust) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
/** | ||
* If Grunt task is loaded as a submodule then create a `grunt-collection` module | ||
* in your local `node_modules` folder to trick grunt into loading dependencies | ||
* from a parent folder. This might be necessary if project A contains a Gruntfile.js | ||
* with dependencies X, Y, and Z, and is loaded as a npm dependency of project B | ||
* which contains dependencies A, X and Y. In that scenario NPM will de-dupe | ||
* project A's NPM dependencies when executing `npm install` in project B and will | ||
* look like this: | ||
* | ||
* B | ||
* ├── node_modules | ||
* │ ├── A | ||
* │ │ ├── Gruntfile.js | ||
* │ │ ├── node_modules | ||
* │ │ │ └── Z | ||
* │ │ └── package.json (has depencencies X,Y,Z) | ||
* │ ├── X | ||
* │ └── Y | ||
* └── package.json (has dependencies A,X,Y) | ||
* | ||
* If project A's package.json contains an `install` or `postinstall` script that | ||
* executes it's Gruntfile.js the Grunt task will throw 2 errors: | ||
* | ||
* Local Npm module "X" not found. Is it installed? | ||
* Local Npm module "Y" not found. Is it installed? | ||
* | ||
* Project A's Grunt task will not be able to load the de-duped dependencies because | ||
* they reside in the parents node_modules folder. This can be fixed by dropping in | ||
* a new module which contains project A's package.json with the addition of a | ||
* `keywords` property that contains `"gruntcollection"` in it's array. | ||
* | ||
* B | ||
* ├── node_modules | ||
* │ ├── A | ||
* │ │ ├── Gruntfile.js | ||
* │ │ ├── node_modules | ||
* │ │ │ ├── grunt-collection | ||
* │ │ │ │ └── package.json (has dependencies X,Y,Z and 'keywords: ["gruntcollection"]') | ||
* │ │ │ └── Z | ||
* │ │ └── package.json (has depencencies X,Y,Z) | ||
* │ ├── X | ||
* │ └── Y | ||
* └── package.json (has dependencies A,X,Y) | ||
* | ||
* Then at the beginning of your Gruntfile.js you call `grunt.loadNpmTasks('grunt-collection')`. | ||
* Now Grunt will search up for the current directory to find the modules to load. | ||
* | ||
* See: | ||
* http://stackoverflow.com/questions/15225865/centralise-node-modules-in-project-with-subproject | ||
* https://github.com/gruntjs/grunt/issues/696 | ||
* http://stackoverflow.com/questions/24854215/grunt-doesnt-look-for-node-modules-in-parent-directory-like-node-does | ||
*/ | ||
'use strict'; | ||
var path = require('path'); | ||
|
||
/** | ||
* Returns the element as an array. | ||
* @method toArray | ||
* @param {*} el An array or any other data type. | ||
* @return {Array} The element as an array. | ||
*/ | ||
function toArray(el) { | ||
return Array.isArray(el) ? el : [el]; | ||
} | ||
|
||
/** | ||
* Creates a resolution for loading a package.json file. | ||
* @method resolveConfig | ||
* @param {String|Object} config The location of a package.json or the contents of the package.json. | ||
* @return {Object} The contents of the package.json. | ||
*/ | ||
function resolveConfig(config) { | ||
if (typeof config === 'string') { | ||
return require(path.resolve(config)); | ||
} | ||
return config; | ||
} | ||
|
||
function loadGruntParentTasks(grunt, options) { | ||
var log = function() { | ||
grunt.log.writeln(['[loadGruntParentTasks]'.magenta].concat(Array.prototype.slice.call(arguments)).join(' ')); | ||
}; | ||
|
||
options = options || {}; | ||
|
||
log('process.cwd(): ' + process.cwd().cyan); | ||
|
||
var isRoot = process.cwd().split(path.sep).filter(function(name) { | ||
return name === 'node_modules'; | ||
}).length === 0; | ||
|
||
log('isRoot: ' + ('' + isRoot).cyan); | ||
|
||
if (!isRoot) { | ||
var _ = require('lodash'); | ||
var findup = require('findup-sync'); | ||
var globule = require('globule'); | ||
|
||
var config = resolveConfig(options.config || findup('package.json')); | ||
var pattern = toArray(options.pattern || ['grunt-*']); | ||
var scope = toArray(options.scope || ['dependencies', 'optionalDependencies']); | ||
|
||
var gruntCollection = path.resolve('./node_modules/', (options.module || 'grunt-collection')); | ||
var gruntCollectionJson = path.join(gruntCollection, 'package.json'); | ||
|
||
var newPkg = {}; | ||
var names = []; | ||
var deps = {}; | ||
|
||
pattern.push('!grunt', '!grunt-cli'); | ||
|
||
names = scope.reduce(function (result, prop) { | ||
deps[prop] = {}; | ||
return result.concat(Object.keys(config[prop] || {})); | ||
}, []); | ||
|
||
// Create a new depenencies object of grunt tasks to load based on the | ||
// globbing pattern and scope. | ||
globule.match(pattern, names).map(function(name) { | ||
scope.forEach(function (prop) { | ||
if (config[prop][name]) { | ||
deps[prop][name] = config[prop][name]; | ||
} | ||
}); | ||
}); | ||
|
||
newPkg = _.assign({}, config, { | ||
keywords: [ 'gruntcollection' ], | ||
scripts: {} | ||
}, deps); | ||
|
||
grunt.file.mkdir(gruntCollection); | ||
grunt.file.write(gruntCollectionJson, JSON.stringify(newPkg, null, 2)); | ||
grunt.loadNpmTasks('grunt-collection'); | ||
} | ||
} | ||
|
||
module.exports = loadGruntParentTasks; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{ | ||
"name": "load-grunt-parent-tasks", | ||
"description": "Loads de-duped grunt tasks from parent or sibling modules.", | ||
"version": "0.1.0", | ||
"homepage": "https://github.com/psyrendust/load-grunt-parent-tasks", | ||
"author": { | ||
"name": "Larry Gordon", | ||
"email": "lgordon@psyrendust.com" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/psyrendust/load-grunt-parent-tasks.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/psyrendust/load-grunt-parent-tasks/issues" | ||
}, | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "http://psyrendust.mit-license.org/2014/license.html" | ||
} | ||
], | ||
"engines": { | ||
"node": ">= 0.10.0" | ||
}, | ||
"scripts": {}, | ||
"dependencies": { | ||
"findup-sync": "^0.1.3", | ||
"globule": "^0.2.0", | ||
"lodash": "^2.4.1" | ||
}, | ||
"devDependencies": {}, | ||
"keywords": [ | ||
"grunt", | ||
"load", | ||
"require", | ||
"tasks", | ||
"glob", | ||
"pattern", | ||
"match", | ||
"matchdep", | ||
"dependencies", | ||
"loadNpmTasks", | ||
"de-duped", | ||
"submodules" | ||
] | ||
} |