pachyderm
v0.0.3
Published
Lazily require a directory, loading nothing until it is called
Downloads
4
Readme
pachyderm
Build a single javascript file that represents an entire directory.
Use this tool if you'd rather not do this.
var subModule = require('some-module/digging/through/directories/for/source');
If you'd rather do this,
var entireModule = require('some-module');
var subModule = entireModule.digging.through.directories.for.source;
then pachyderm
might be for you.
If you look at the above example and are concerned about large projects being loaded all at once, then don't worry! Pachyderm arranges the resulting module in a way so that the resource subModule
is only required when it is asked for, not when entireModule
is defined.
A quick example.
Skip to Options.
When would I use it?
Let's take an example project that might benefit from pachyderm. Here, a large collection of directories and stand alone modules were created without the intent of releasing them as an npm module. Later, this changes. Instead of creating an index.js
file that simply requires javascript files from deeper within the project, it'd be nice to generate it instead.
$> tree myProject
api
└── src
├── routes.js
├── auth.js
├── auth.spec.js
├── myProject
│ ├── myProject.js
│ └── myProject.spec.js
└── common
├── README.md
├── util.js
└── util.spec.js
apiSDK
└── components
├── preferences.js
├── purchaseOrders
│ ├── add.js
│ ├── disable.js
│ └── history.js
├── purchaseOrders.js
├── search
│ ├── account.js
│ └── keyword.js
├── transactions.js
├── util.js
└── index.js
tests
├── preferences.js
├── purchaseOrders
│ ├── add.js
│ ├── disable.js
│ └── history.js
├── purchaseOrders.js
├── search
│ ├── account.js
│ └── keyword.js
└── transactions.js
In this example, an API has been created as the main project resource, and in another directory, an API SDK has been created to abstract over it. In a final directory, there are the tests that utilize the SDK. If you split this up, you'd lose the advantage of having the project's API, SDK, and tests being featured together. As new API endpoints are added, the SDK can be updated, as well as the tests, with minimal hassle. They are all first class citizens of a singular project.
However, publishing the SDK as a node module would require that there be some sort of index.js
entry point, and creating and updating this manually is tedious, and error prone. The SDK was initially written to simplify testing the API, but over time it became useful enough to the users of the API that they asked for it to become a dependency within their applications.
In this example, pachyderm would be a good fit -- the only need for the SDK is to bundle all the files in the components
directory into a singular index.js
file. Each one stands alone as a module, and users only need to access them individually to utilize the SDK.
Again, this is used to avoid having your SDK behave like this.
var sdk = require('api-sdk');
var sdkAccountSearch = require('api-sdk/search/account');
var sdkKeywordSearch = require('api-sdk/search/keyword');
sdkAaccountSearch('12345');
sdkKeywordSearch('foobar');
And instead, would act as a singular require
statement.
var sdk = require('api-sdk');
sdk.search.account('12345');
sdk.search.keyword('foobar');
Using pachyderm, a developer would work as they normally do. Once a new endpoint is added, the SDK and tests are updated. Everything is normal. The only thing that changes is that when it comes time to release a new version of the API, the SDK can be shipped along with it. This is done by adding an .npmrc
, package.json
, .npmignore
, etc., to the ./apiSDK
directory.
Later, perhaps in some gulp/grunt task, an extra step is added to run pachyderm over the apiSDK
directory.
Generating a Directory as Javascript
var pachyderm = require('pachyderm');
pachyderm.go({ directory: './apiSDK/components/' });
This would be committed as part of the current release. Finally, you'd cd
into the apiSDK
directory and run npm publish
.
This allows the API and SDK to stay in sync in the same project, even though to the rest of the world the SDK appears to be a stand alone project.
The resulting ./apiSDK/components/index.js
would look like this:
/**
This file is auto-generated by `pachyderm`.
https://www.npmjs.com/package/pachyderm
*/
module.exports = {
get preferences() { return require('./preferences.js'); },
purchaseOrders: {
get add() { return require('./purchaseOrders/add.js'); },
get disable() { return require('./purchaseOrders/disable.js'); },
get history() { return require('./purchaseOrders/history.js'); }
},
get purchaseOrdersJs() { return require('./purchaseOrders.js'); },
search: {
get account() { return require('./search/account.js'); },
get keyword() { return require('./search/keyword.js'); }
},
get transactions() { return require('./transactions.js'); },
get util() { return require('./util.js'); }
};
Attentive readers will notice that the resulting javascript object had a key collision. There was a purchaseOrders.js
file that matched purchaseOrders/
, a directory. In this instance, the value found in the option appendToConflicts
is used to differentiate between files and directories that have the same name. By default, this is 'Js'
.
Options
Here are the defaults for running pachyderm
without specifying anything.
pachyderm.go({
directory: path.resolve('.'),
output: 'index.js',
shouldBeIndexed: function (filename) {
return _.all([
filename.slice(-3) === '.js',
filename.slice(-8) !== 'index.js',
filename.match(/node_modules/) === null
]);
},
header: [
' This file is auto-generated by `pachyderm`.',
' https://www.npmjs.com/package/pachyderm'
].join('\n'),
appendToConflicts: 'Js'
});
directory
The directory to be traversed and transformed into an object.
output
The name of the resulting javascript file. It will always be the direct child of the directory
that was traversed.
shouldBeIndexed
A function that will be applied to each file found, before it gets added to the final output.
header
A comment that will be added to the top of the file from output
. Useful for when you need to add specific instructions for contributors, especially for those who may not be aware that the file is auto-generated.
appendToConflicts
The string to be added to the end of filenames that have the same name as a directory in the same location within the javascript object.