5

I need to be able to use require() on a dynamic relative path - meaning that the relative path needs to change depending on the current environment.

What is the best practice for this type of situation?

I thought of something like this:

var module = require(process.env.MY_MODULES_PATH + '/my-module');

However environment variables are not very convenient.

Are there other possibilities?

  • Maybe use package.json post-install script to set the environment variable for me?
  • Maybe there's a built in solution in node I don't know about?

EDIT

I just realized that this is a special case of require() "mocking". Is there a best practice for how to mock require() for unit-tests for example?

Malki
  • 2,335
  • 8
  • 31
  • 61
  • 3
    In any case you should use [`path.join()`](https://nodejs.org/api/path.html#path_path_join_path1_path2). – Tomalak May 05 '15 at 12:57
  • Will the module always be relative to the current path? For instance you could do `require('../../some/directory/my-module');` to go up two directories and back down `some/directory/my-module`. – Randy May 05 '15 at 14:04
  • What exactly is inconvenient about environment variables? Is it just setting them correctly that's a problem? – Trott May 05 '15 at 14:32
  • it's inconvenient because it's something external to my code that could change at any time. I much prefer config files for example - they are much more obvious and intuitive – Malki May 06 '15 at 06:56
  • @Randy - no, I need to be able to route to different paths on each env, regardless of the current path. – Malki May 06 '15 at 10:29
  • (note to myself) found this - https://nodejs.org/api/globals.html#globals_require_resolve – Malki May 11 '15 at 07:50

3 Answers3

1

MockedRequire.js

var path = require('path');

function MockedRequire(module) {
    return require(path.join('/path/to/modules', module));
}

module.exports = MockedRequire;

Use:

var mymodule = require('./MockedRequire.js')('mymodule');

To be honest I haven't actually tested this but it should work without issues.

Randy
  • 4,351
  • 2
  • 25
  • 46
  • this does not solve the problem I described. I need to be able to control the `/path/to/modules` to be different on different environments. All you did was provide a module that does exactly what I already know... – Malki May 07 '15 at 15:02
  • You said you didn't want to use environment variables. So another option is to use a file with "settings". Well this could essentially be your settings file for changing the require path. So on System X you use this one where the path is `/path/to/modules` and on System Y you can use a similar file where the path is `/other/path`. Or if it's OS based then you could simply check the OS at require time (http://stackoverflow.com/questions/8683895/how-do-i-determine-the-current-operating-system-with-node-js). Based on your question you just want to be able to change the path. Here is one way. – Randy May 07 '15 at 15:21
1

Webpack needs to know what files to bundle at compile time, but expression only be given value in runtime, you need require.context:

/* If structure like:

    src -
         |
          -- index.js (where these code deploy)
         |
          -- assets - 
                     |
                      --img
*/  


let assetsPath = require.context('./assets/img', false, /\.(png|jpe?g|svg)$/); 

// See where is the image after bundling.
// console.log(assetsPath('./MyImage.png'));
// In fact you could put all the images you want in './assets/img', and access it by index: './otherImg.jpg' 
var newelement = {
    "id": doc.id,
    "background": assetsPath('./MyImage.png');
};
Ruan
  • 3,969
  • 10
  • 60
  • 87
0

I would suggest using a configuration loader. It will select your path based on your NODE_ENV variable, but its much cleaner than what you suggested because you keep all of the environment specific config within a single external file.

Examples:

martyhu
  • 161
  • 1
  • 5