• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const {
4  ObjectCreate,
5  StringPrototypeEndsWith,
6} = primordials;
7const CJSLoader = require('internal/modules/cjs/loader');
8const { Module, toRealPath, readPackageScope } = CJSLoader;
9const { getOptionValue } = require('internal/options');
10const path = require('path');
11const {
12  handleProcessExit,
13} = require('internal/modules/esm/handle_process_exit');
14
15function resolveMainPath(main) {
16  // Note extension resolution for the main entry point can be deprecated in a
17  // future major.
18  // Module._findPath is monkey-patchable here.
19  let mainPath = Module._findPath(path.resolve(main), null, true);
20  if (!mainPath)
21    return;
22
23  const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
24  if (!preserveSymlinksMain)
25    mainPath = toRealPath(mainPath);
26
27  return mainPath;
28}
29
30function shouldUseESMLoader(mainPath) {
31  /**
32   * @type {string[]} userLoaders A list of custom loaders registered by the user
33   * (or an empty list when none have been registered).
34   */
35  const userLoaders = getOptionValue('--experimental-loader');
36  /**
37   * @type {string[]} userImports A list of preloaded modules registered by the user
38   * (or an empty list when none have been registered).
39   */
40  const userImports = getOptionValue('--import');
41  if (userLoaders.length > 0 || userImports.length > 0)
42    return true;
43  const esModuleSpecifierResolution =
44    getOptionValue('--experimental-specifier-resolution');
45  if (esModuleSpecifierResolution === 'node')
46    return true;
47  // Determine the module format of the main
48  if (mainPath && StringPrototypeEndsWith(mainPath, '.mjs'))
49    return true;
50  if (!mainPath || StringPrototypeEndsWith(mainPath, '.cjs'))
51    return false;
52  const pkg = readPackageScope(mainPath);
53  return pkg && pkg.data.type === 'module';
54}
55
56function runMainESM(mainPath) {
57  const { loadESM } = require('internal/process/esm_loader');
58  const { pathToFileURL } = require('internal/url');
59
60  handleMainPromise(loadESM((esmLoader) => {
61    const main = path.isAbsolute(mainPath) ?
62      pathToFileURL(mainPath).href : mainPath;
63    return esmLoader.import(main, undefined, ObjectCreate(null));
64  }));
65}
66
67async function handleMainPromise(promise) {
68  process.on('exit', handleProcessExit);
69  try {
70    return await promise;
71  } finally {
72    process.off('exit', handleProcessExit);
73  }
74}
75
76// For backwards compatibility, we have to run a bunch of
77// monkey-patchable code that belongs to the CJS loader (exposed by
78// `require('module')`) even when the entry point is ESM.
79function executeUserEntryPoint(main = process.argv[1]) {
80  const resolvedMain = resolveMainPath(main);
81  const useESMLoader = shouldUseESMLoader(resolvedMain);
82  if (useESMLoader) {
83    runMainESM(resolvedMain || main);
84  } else {
85    // Module._load is the monkey-patchable CJS module loader.
86    Module._load(main, null, true);
87  }
88}
89
90module.exports = {
91  executeUserEntryPoint,
92  handleMainPromise,
93};
94