node.js
2.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import { isWindows } from './system';
import log from './logger';
import { exec } from 'teen_process';
import path from 'path';
/**
* Internal utility to link global package to local context
*
* @returns {string} - name of the package to link
* @throws {Error} If the command fails
*/
async function linkGlobalPackage (packageName) {
try {
log.debug(`Linking package '${packageName}'`);
const cmd = isWindows() ? 'npm.cmd' : 'npm';
await exec(cmd, ['link', packageName], {timeout: 20000});
} catch (err) {
const msg = `Unable to load package '${packageName}', linking failed: ${err.message}`;
log.debug(msg);
if (err.stderr) {
// log the stderr if there, but do not add to thrown error as it is
// _very_ verbose
log.debug(err.stderr);
}
throw new Error(msg);
}
}
/**
* Utility function to extend node functionality, allowing us to require
* modules that are installed globally. If the package cannot be required,
* this will attempt to link the package and then re-require it
*
* @param {string} packageName - the name of the package to be required
* @returns {object} - the package object
* @throws {Error} If the package is not found locally or globally
*/
async function requirePackage (packageName) {
// first, get it in the normal way (see https://nodejs.org/api/modules.html#modules_all_together)
try {
log.debug(`Loading local package '${packageName}'`);
return require(packageName);
} catch (err) {
log.debug(`Failed to load local package '${packageName}': ${err.message}`);
}
// second, get it from where it ought to be in the global node_modules
try {
const globalPackageName = path.resolve(process.env.npm_config_prefix, 'lib', 'node_modules', packageName);
log.debug(`Loading global package '${globalPackageName}'`);
return require(globalPackageName);
} catch (err) {
log.debug(`Failed to load global package '${packageName}': ${err.message}`);
}
// third, link the file and get locally
try {
await linkGlobalPackage(packageName);
log.debug(`Retrying load of linked package '${packageName}'`);
return require(packageName);
} catch (err) {
log.errorAndThrow(`Unable to load package '${packageName}': ${err.message}`);
}
}
export { requirePackage };