-
Notifications
You must be signed in to change notification settings - Fork 30.1k
/
run_main.js
142 lines (128 loc) Β· 4.84 KB
/
run_main.js
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
'use strict';
const {
StringPrototypeEndsWith,
} = primordials;
const { containsModuleSyntax } = internalBinding('contextify');
const { getOptionValue } = require('internal/options');
const path = require('path');
/**
* Get the absolute path to the main entry point.
* @param {string} main - Entry point path
*/
function resolveMainPath(main) {
const defaultType = getOptionValue('--experimental-default-type');
/** @type {string} */
let mainPath;
if (defaultType === 'module') {
if (getOptionValue('--preserve-symlinks-main')) { return; }
mainPath = path.resolve(main);
} else {
// Extension searching for the main entry point is supported only in legacy mode.
// Module._findPath is monkey-patchable here.
const { Module } = require('internal/modules/cjs/loader');
mainPath = Module._findPath(path.resolve(main), null, true);
}
if (!mainPath) { return; }
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
if (!preserveSymlinksMain) {
const { toRealPath } = require('internal/modules/helpers');
try {
mainPath = toRealPath(mainPath);
} catch (err) {
if (defaultType === 'module' && err?.code === 'ENOENT') {
const { decorateErrorWithCommonJSHints } = require('internal/modules/esm/resolve');
const { getCWDURL } = require('internal/util');
decorateErrorWithCommonJSHints(err, mainPath, getCWDURL());
}
throw err;
}
}
return mainPath;
}
/**
* Determine whether the main entry point should be loaded through the ESM Loader.
* @param {string} mainPath - Absolute path to the main entry point
*/
function shouldUseESMLoader(mainPath) {
if (getOptionValue('--experimental-default-type') === 'module') { return true; }
/**
* @type {string[]} userLoaders A list of custom loaders registered by the user
* (or an empty list when none have been registered).
*/
const userLoaders = getOptionValue('--experimental-loader');
/**
* @type {string[]} userImports A list of preloaded modules registered by the user
* (or an empty list when none have been registered).
*/
const userImports = getOptionValue('--import');
if (userLoaders.length > 0 || userImports.length > 0) { return true; }
// Determine the module format of the entry point.
if (mainPath && StringPrototypeEndsWith(mainPath, '.mjs')) { return true; }
if (!mainPath || StringPrototypeEndsWith(mainPath, '.cjs')) { return false; }
const { readPackageScope } = require('internal/modules/package_json_reader');
const pkg = readPackageScope(mainPath);
// No need to guard `pkg` as it can only be an object or `false`.
switch (pkg.data?.type) {
case 'module':
return true;
case 'commonjs':
return false;
default: { // No package.json or no `type` field.
if (getOptionValue('--experimental-detect-module')) {
// If the first argument of `containsModuleSyntax` is undefined, it will read `mainPath` from the file system.
return containsModuleSyntax(undefined, mainPath);
}
return false;
}
}
}
/**
* Run the main entry point through the ESM Loader.
* @param {string} mainPath - Absolute path for the main entry point
*/
function runMainESM(mainPath) {
const { loadESM } = require('internal/process/esm_loader');
const { pathToFileURL } = require('internal/url');
const main = pathToFileURL(mainPath).href;
handleMainPromise(loadESM((esmLoader) => {
return esmLoader.import(main, undefined, { __proto__: null });
}));
}
/**
* Handle process exit events around the main entry point promise.
* @param {Promise} promise - Main entry point promise
*/
async function handleMainPromise(promise) {
const {
handleProcessExit,
} = require('internal/modules/esm/handle_process_exit');
process.on('exit', handleProcessExit);
try {
return await promise;
} finally {
process.off('exit', handleProcessExit);
}
}
/**
* Parse the CLI main entry point string and run it.
* For backwards compatibility, we have to run a bunch of monkey-patchable code that belongs to the CJS loader (exposed
* by `require('module')`) even when the entry point is ESM.
* This monkey-patchable code is bypassed under `--experimental-default-type=module`.
* Because of backwards compatibility, this function is exposed publicly via `import { runMain } from 'node:module'`.
* @param {string} main - First positional CLI argument, such as `'entry.js'` from `node entry.js`
*/
function executeUserEntryPoint(main = process.argv[1]) {
const resolvedMain = resolveMainPath(main);
const useESMLoader = shouldUseESMLoader(resolvedMain);
if (useESMLoader) {
runMainESM(resolvedMain || main);
} else {
// Module._load is the monkey-patchable CJS module loader.
const { Module } = require('internal/modules/cjs/loader');
Module._load(main, null, true);
}
}
module.exports = {
executeUserEntryPoint,
handleMainPromise,
};