Best way to load modules node.js - javascript

My project has got many folders and I often load my own modules in node.js in the following way:
var request = require("request"),
config = require("../../../modules/config"),
urls = require("../../../modules/urls");
I sometimes move the folders around and the path changes, so I need to adjust the ../ part manually.
I don't want to move my modules into the node_modules folder, but I'd like to load the modules in the following way:
var request = require("request"),
config = require("config"),
urls = require("urls");
or
var request = require("request"),
config = require("modules/config"),
urls = require("modules/urls");
What are my options?

New Answer:
Relative paths seem to be the simplest choice after all, it allows you to run your script from any location.
var config = require("../../config");
Old answer:
I found out that, while not ideal, there's also the possibility to use process.cwd().
var request = require("request"),
config = require(process.cwd() + "/modules/config");
or, if the process.cwd() is set to a global variable in the main js file
global.cwd = process.cwd();
then
var request = require("request"),
config = require(global.cwd + "/modules/config"),
urls = require(global.cwd + "/modules/urls");

You can try to do the following, based on some conditions
if the scripts are exclusively written for your application, meaning it won't work with any other application, and the scripts don't have any dependencies place them under modules directory and try to create expose a variable such as global.basepath and using path.join to construct the filepath and require it.You could also inject module variable after you require them at the main script of your app.
main.js
var config = require('modules/config.js')(_,mongoose,app);
modules/config.js
module.exports=function(_,mongoose,app){
return function(){
// _,mongoose,app
this.loadConfigVariable..
}
}
if the scripts are not one-files that have separate tests, require other vendor modules in order to be executed then create individual node modules and publish them to a registry for convenience when installing the main application.
Just as express does, there is the main application express and there are modules that express uses such as express-validation which in turn has its own dependencies.

You could add a symlink in node_modules, pointing to wherever your modules are.
For example, add a symlink named "my_modules", referencing '../foo/bar/my_modules'. Then, your requires will look like
var config = require('my_modules/config');
var urls = require('my_modules/urls');

Related

Avoiding relative require paths in Node.js

I prefer to import dependencies without lots of relative filesystem navigation like ../../../foo/bar.
In the front-end I have traditionally used RequireJS to configure a default base path which enables "absolute" pathing e.g. myapp/foo/bar.
How can I achieve this in Node.js?
What you can do is use require.main.require which would always be the module path of the starting file. See https://nodejs.org/api/modules.html#modules_accessing_the_main_module
This means, that when you run
const x = require.main.require('some/file/path/y')
It would require it based on the base path of your starting file (that was invoked , node app.js meaning the app.js file).
Other options include using process.cwd() to get the starting path of your app, but that would be depending on where you invoke your node process, not the location of the file. Meaning, node app.js would be different than of you would start it one level up, node src/app.js.
Just to add to the other answer, you can put this few lines in your main file:
(function (module) {
let path = require('path')
let __require = module.constructor.prototype.require
let __cpath = __dirname
module.constructor.prototype.require = function (str) {
if (str.startsWith('package:')) {
let package = str.substr(8)
let p = path.resolve(__dirname, package)
return __require(p)
} else {
return __require(str)
}
}
})(module)
It extends your require in such way:
if path begins with package: (i.e. package:src/foo/bar) it translates it to require('/absolute/path/to/your/app/src/foo/bar'),
if it doesn't start with package: then it behaves like a normal require would.

Obtaining path in nodejs

My Directory structure is something as below:
app/
server/
api/
user/
controller.js
images/
image1.jpeg
The problem is when reading image1.jpeg within controller.js I have to use a string like
var imagePath = __dirname + '/../../../images/images1.jpeg';
fs.readFile(imagePath, ()....
now the above works FINE. however what I don't like is this string '/../../../'
is there a better way to access files in the images/ folder ?
You could use path.relative. You'd probably want to save these as constants but you could do the following to make things more readable.
Pass in the path to your current directory as the first parameter and the path to the image itself from the same parent directory (in this case app) and it will return the relative path from the current directory to the image.
// returns '/../../../images/images1.jpeg'
var relativePathToImage = path.relative(
'/app/server/api/user',
'/app/images/images1.jpeg');
var pathToImage = __dirname + relativePathToImage;
Short of passing the path to app/images to the controller, that's about as good as you can do.
You could traverse the module.parent references until module.parent isn't set, if you can safely make assumptions about where your main script is. For example, if your main script is app.js inside app/, you could do something like:
var path = require('path');
var topLevel = module;
while (topLevel.parent)
topLevel = topLevel.parent;
topLevel = path.dirname(topLevel.filename);
var imagesBasePath = path.join(topLevel, 'images');
// ...
fs.readFile(path.join(imagesBasePath, 'images1.jpeg'), ...);
I use an npm module called node-app-root-path to help me manage my paths within the NodeJS application.
See:
https://github.com/inxilpro/node-app-root-path
To obtain the application's root path you would do require('app-root-path');
Example:
global.appRoot = require('app-root-path');
var imagePath = global.appRoot.resolve('server/images');
var img1 = imagePath + '/image1.jpeg';
fs.readFile(img1, ()....
Not sure whether is it a good idea or not but for this case I have stored the appRoot as a global variable and this is so that it will be available anywhere within my NodeJS application stack, even to some of my other NodeJs libraries.
There are many other usages noted in their documentation, have a look and see if it helps you too.

Is it possible to require modules from outside of your project directory without relative paths?

I'm trying to build a local library of JS modules to use in Node projects.
If a new project lives in /Users/me/projects/path/to/new/project/ and my library files are located in /Users/me/projects/library/*.js is there a way to access those files without using a relative path?
In /Users/me/projects/path/to/new/project/app.js you can require foo.js like so:
var foo = require('../../../../../library/foo') and that will work but that's clunky and if files move you'd have to update your relative paths.
I've tried requireFrom and app-module-path with no luck as they are relative to a project root.
Any ideas for how to require files from outside of your project dir?
Thanks in advance!
var librarypath = '/Users/me/projects/library/';
// or if you prefer...
// var librarypath = '../../../../../library/';
var foo = require(librarypath + 'foo.js');
... or dressed up a bit more ...
function requirelib(lib){ return require('/Users/me/projects/library/'+lib+'.js'); }
var foo = requirelib('foo');
var bar = requirelib('bar');
I had the same problem many times. This can be solved by using the basetag npm package. It doesn't have to be required itself, only installed as it creates a symlink inside node_modules to your base path.
const localFile = require('$/local/file')
// instead of
const localFile = require('../../local/file')
Using the $/... prefix will always reference files relative to your apps root directory.
Disclaimer: I created basetag to solve this problem

Switching Development/Test/Production variables in Javascript

I am trying to search the best approach to manage different values for same variables in Devlopment, Test and Production environment.
For example, I have variable jsonFile which can be:
var jsonFile = http://localhost:63342/json/appsconfig.json
for development env
var jsonFile = http://192.168.35.59/applications/json/appsconfig.json
for test env
var jsonFile = http://example.com/applications/json/appsconfig.json
for production env
I am trying to read a lot about Frontend Development Stack, but I am confused about what tool to use. I will use Google Closure Tools for minification, can it be also useful to switch variable values? Or can it be considered a Grunt task (even if I am not able to understand how to properly configure Grunt tasks...)?
What might be better is to write the JSON into a JS file that is part of your build artifacts. Something like file-creator that can write a file like so (using a simplistic setup that can obviously be made more dynamic).
In the top of your module.exports for grunt tasks, load in the config file into a var like:
var configData = grunt.file.readJSON('../config/appsconfig.json'),
Then write to a new JS file using the grunt file-creator module
"file-creator": {
'dev': {
'build/config.js': function (fs, fd, done) {
fs.writeSync(fd,
'var yourSiteHere = yourSiteHere || {}; yourSiteHere.config = '
+ JSON.stringify(configData) + ";"
);
done();
}
}
}
Then load this JS file into the page (perhaps even minify it using a separate grunt task). You will be then able to refer to the config data like so:
var apiEndPoint = yourSiteHere.config.api.apiEndPoint,
apiKey = yourSiteHere.config.api.apiKey;

Where do we put node modules we install by npm in a Meteor project?

I followed the github meteorirc project's lead and put them in /public/
I installed my node modules via npm from inside /public/ and therefore I have a /public/node_modules/ directory.
I don't think this is the 'proper' or 'standard' place for them because according to the Meteor docs...
Meteor gathers all your JavaScript files, excluding anything under the
client and public subdirectories, and loads them into a Node.js server
instance inside a fiber
The code to load is in the server dir and server js files and looks like this.
var require = __meteor_bootstrap__.require;
var path = require("path");
var fs = require('fs');
var base = path.resolve('.');
if (base == '/'){
base = path.dirname(global.require.main.filename);
}
var Twit;
var twitPath = 'node_modules/twit';
var publicTwitPath = path.resolve(base+'/public/'+twitPath);
var staticTwitPath = path.resolve(base+'/static/'+twitPath);
if (path.existsSync(publicTwitPath)){
Twit = require(publicTwitPath);
}
else if (path.existsSync(staticTwitPath)){
Twit = require(staticTwitPath);
}
else{
console.log('WARNING Twit not loaded. Node_modules not found');
}
Based on the docs this is not standard and I don't believe I should be doing it this way. Yet, it works both on my dev platform and in production at deploy meteor.com.
Where in the directory structure of the project should node modules be installed so that they work locally and upon deployment at meteor.com or elsewhere?
cd /usr/local/meteor/lib/ && npm install <module>
To use Npm modules in Meteor its adding the npm module in.
First you need to add a npm package adapter such as meteorhacks:npm
meteor add meteorhacks:npm
Then start your meteor app by running meteor, you will notice a new packages.json file in your project
Add in modules like this (you need to explicitly define a version)
{
"request" : "2.53.0"
}
Then you can use the npm modules in your meteor app, use Meteor.npmRequire instead of require
var request = Meteor.npmRequire("request")
Meteor takes lib/node_modules from the development bundle and makes a symbolic link or copies it to server/node_modules, which is in the hidden .meteor sub folder under your project.
So, if you cd into the lib directory of the development bundle or into server directory of the .meteor folder (I believe it is in build); you will be able to use the node modules. If you have trouble loading them, you might want to check out this question.
You have to add bundle folder to the path:
var staticTwitPath = path.resolve(base+'/bundle/static/'+twitPath);
Here is my working sample in coffeescript, node_modules are in public folder:
# loading node_modules from public folder
require = __meteor_bootstrap__.require
path = require("path")
fs = require('fs')
cheerioPath = 'node_modules/cheerio'
base = path.resolve('.')
if base == '/'
base = path.dirname(global.require.main.filename)
publicPath = path.resolve(base+'/public/'+cheerioPath)
staticPath = path.resolve(base+'/bundle/static/'+cheerioPath)
if path.existsSync(publicPath)
cheerio = require(publicPath)
else if path.existsSync(staticPath)
cheerio = require(staticPath)
else
console.log('node_modules not found')
Good luck!
This helped me a lot including a syntax highlighting package! Thanks!
I use a little helper though, as I think this will not be the last npm package I'll use ;)
meteorNpm = do() ->
require = __meteor_bootstrap__.require
path = require 'path'
fs = require 'fs'
base = path.resolve '.'
if base is '/'
base = path.dirname global.require.main.filename
meteorNpm =
# requires npm modules placed in `public/node_modules`
require: (moduleName) ->
modulePath = 'node_modules/' + moduleName
publicPath = path.resolve(base + '/public/' + modulePath)
staticPath = path.resolve(base + '/bundle/static/' + modulePath)
if path.existsSync(publicPath)
module = require publicPath
else if path.existsSync(staticPath)
module = require staticPath
else
module = null
return module
Use it like this:
highlight = meteorNpm.require "highlight.js"
I am using such script which nicely install all node.js dependencies. It behaves similar to official support in Meteor engine branch (it installs dependencies at runtime) but it supports also installing from git repositories and similar goodies.

Categories

Resources