Skip to content

Commit 7f0047c

Browse files
committed
Close #1348 Remove require.paths
Module.globalPaths is still set to a read-only copy of the global include paths pulled off of the NODE_PATH environment variable. It's important to be able to inspect this, but modifying it no longer has any effect.
1 parent ebc4d5c commit 7f0047c

File tree

8 files changed

+43
-181
lines changed

8 files changed

+43
-181
lines changed

doc/api/modules.markdown

Lines changed: 13 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -231,77 +231,24 @@ in pseudocode of what require.resolve does:
231231
c. let I = I - 1
232232
6. return DIRS
233233

234-
### Loading from the `require.paths` Folders
234+
### Loading from the global folders
235235

236-
In node, `require.paths` is an array of strings that represent paths to
237-
be searched for modules when they are not prefixed with `'/'`, `'./'`, or
238-
`'../'`. For example, if require.paths were set to:
236+
If the `NODE_PATH` environment variable is set to a colon-delimited list
237+
of absolute paths, then node will search those paths for modules if they
238+
are not found elsewhere.
239239

240-
[ '/home/micheil/.node_modules',
241-
'/usr/local/lib/node_modules' ]
240+
Additionally, node will search in the following locations:
242241

243-
Then calling `require('bar/baz.js')` would search the following
244-
locations:
242+
* 1: `$HOME/.node_modules`
243+
* 2: `$HOME/.node_libraries`
244+
* 3: `$PREFIX/lib/node`
245245

246-
* 1: `'/home/micheil/.node_modules/bar/baz.js'`
247-
* 2: `'/usr/local/lib/node_modules/bar/baz.js'`
246+
Where `$HOME` is the user's home directory, and `PREFIX` is node's
247+
configured `installPrefix`.
248248

249-
The `require.paths` array can be mutated at run time to alter this
250-
behavior.
251-
252-
It is set initially from the `NODE_PATH` environment variable, which is
253-
a colon-delimited list of absolute paths. In the previous example,
254-
the `NODE_PATH` environment variable might have been set to:
255-
256-
/home/micheil/.node_modules:/usr/local/lib/node_modules
257-
258-
Loading from the `require.paths` locations is only performed if the
259-
module could not be found using the `node_modules` algorithm above.
260-
Global modules are lower priority than bundled dependencies.
261-
262-
#### **Note:** Please Avoid Modifying `require.paths`
263-
264-
`require.paths` may disappear in a future release.
265-
266-
While it seemed like a good idea at the time, and enabled a lot of
267-
useful experimentation, in practice a mutable `require.paths` list is
268-
often a troublesome source of confusion and headaches.
269-
270-
##### Setting `require.paths` to some other value does nothing.
271-
272-
This does not do what one might expect:
273-
274-
require.paths = [ '/usr/lib/node' ];
275-
276-
All that does is lose the reference to the *actual* node module lookup
277-
paths, and create a new reference to some other thing that isn't used
278-
for anything.
279-
280-
##### Putting relative paths in `require.paths` is... weird.
281-
282-
If you do this:
283-
284-
require.paths.push('./lib');
285-
286-
then it does *not* add the full resolved path to where `./lib`
287-
is on the filesystem. Instead, it literally adds `'./lib'`,
288-
meaning that if you do `require('y.js')` in `/a/b/x.js`, then it'll look
289-
in `/a/b/lib/y.js`. If you then did `require('y.js')` in
290-
`/l/m/n/o/p.js`, then it'd look in `/l/m/n/o/lib/y.js`.
291-
292-
In practice, people have used this as an ad hoc way to bundle
293-
dependencies, but this technique is brittle.
294-
295-
##### Zero Isolation
296-
297-
There is (by regrettable design), only one `require.paths` array used by
298-
all modules.
299-
300-
As a result, if one node program comes to rely on this behavior, it may
301-
permanently and subtly alter the behavior of all other node programs in
302-
the same process. As the application stack grows, we tend to assemble
303-
functionality, and those parts interact in ways that are difficult to
304-
predict.
249+
These are mostly for historic reasons. You are highly encouraged to
250+
place your dependencies localy in `node_modules` folders. They will be
251+
loaded faster, and more reliably.
305252

306253
### Accessing the main module
307254

lib/module.js

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ Module._contextLoad = (+process.env['NODE_MODULE_CONTEXTS'] > 0);
4343
Module._cache = {};
4444
Module._pathCache = {};
4545
Module._extensions = {};
46-
Module._paths = [];
46+
var modulePaths = [];
47+
Module.globalPaths = [];
4748

4849
Module.wrapper = NativeModule.wrapper;
4950
Module.wrap = NativeModule.wrap;
@@ -217,7 +218,7 @@ Module._resolveLookupPaths = function(request, parent) {
217218

218219
var start = request.substring(0, 2);
219220
if (start !== './' && start !== '..') {
220-
var paths = Module._paths;
221+
var paths = modulePaths;
221222
if (parent) {
222223
if (!parent.paths) parent.paths = [];
223224
paths = parent.paths.concat(paths);
@@ -229,7 +230,7 @@ Module._resolveLookupPaths = function(request, parent) {
229230
if (!parent || !parent.id || !parent.filename) {
230231
// make require('./path/to/foo') work - normally the path is taken
231232
// from realpath(__filename) but with eval there is no filename
232-
var mainPaths = ['.'].concat(Module._paths);
233+
var mainPaths = ['.'].concat(modulePaths);
233234
mainPaths = Module._nodeModulePaths('.').concat(mainPaths);
234235
return [request, mainPaths];
235236
}
@@ -353,15 +354,23 @@ Module.prototype._compile = function(content, filename) {
353354

354355
require.resolve = function(request) {
355356
return Module._resolveFilename(request, self)[1];
356-
}
357-
require.paths = Module._paths;
357+
};
358+
359+
Object.defineProperty(require, 'paths', { get: function() {
360+
throw new Error('require.paths is removed. Use ' +
361+
'node_modules folders, or the NODE_PATH '+
362+
'environment variable instead.');
363+
}});
364+
358365
require.main = process.mainModule;
366+
359367
// Enable support to add extra extension types
360368
require.extensions = Module._extensions;
361369
require.registerExtension = function() {
362370
throw new Error('require.registerExtension() removed. Use ' +
363371
'require.extensions instead.');
364-
}
372+
};
373+
365374
require.cache = Module._cache;
366375

367376
var dirname = path.dirname(filename);
@@ -475,7 +484,10 @@ Module._initPaths = function() {
475484
paths = process.env['NODE_PATH'].split(':').concat(paths);
476485
}
477486

478-
Module._paths = paths;
487+
modulePaths = paths;
488+
489+
// clone as a read-only copy, for introspection.
490+
Module.globalPaths = modulePaths.slice(0);
479491
};
480492

481493
// bootstrap repl

test/fixtures/require-path/p1/bar.js

Lines changed: 0 additions & 29 deletions
This file was deleted.

test/fixtures/require-path/p1/foo.js

Lines changed: 0 additions & 23 deletions
This file was deleted.

test/fixtures/require-path/p2/bar.js

Lines changed: 0 additions & 23 deletions
This file was deleted.

test/fixtures/require-path/p2/foo.js

Lines changed: 0 additions & 23 deletions
This file was deleted.

test/simple/test-module-loading.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,15 +143,14 @@ require.extensions['.test'] = function(module, filename) {
143143
};
144144

145145
assert.equal(require('../fixtures/registerExt2').custom, 'passed');
146-
common.debug('load modules by absolute id, then change require.paths, ' +
147-
'and load another module with the same absolute id.');
148-
// this will throw if it fails.
149-
var foo = require('../fixtures/require-path/p1/foo');
150-
assert.ok(foo.bar.expect === foo.bar.actual);
151146

152147
assert.equal(require('../fixtures/foo').foo, 'ok',
153148
'require module with no extension');
154149

150+
assert.throws(function() {
151+
require.paths;
152+
}, /removed/, 'Accessing require.paths should throw.');
153+
155154
// Should not attempt to load a directory
156155
try {
157156
require('../fixtures/empty');

test/simple/test-require-cache-without-stat.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,20 @@ fs.stat = function() {
4545
};
4646

4747
// Load the module 'a' and 'http' once. It should become cached.
48-
require.paths.push(common.fixturesDir);
49-
require('a');
48+
require(common.fixturesDir + '/a');
49+
require('../fixtures/a.js');
50+
require('./../fixtures/a.js');
5051
require('http');
5152

5253
console.log("counterBefore = %d", counter);
5354
var counterBefore = counter;
5455

55-
// Now load the module a bunch of times.
56+
// Now load the module a bunch of times with equivalent paths.
5657
// stat should not be called.
5758
for (var i = 0; i < 100; i++) {
58-
require('a');
59+
require(common.fixturesDir + '/a');
60+
require('../fixtures/a.js');
61+
require('./../fixtures/a.js');
5962
}
6063

6164
// Do the same with a built-in module
@@ -67,4 +70,3 @@ console.log("counterAfter = %d", counter);
6770
var counterAfter = counter;
6871

6972
assert.equal(counterBefore, counterAfter);
70-

0 commit comments

Comments
 (0)