Dynamic index module boilerplate creator for your Node or client packaged ES6 submodules. Indexr overcomes some of the limits of ES6 modules by autogenerating module index boilerplate code usually as part of a precompilation stage in your build process.
##Contents
When creating great applications it is important to provide systems that allow features to be implemented and maintained as discrete units of code.
It is also important to avoid magic runtime binding where functionality is implied by folder structure or some other magic variables or constants.
ES6 modules have come along and they are a great way to organise JavaScript code. They are declarative and statically analysable. Very importantly what you see is what you get.
However they lack the ability to autoload modules on the fly based on a dynamic folder structure such as the kind you would see in a modular framework that needs to bind dynamic packages of code together.
It is for this reason I created the Indexr open source project.
What Indexr does is it takes a folder, searches for any 'module' folders based on globs you provide and generates index files that export all the 'submodules' within the 'module' folders in whatever way you choose.
Let's look at an example:
$ indexr . \
--out reducers.js \
--modules **/modules/ \
--submodules */reducer.js \
--direct-import
--named-exports
This example does the following:
- Use the current folder as a root folder
- Find module folders nested within this root folder that have the name
modules
- Within each
modules
folder find subfolder that contains anreducer.js
file - Create an ES6
reducers.js
file within each 'modules' folder that directly imports the submodule'sreducer.js
file. - Export the reducers as named exports.
You can also do the same thing via Node API
import indexr from 'indexr';
indexr(__dirname, {
outputFilename: 'reducers.js',
modules: '**/modules/',
submodules: '*/reducer.js',
directImport: true,
namedExports: true,
});
http://github.com/ryardley/indexr
Install locally and use the node API or use indexr in npm scripts (recommended).
# better
npm install indexr --save
Tip
Try adding ./node_modules/.bin
to your path for your terminal. That way you can get access to local cli programs as you enter your npm projects.
# ~/.bash_profile
...
PATH=$PATH:./node_modules/.bin
...
Alternatively if you have to you can install globally and use indexr in the bash prompt.
# You probably don't want to do this
npm install indexr -g
You can use indexr as either a command-line program or a node API.
Assuming we have a folder tree like this:
./modules
├── bar
├── baz
└── foo
We run this in the root:
$ indexr .
Within any subfolder it finds called 'modules' you will find it will create a file called ./index.r.js
that contains the following:
/**
This file is autogenerated by indexr.
Check this file into source control.
Do not edit this file.
For more information: http://github.com/ryardley/indexr
**/
import bar from './bar';
import baz from './baz';
import foo from './foo';
export default [
bar,
baz,
foo
];
/** End autogenerated content **/
Alternatively if we run this:
$ indexr . --named-exports
Within any subfolder it finds called 'modules' you will find it will create a file called ./index.r.js
that contains the following index with named exports:
/**
This file is autogenerated by indexr.
Check this file into source control.
Do not edit this file.
For more information: http://github.com/ryardley/indexr
**/
export { default as bar } from './bar';
export { default as baz } from './baz';
export { default as foo } from './foo';
/** End autogenerated content **/
For help with the commandline program you can try the help flag:
$ indexr --help
Usage: indexr <rootFolder> [options]
Options:
-h, --help output usage information
-V, --version output the version number
-e --ext <string> Remove this extension from imports.
-o --out <filename> The name of the output file.
-d --direct-import Directly import files as opposed to folders.
-m --modules <string> Glob string that determine which folders hold modules.
-i --modules-ignore <string> Glob string that determine which folders are ignored.
-5 --es5 Use ES5 template for index output.
-n --named-exports Use named exports instead of arrays.
-s --submodules <string> Glob string that determine what is a submodule.
-g --submodules-ignore <string> Glob string that determine which submodules are ignored.
-w --watch [string] Files to watch as a glob string.
NOTE: All commandline globs must be enclosed in quotes!!
The following example will look in the ./app
folder for modules folders identified by '**/modules/' and then identify submodules given by '*/server.js' and use them to write a file to ./app/modules/server.js
.
$ indexr ./app --out 'server.js' --modules '**/modules/' --submodules '*/server.js'
We can change the glob used to find the modules folder which is useful if you don't want to have your modules under 'modules'.
$ indexr . --modules '**/features/'
We can change the output filename of the file indexr produces.
$ indexr . --out 'index.js'
We can also filter which modules and entry files we want by setting some options. the following will only include modules which contain reducer.js
files.
$ indexr . --submodules '*/reducer.js'
$ indexr . --es5
If the es5 flag is set Indexr can export the template in es5/common js style.
/**
This file is autogenerated by indexr.
Check this file into source control.
Do not edit this file.
For more information: http://github.com/ryardley/indexr
**/
var foo = require('./foo');
var bar = require('./bar');
var baz = require('./baz');
module.exports = [foo, bar, baz];
/** End autogenerated content **/
By using the --named-exports
flag it will export the submodules as named exports:
$ indexr . --named-exports
export { default as bar } from './bar';
export { default as baz } from './baz';
export { default as foo } from './foo';
By using the --direct-import
flag it will include the searched files specifically in the import statements:
$ indexr . --submodules '*/server.js' --direct-import
import foo from './foo/server.js';
import bar from './bar/server.js';
export default [foo, bar];
You can watch files using the --watch
flag:
$ indexr . --watch
indexr(rootFolder:String, options?:Object):Promise
argument | notes |
---|---|
rootFolder |
The root folder to work from. |
options |
An object containing configuration options |
option | default | notes |
---|---|---|
directImport |
false |
Include the searched files in the import statements. |
es5 |
false |
Boolean flag to use es5 commonjs style modules over es6. This is overridden if a template function |
exts |
[] |
Remove this extension from the imported files. A usefull example might be ['js'] which you would use if you would prefer to import ./foo/server instead of ./foo/server.js |
modules |
'\*\*/modules/' |
A glob or array of globs pathed to the rootFolder that will determine which folders are module holders. If this is ommitted defaults to **/modules/ . |
modulesIgnore |
undefined |
A glob pathed to the rootFolder that will determine which folders are not module holders. If this is ommitted nothing is ignored. |
namedExports |
false |
This flag will ensure that indexes use named exports instead of arrays. |
submodules |
'\*/' |
A glob pathed to each module holder folder that will determine which submodules are imported to the index. Defaults to */index.js |
submodulesIgnore |
undefined |
A glob pathed to the rootFolder that will determine which folders are not considered submodules. If this is ommitted nothing is ignored. |
template |
indexr's es6 template | A template function the function should takes an array of relative module paths and output the module file as a string |
outputFilename |
'index.r.js' |
The name of the output file. This file will be added to each module folder. |
watch |
false |
Either a boolean value or a glob that represents files for chokdir to watch. |
Here is an example
import indexr from 'indexr';
import es6 from 'indexr/dist/modules/template/es6'; // This will change don't do this.
indexr(__dirname, {
es5: false,
modules: '**/modules/',
submodules: '*/index.js',
directImport: true,
exts: ['js', 'jsx'],
namedExports: false,
outputFilename: 'index.js',
template: es6, // or some function that takes an array of module paths and spits out a template
watch: false,
})
.then((err, result) => {
console.log('Files have been indexed!');
});
NOTE: dont load the template from the dist file as it's location may change. This is only for illustration purposes.
Start the gulp watcher.
$ gulp
Run the tests
$ npm run test-watch
Edit the code.
If anything is unclear or wrong in these docs please let me know by submitting an issue