Skip to content

Commit

Permalink
module: add createRequire method
Browse files Browse the repository at this point in the history
This is an abstraction on top of creatRequireFromPath that can accept
both paths, URL Strings, and URL Objects.

PR-URL: nodejs/node#27405
Reviewed-By: Benjamin Gruenbaum <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Jan Krems <[email protected]>
Reviewed-By: Jeremiah Senkpiel <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
Reviewed-By: Rich Trott <[email protected]>
  • Loading branch information
MylesBorins authored and aduh95 committed Aug 27, 2020
1 parent f38bcc2 commit 8beaac3
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 8 deletions.
1 change: 0 additions & 1 deletion doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2107,7 +2107,6 @@ Type: Documentation-only
[`fs.read()`]: fs.html#fs_fs_read_fd_buffer_offset_length_position_callback
[`fs.readSync()`]: fs.html#fs_fs_readsync_fd_buffer_offset_length_position
[`fs.stat()`]: fs.html#fs_fs_stat_path_options_callback
[`os.networkInterfaces`]: os.html#os_os_networkinterfaces
[`os.tmpdir()`]: os.html#os_os_tmpdir
[`process.env`]: process.html#process_process_env
[`punycode`]: punycode.html
Expand Down
20 changes: 20 additions & 0 deletions doc/api/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,26 @@ by the [module wrapper][]. To access it, require the `Module` module:
const builtin = require('module').builtinModules;
```

### module.createRequire(filename)
<!-- YAML
added:
- REPLACEME
- v12.2.0
-->

* `filename` {string|URL} Filename to be used to construct the require
function. Must be a file URL object, file URL string, or absolute path
string.
* Returns: {[`require`][]} Require function

```js
const { createRequire } = require('module');
const requireUtil = createRequire(require.resolve('../src/utils/'));

// Require `../src/utils/some-tool`
requireUtil('./some-tool');
```

### module.createRequireFromPath(filename)
<!-- YAML
added: v10.12.0
Expand Down
48 changes: 42 additions & 6 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

const { NativeModule } = require('internal/bootstrap/loaders');
const util = require('util');
const { pathToFileURL } = require('internal/url');
const { pathToFileURL, fileURLToPath, URL } = require('internal/url');
const vm = require('vm');
const assert = require('assert').ok;
const fs = require('fs');
Expand Down Expand Up @@ -834,12 +834,48 @@ Module.runMain = function() {
process._tickCallback();
};

Module.createRequireFromPath = (filename) => {
const m = new Module(filename);
m.filename = filename;
m.paths = Module._nodeModulePaths(path.dirname(filename));
function createRequireFromPath(filename) {
// Allow a directory to be passed as the filename
const trailingSlash =
filename.endsWith(path.sep) || path.sep !== '/' && filename.endsWith('\\');

const proxyPath = trailingSlash ?
path.join(filename, 'noop.js') :
filename;

const m = new Module(proxyPath);
m.filename = proxyPath;

m.paths = Module._nodeModulePaths(path.dirname(proxyPath));
return makeRequireFunction(m);
};
}

Module.createRequireFromPath = createRequireFromPath;

const createRequireError = 'must be a file URL object, file URL string, or' +
'absolute path string';

function createRequire(filename) {
let filepath;
if (typeof filename === 'object' && !(filename instanceof URL)) {
throw new ERR_INVALID_ARG_VALUE('filename', filename, createRequireError);
} else if (typeof filename === 'object' ||
typeof filename === 'string' && !path.isAbsolute(filename)) {
try {
filepath = fileURLToPath(filename);
} catch {
throw new ERR_INVALID_ARG_VALUE('filename', filename,
createRequireError);
}
} else if (typeof filename !== 'string') {
throw new ERR_INVALID_ARG_VALUE('filename', filename, createRequireError);
} else {
filepath = filename;
}
return createRequireFromPath(filepath);
}

Module.createRequire = createRequire;

Module._initPaths = function() {
const isWindows = process.platform === 'win32';
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/experimental
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports.ofLife=42
24 changes: 23 additions & 1 deletion test/parallel/test-module-create-require.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,31 @@ require('../common');
const assert = require('assert');
const path = require('path');

const { createRequireFromPath } = require('module');
const { createRequire, createRequireFromPath } = require('module');

const p = path.resolve(__dirname, '..', 'fixtures', 'fake.js');
const u = new URL(`file://${p}`);

const req = createRequireFromPath(p);
assert.strictEqual(req('./baz'), 'perhaps I work');

const reqToo = createRequire(u);
assert.deepStrictEqual(reqToo('./experimental'), { ofLife: 42 });

assert.throws(() => {
createRequire('https://github.com/nodejs/node/pull/27405/');
}, {
code: 'ERR_INVALID_ARG_VALUE'
});

assert.throws(() => {
createRequire('../');
}, {
code: 'ERR_INVALID_ARG_VALUE'
});

assert.throws(() => {
createRequire({});
}, {
code: 'ERR_INVALID_ARG_VALUE'
});

0 comments on commit 8beaac3

Please sign in to comment.