nodeclient (NCLI) assists developers with managing multiple Node.js packages in an application ecosystem. With NCLI, you can readily call scripts and manage configurations.
$ npm i -g nodeclient
Note that if you do not install Nodeclient globally, Nodeclient will move itself
to your global folder on first run. On first run, Nodeclient will copy itself
to your $(npm config get prefix)
OS-specific folder:
- Mac/Linux:
$(npm config get prefix)/lib/node_modules
- Windows:
$(npm config get prefix)/node_modules
This choice was made because Nodeclient includes a bin
script.
Nodeclient links itself in your ~/.node_modules
folder such that you can
always require('nodeclient')
from within your code. Note that
~/.node_modules
is in the lookup paths of require('module').globalPaths
.
This choice was made because Nodeclient takes more than a minute to install.
This way, you only need to install Nodeclient once.
You'll need to install the Windows Subsystem for Linux. This allows you to run bash in a Windows environment, and it's used by NCLI during install.
It's difficult to manage large Node.js projects. Developers typically discover a single Git repository is more valuable than many NPM packages. Developers become confused about the purpose of a Node.js package. Lerna is one of a small number of packages that help utilize the Node.js filesystem for large projects. However, Lerna has a learning curve. Developers understand that packages are an option for segmenting large projects but are left without a tool to truly leverage the Node.js filesystem.
Multi-package development should allow you to decouple development to allow multiple developers or teams to progress your application ecosystem simultaneously. The way NCLI solves this is 1) semantically grouping files by folder within a package and 2) accessing those files with great tooling. Example folders include:
api
configs
functions
keys
scripts
tests
timers
www
You may already see how this can be useful based on a recent project you know. For instance, consider the following application ecosystem for a chatbot:
📁 /chatbot
📁 /backend
📁 /configs
📄 chatbot.json
📁 /scripts
📄 build.js
📄 start.js
📄 package.json
📁 /data
📁 /configs
📄 chatbot.json
📁 /scripts
📄 build.js
📄 package.json
📁 /frontend
📁 /configs
📄 chatbot.json
📁 /scripts
📄 build.js
📄 package.json
📁 /scripts
📄 build.js
📄 package.json
In the above ecosystem, there is a chatbot-frontend
, chatbot-data
, and chatbot-backend
package. Each package implements a configs
and scripts
folder.
Without NCLI, you'll need to manually add the build.js
to the package.json
file in each package. Each time you want to run the build
script, you'll need to change into that directory before running the npm run-script
command.
Likewise, for configs
you'll need to read each file and parse it as JSON. You need to perform error handling for bad JSON, and if you want to merge chatbot.json
you need to manually call Object.assign
.
NCLI makes this easy. Run the build script any number of ways without changing directory:
$ ncli build # runs build script in all packages.
$ ncli chatbot-backend/build # runs build in backend.
$ ncli chatbot-*/build # runs build in backend/data/frontend.
Include configs across packages with one line of code. The configs object is populated upon requiring NCLI.
require('ncli').configs['build'];
In the above example, the build object represents the configs specified across the chatbot-frontend
, chatbot-data
, chatbot-backend
and chatbot
packages. The chatbot
package inherits properties from chatbot-frontend
, chatbot-data
, and chatbot-backend
. The chatbot
package additionally overwrites any config keys specified by default. Internally, this is achieved using Object.assign
.
✅ -- Currently Supported
☐ -- Still in Development
❌ -- Unsupported
NCLI | |
Task Runner | ✅ |
Configs Management | ✅ |
Console Management | ☐ |
To utilize packages in your filesystem and treat them as node_modules, simply require the NCLI package from your code:
require('ncli');
Now you can require packages outside node_modules as though they are inside node_modules.
📁 /packages
📁 /mypackage
📄 foo.js
📄 package.json
📁 /node_modules
📁 /otherPackage
📄 package.json
📄 bar.js
📄 package.json
require('mypackage'); // great!.
require('mypackage/foo.js'); // also cool.
require('node_modules/mypackage'); // yes, even this works.
If you need a list of all files across all packages, getFiles
provides an array listing of files given a folder.
Example: You need to run SQL files across all packages, where all SQL files live inside a "sql" folder for each package.
require('ncli').getFiles('sql'); // all files as array.
If you need the contents of each file across packages, use getFileContents
. This function returns an object of file contents, keyed by filename.
Example: You need to return an aggregation of logs using string concatenation. All logs are stored via the "logs" folder for each package.
require('ncli').getFileContents('logs'); // all function files contents, keyed by filename.
If you need to require each file contained within a package folder, use requireFiles
. This calls a provided callback function on each require
call made. This allows for code execution to be controlled.
Example: You'd like to include all routes specified in the "api" folder across packages.
require('ncli').requireFiles('api', (file, pkg, code, exports) => {
}); // require every function, and run callback on each require.
If you want to read JSON files stored across packages, use getJSON
. This utilizes Object.assign(topMostPackage, subPackage, subSubPackage)
to create a JSON object with the resulting key/values. The returned object is a JSON object itself, keyed by the filenames, e.g. obj['configFilename']['key']
.
Example: You'd like to create an object of configurations as stored in the "configs" folder per package. You'd like a hierarchical value returned such that a top-most package inherits config values from sub-packages as well as the top-most package may override keys specified.
require('ncli').getJSON('configs'); // returns JSON from functions folders, keyed by filename and overwritten/inherited by top-most package via Object.assign.
Lerna: https://github.com/lerna/lerna
Grunt: https://github.com/lerna/lerna
npm-run-all: https://github.com/mysticatea/npm-run-all
Mozilla Convict: https://github.com/mozilla/node-convict
node-config-manager: https://www.npmjs.com/package/node-config-manager