How does react avoid using require("../../Path/To/Module"), and just use require("Module") - node.js

As far as I've seen, npm modules can be require() without a path:
require("module") // --> npm module
and local modules are require() using a path:
require("./module") // --> local module, in this directory
require("../../path/to/module") // path to directory
In react.js, modules are required without a path. See here for example. I'm wondering how they achieve this.

Apparently it uses rewrite-modules Babel plugin with module-map module (see gulpfile.js.)
There's also this Babel plugin that you can use to achieve the same behavior.

If you're using Webpack, you can add path/to/modules into resolve.modulesDirectories array and it will work similarly to requiring from node_modules instead of using relative paths.
resolve: {
modulesDirectories: ['path/to/modules', 'node_modules'],
},
and then
var foo = require('foo');
// Instead of:
// var foo = require('/path/to/modules/foo');
// or
// var foo = require('../../foo');

Related

How to dynamically import package.json dependencies based on environment variables?

How could I add a script to my package.json file that would allow me to dynamically use a local file instead of a package version based on an environment variable?
"dependencies": {
"dynamic-dependency": "$(process.env.NODE_ENV !== 'dev' ? '^1.0.7' : 'file:../local-path-to-package')"
}
You can't do this in package.json, which is non-executable JSON file. The JSON variant used in package.json doesn't even support comments :). The purpose of package.json is to specify which dependencies are installed into node_modules, and that's it. With those dependencies installed, they can be used by Node at runtime, which locates them using the module resolution algorithm:
If the module identifier passed to require() is not a core module, and does not begin with '/', '../', or './', then Node.js starts at the parent directory of the current module, and adds /node_modules, and attempts to load the module from that location. Node.js will not append node_modules to a path already ending in node_modules.
So you can't use NPM/package.json for this. But, I see that you tagged your question with React, so if you are using Webpack, you can solve this issue in your Webpack config. This can be done with resolve.alias:
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
'dynamic-dependency': process.env.NODE_ENV !== 'dev' ? 'dynamic-dependency' : path.resolve(__dirname, '../local-path-to-package'),
},
},
};
I have not used other JS bundlers, but I would have to think Parcel/Rollup etc support this kind of configuration as well.

How can I keep "require" working for dynamic expressions

I want to bundle a Node.js script, which somewhere calls require(expression). After bundling the script with webpack, require fails. This is a super simplified example:
// main.js
const x = require(process.argv[2])
console.log(x)
I would like to either have a "normal" require for this case or tell webpack to include a specific file which I know will be required in the future (after bundling). To stick with this example, I know the value of process.argv[2] ahead of bundling.
Note: The code doing the expression based require is a dependency, so I cannot tweak require code.
This is my webpack.config.js
module.exports = {
entry: './test.js',
output: {
filename: 'test.js'
},
target: 'node'
}
The require path is relative to the file it is used in. So you'll need to figure out the path from where require is executing to the file it's loading from the parameter. Then prepend the relative part to the parameter.

Unable to use requireJS and Node's Require in the same TypeScript project

I have a typescript project targeted at both Node and the browser. I'm using Node's require() in some scripts and requireJS's require() in others. My project directory looks like this:
myProject
\-- a.ts
\-- b.ts
\-- node.d.ts
\-- require.d.ts
where a.ts contains:
/// <reference path="./node.d.ts" />
var cp = require('child-process');
var a = 'hello world'
export = a
and b.ts contains:
/// <reference path="./require.d.ts" />
require('hello',function(x){console.log('world')});
var b = 'hello world'
export = b
and where require.d.ts and node.d.ts are obtained from DefinitlyTyped.
When I compile my project, I get these errors:
b.ts(2,1): error TS2346: Supplied parameters do not match any signature of call target.
require.d.ts(396,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'require' must be of type 'NodeRequire', but here has type 'Require'.
I use this idiom to determine which modules to load, so I'm not loading a node module in the browser or vice versa.
if(typeof module !== 'undefined' && module.exports){
// We're in a Node process
}else{
// We're in an AMD module in the browser:
}
Is there a way to use both of these .d.ts files in the same project. It seems using them in separate modules is not enough.
Is there a way to use both of these .d.ts files in the same project
I highly recommend going with commonjs everywhere. That is what the React community has spearheaded and it's a much simpler workflow. Just use CommonJS + webpack (to get lazy require.ensure from here). 🌹
There's also a quickstart for TypeScript in the browser environment.
In the end what I needed was the ability to require() JS content that is compiled on the fly by the server -- which doesn't seem to work with web-pack.
To suppress the errors from the typescript compiler in the original question, I commented out this line from require.d.ts (the RequireJS declaration file):
declare var require: Require;
and I used the {foo:bar}['f'+'oo'] trick to get tsc to 'forget' the type of the ambient require variable when assigning it to the typed requirejs variable, like so:
var requirejs:Require; // requirejs
if(typeof module !== 'undefined' && module.exports){
// We're in a Node process
requirejs = require('requirejs');
}else{
// We're in an AMD module in the browser:
requirejs = {require:require}['req'+'ire'];
}
// use requirejs for dynamic require statements
requirejs(gather_requirements(),do_things);

How can I make webpack skip a require

How can I make webpack skip occurences of
require('shelljs/global');
in my source files? I want to make a bundle of my source files but keep the require('shelljs/global') in the files and not bundle shelljs/global.
If you store the path in a variable then IgnorePlugin will not work. Though you still could do:
const myCustomModule = eval('require')(myCustomPath)
for new comers, on webpack 2+ the way to do this is like so:
module.exports = {
entry: __dirname + '/src/app',
output: {
path: __dirname + '/dist',
libraryTarget: 'umd'
},
externals: {
'shelljs/globals': 'commonjs shelljs/global'
}
};
the bundle will contain a verbatim require:
require('shelljs/global');
read on more supported formats on webpack's config guide and some good examples here
You can use Ignore Plugin (webpack 1) / Ignore plugin (webpack 2).
Add plugin in webpack.config.js:
plugins: [
new webpack.IgnorePlugin(/shelljs\/global/),
],
If require is in the global namespace and this is why you want Webpack to ignore it, just do window.require()
This should be a last resort option, but if you are certain that your JS file is always parsed by Webpack, and nothing else:
You could replace your require() calls with __non_webpack_require__()
Webpack will parse and convert any occurrence of this and output a normal require() call. This will only work if you are executing in NodeJS OR in a browser if you have a global require library available to trigger.
If webpack does not parse the file, and the script is run by something else, then your code will try to call the non-converted __non_webpack_require__ which will fail. You could potentially write some code that checks earlier in your script if __non_webpack_require__ exists as a function and if not, have it pass the call on to require.
However, this should be temporary, and only to just avoid the build errors, until you can replace it with something like Webpack's own dynamic imports.
Here a trick
const require = module[`require`].bind(module);
Note the use of a template string
If some files contains nested requires and You want to ignore them, You can tell webpack to not do parsing for these specific files.
For example if swiper.js and vue-quill-editor.js had inner requires this would be how to ignore them.
module.exports = {
module: {
noParse: [
/swiper.js/,/quill/
],

How to have path alias in nodejs?

Let's say i have following codes:
var mod1 = require('../../../../ok/mod1');
var mod2 = require('../../../info/mod2');
It's not pretty coding like above, i am wondering if there is a way to configure the root resolver just like webpack-resolve-root in nodejs?
So far as i know, the NODE_PATH can be used to replace the root of node_modules, but that's not what i want. I'd like to have the resolver to resolve multiple folders in order.
Updated answer for 2021.
nodejs subpath imports have been added in: v14.6.0, v12.19.0
This allows for you to add the following to package.json
"imports": {
"#ok/*": "./some-path/ok/*"
"#info/*": "./some-other-path/info/*"
},
and in your .js
import mod1 from '#ok/mod1';
import mod2 from '#info/mod2';
There is an npm package called module-alias that may do what you are looking for.
The best way to approach this would be to use a global (config) container.
In most cases you will have a config file in your application. In this config you can add a property which will be an object containing all absolute paths to files/folders.
Because config files are used at the start of you application, you just do the following:
var config = require("./config.js");
//config = {... , path: {"someModule": "/absolute/path/to", "someModule2": "/absolute/path/to"...}}
global.CONFIG_CONTAINER = config
Later on in your application you can just use
var myModule = require(CONFIG_CONTAINER.path.someModule)
// + concat if you are looking for a file
In case you have some complex paths and you need a more dynamic system, you can always implement a function inside the config that will build paths for you. ( config.makePath = function(){...} )
That should take care of it in a nutshell.

Resources