index.js 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. import path, { dirname, resolve, extname, normalize, sep } from 'path';
  2. import builtinList from 'builtin-modules';
  3. import deepMerge from 'deepmerge';
  4. import isModule from 'is-module';
  5. import fs, { realpathSync } from 'fs';
  6. import { promisify } from 'util';
  7. import { pathToFileURL, fileURLToPath } from 'url';
  8. import resolve$1 from 'resolve';
  9. import { createFilter } from '@rollup/pluginutils';
  10. const access = promisify(fs.access);
  11. const readFile = promisify(fs.readFile);
  12. const realpath = promisify(fs.realpath);
  13. const stat = promisify(fs.stat);
  14. async function exists(filePath) {
  15. try {
  16. await access(filePath);
  17. return true;
  18. } catch {
  19. return false;
  20. }
  21. }
  22. const onError = (error) => {
  23. if (error.code === 'ENOENT') {
  24. return false;
  25. }
  26. throw error;
  27. };
  28. const makeCache = (fn) => {
  29. const cache = new Map();
  30. const wrapped = async (param, done) => {
  31. if (cache.has(param) === false) {
  32. cache.set(
  33. param,
  34. fn(param).catch((err) => {
  35. cache.delete(param);
  36. throw err;
  37. })
  38. );
  39. }
  40. try {
  41. const result = cache.get(param);
  42. const value = await result;
  43. return done(null, value);
  44. } catch (error) {
  45. return done(error);
  46. }
  47. };
  48. wrapped.clear = () => cache.clear();
  49. return wrapped;
  50. };
  51. const isDirCached = makeCache(async (file) => {
  52. try {
  53. const stats = await stat(file);
  54. return stats.isDirectory();
  55. } catch (error) {
  56. return onError(error);
  57. }
  58. });
  59. const isFileCached = makeCache(async (file) => {
  60. try {
  61. const stats = await stat(file);
  62. return stats.isFile();
  63. } catch (error) {
  64. return onError(error);
  65. }
  66. });
  67. const readCachedFile = makeCache(readFile);
  68. // returns the imported package name for bare module imports
  69. function getPackageName(id) {
  70. if (id.startsWith('.') || id.startsWith('/')) {
  71. return null;
  72. }
  73. const split = id.split('/');
  74. // @my-scope/my-package/foo.js -> @my-scope/my-package
  75. // @my-scope/my-package -> @my-scope/my-package
  76. if (split[0][0] === '@') {
  77. return `${split[0]}/${split[1]}`;
  78. }
  79. // my-package/foo.js -> my-package
  80. // my-package -> my-package
  81. return split[0];
  82. }
  83. function getMainFields(options) {
  84. let mainFields;
  85. if (options.mainFields) {
  86. ({ mainFields } = options);
  87. } else {
  88. mainFields = ['module', 'main'];
  89. }
  90. if (options.browser && mainFields.indexOf('browser') === -1) {
  91. return ['browser'].concat(mainFields);
  92. }
  93. if (!mainFields.length) {
  94. throw new Error('Please ensure at least one `mainFields` value is specified');
  95. }
  96. return mainFields;
  97. }
  98. function getPackageInfo(options) {
  99. const {
  100. cache,
  101. extensions,
  102. pkg,
  103. mainFields,
  104. preserveSymlinks,
  105. useBrowserOverrides,
  106. rootDir,
  107. ignoreSideEffectsForRoot
  108. } = options;
  109. let { pkgPath } = options;
  110. if (cache.has(pkgPath)) {
  111. return cache.get(pkgPath);
  112. }
  113. // browserify/resolve doesn't realpath paths returned in its packageFilter callback
  114. if (!preserveSymlinks) {
  115. pkgPath = realpathSync(pkgPath);
  116. }
  117. const pkgRoot = dirname(pkgPath);
  118. const packageInfo = {
  119. // copy as we are about to munge the `main` field of `pkg`.
  120. packageJson: { ...pkg },
  121. // path to package.json file
  122. packageJsonPath: pkgPath,
  123. // directory containing the package.json
  124. root: pkgRoot,
  125. // which main field was used during resolution of this module (main, module, or browser)
  126. resolvedMainField: 'main',
  127. // whether the browser map was used to resolve the entry point to this module
  128. browserMappedMain: false,
  129. // the entry point of the module with respect to the selected main field and any
  130. // relevant browser mappings.
  131. resolvedEntryPoint: ''
  132. };
  133. let overriddenMain = false;
  134. for (let i = 0; i < mainFields.length; i++) {
  135. const field = mainFields[i];
  136. if (typeof pkg[field] === 'string') {
  137. pkg.main = pkg[field];
  138. packageInfo.resolvedMainField = field;
  139. overriddenMain = true;
  140. break;
  141. }
  142. }
  143. const internalPackageInfo = {
  144. cachedPkg: pkg,
  145. hasModuleSideEffects: () => null,
  146. hasPackageEntry: overriddenMain !== false || mainFields.indexOf('main') !== -1,
  147. packageBrowserField:
  148. useBrowserOverrides &&
  149. typeof pkg.browser === 'object' &&
  150. Object.keys(pkg.browser).reduce((browser, key) => {
  151. let resolved = pkg.browser[key];
  152. if (resolved && resolved[0] === '.') {
  153. resolved = resolve(pkgRoot, resolved);
  154. }
  155. /* eslint-disable no-param-reassign */
  156. browser[key] = resolved;
  157. if (key[0] === '.') {
  158. const absoluteKey = resolve(pkgRoot, key);
  159. browser[absoluteKey] = resolved;
  160. if (!extname(key)) {
  161. extensions.reduce((subBrowser, ext) => {
  162. subBrowser[absoluteKey + ext] = subBrowser[key];
  163. return subBrowser;
  164. }, browser);
  165. }
  166. }
  167. return browser;
  168. }, {}),
  169. packageInfo
  170. };
  171. const browserMap = internalPackageInfo.packageBrowserField;
  172. if (
  173. useBrowserOverrides &&
  174. typeof pkg.browser === 'object' &&
  175. // eslint-disable-next-line no-prototype-builtins
  176. browserMap.hasOwnProperty(pkg.main)
  177. ) {
  178. packageInfo.resolvedEntryPoint = browserMap[pkg.main];
  179. packageInfo.browserMappedMain = true;
  180. } else {
  181. // index.node is technically a valid default entrypoint as well...
  182. packageInfo.resolvedEntryPoint = resolve(pkgRoot, pkg.main || 'index.js');
  183. packageInfo.browserMappedMain = false;
  184. }
  185. if (!ignoreSideEffectsForRoot || rootDir !== pkgRoot) {
  186. const packageSideEffects = pkg.sideEffects;
  187. if (typeof packageSideEffects === 'boolean') {
  188. internalPackageInfo.hasModuleSideEffects = () => packageSideEffects;
  189. } else if (Array.isArray(packageSideEffects)) {
  190. internalPackageInfo.hasModuleSideEffects = createFilter(packageSideEffects, null, {
  191. resolve: pkgRoot
  192. });
  193. }
  194. }
  195. cache.set(pkgPath, internalPackageInfo);
  196. return internalPackageInfo;
  197. }
  198. function normalizeInput(input) {
  199. if (Array.isArray(input)) {
  200. return input;
  201. } else if (typeof input === 'object') {
  202. return Object.values(input);
  203. }
  204. // otherwise it's a string
  205. return [input];
  206. }
  207. /* eslint-disable no-await-in-loop */
  208. const fileExists = promisify(fs.exists);
  209. function isModuleDir(current, moduleDirs) {
  210. return moduleDirs.some((dir) => current.endsWith(dir));
  211. }
  212. async function findPackageJson(base, moduleDirs) {
  213. const { root } = path.parse(base);
  214. let current = base;
  215. while (current !== root && !isModuleDir(current, moduleDirs)) {
  216. const pkgJsonPath = path.join(current, 'package.json');
  217. if (await fileExists(pkgJsonPath)) {
  218. const pkgJsonString = fs.readFileSync(pkgJsonPath, 'utf-8');
  219. return { pkgJson: JSON.parse(pkgJsonString), pkgPath: current, pkgJsonPath };
  220. }
  221. current = path.resolve(current, '..');
  222. }
  223. return null;
  224. }
  225. function isUrl(str) {
  226. try {
  227. return !!new URL(str);
  228. } catch (_) {
  229. return false;
  230. }
  231. }
  232. function isConditions(exports) {
  233. return typeof exports === 'object' && Object.keys(exports).every((k) => !k.startsWith('.'));
  234. }
  235. function isMappings(exports) {
  236. return typeof exports === 'object' && !isConditions(exports);
  237. }
  238. function isMixedExports(exports) {
  239. const keys = Object.keys(exports);
  240. return keys.some((k) => k.startsWith('.')) && keys.some((k) => !k.startsWith('.'));
  241. }
  242. function createBaseErrorMsg(importSpecifier, importer) {
  243. return `Could not resolve import "${importSpecifier}" in ${importer}`;
  244. }
  245. function createErrorMsg(context, reason, internal) {
  246. const { importSpecifier, importer, pkgJsonPath } = context;
  247. const base = createBaseErrorMsg(importSpecifier, importer);
  248. const field = internal ? 'imports' : 'exports';
  249. return `${base} using ${field} defined in ${pkgJsonPath}.${reason ? ` ${reason}` : ''}`;
  250. }
  251. class ResolveError extends Error {}
  252. class InvalidConfigurationError extends ResolveError {
  253. constructor(context, reason) {
  254. super(createErrorMsg(context, `Invalid "exports" field. ${reason}`));
  255. }
  256. }
  257. class InvalidModuleSpecifierError extends ResolveError {
  258. constructor(context, internal) {
  259. super(createErrorMsg(context, internal));
  260. }
  261. }
  262. class InvalidPackageTargetError extends ResolveError {
  263. constructor(context, reason) {
  264. super(createErrorMsg(context, reason));
  265. }
  266. }
  267. /* eslint-disable no-await-in-loop, no-undefined */
  268. function includesInvalidSegments(pathSegments, moduleDirs) {
  269. return pathSegments
  270. .split('/')
  271. .slice(1)
  272. .some((t) => ['.', '..', ...moduleDirs].includes(t));
  273. }
  274. async function resolvePackageTarget(context, { target, subpath, pattern, internal }) {
  275. if (typeof target === 'string') {
  276. if (!pattern && subpath.length > 0 && !target.endsWith('/')) {
  277. throw new InvalidModuleSpecifierError(context);
  278. }
  279. if (!target.startsWith('./')) {
  280. if (internal && !['/', '../'].some((p) => target.startsWith(p)) && !isUrl(target)) {
  281. // this is a bare package import, remap it and resolve it using regular node resolve
  282. if (pattern) {
  283. const result = await context.resolveId(
  284. target.replace(/\*/g, subpath),
  285. context.pkgURL.href
  286. );
  287. return result ? pathToFileURL(result.location) : null;
  288. }
  289. const result = await context.resolveId(`${target}${subpath}`, context.pkgURL.href);
  290. return result ? pathToFileURL(result.location) : null;
  291. }
  292. throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
  293. }
  294. if (includesInvalidSegments(target, context.moduleDirs)) {
  295. throw new InvalidPackageTargetError(context, `Invalid mapping: "${target}".`);
  296. }
  297. const resolvedTarget = new URL(target, context.pkgURL);
  298. if (!resolvedTarget.href.startsWith(context.pkgURL.href)) {
  299. throw new InvalidPackageTargetError(
  300. context,
  301. `Resolved to ${resolvedTarget.href} which is outside package ${context.pkgURL.href}`
  302. );
  303. }
  304. if (includesInvalidSegments(subpath, context.moduleDirs)) {
  305. throw new InvalidModuleSpecifierError(context);
  306. }
  307. if (pattern) {
  308. return resolvedTarget.href.replace(/\*/g, subpath);
  309. }
  310. return new URL(subpath, resolvedTarget).href;
  311. }
  312. if (Array.isArray(target)) {
  313. let lastError;
  314. for (const item of target) {
  315. try {
  316. const resolved = await resolvePackageTarget(context, {
  317. target: item,
  318. subpath,
  319. pattern,
  320. internal
  321. });
  322. // return if defined or null, but not undefined
  323. if (resolved !== undefined) {
  324. return resolved;
  325. }
  326. } catch (error) {
  327. if (!(error instanceof InvalidPackageTargetError)) {
  328. throw error;
  329. } else {
  330. lastError = error;
  331. }
  332. }
  333. }
  334. if (lastError) {
  335. throw lastError;
  336. }
  337. return null;
  338. }
  339. if (target && typeof target === 'object') {
  340. for (const [key, value] of Object.entries(target)) {
  341. if (key === 'default' || context.conditions.includes(key)) {
  342. const resolved = await resolvePackageTarget(context, {
  343. target: value,
  344. subpath,
  345. pattern,
  346. internal
  347. });
  348. // return if defined or null, but not undefined
  349. if (resolved !== undefined) {
  350. return resolved;
  351. }
  352. }
  353. }
  354. return undefined;
  355. }
  356. if (target === null) {
  357. return null;
  358. }
  359. throw new InvalidPackageTargetError(context, `Invalid exports field.`);
  360. }
  361. /* eslint-disable no-await-in-loop */
  362. async function resolvePackageImportsExports(context, { matchKey, matchObj, internal }) {
  363. if (!matchKey.endsWith('*') && matchKey in matchObj) {
  364. const target = matchObj[matchKey];
  365. const resolved = await resolvePackageTarget(context, { target, subpath: '', internal });
  366. return resolved;
  367. }
  368. const expansionKeys = Object.keys(matchObj)
  369. .filter((k) => k.endsWith('/') || k.endsWith('*'))
  370. .sort((a, b) => b.length - a.length);
  371. for (const expansionKey of expansionKeys) {
  372. const prefix = expansionKey.substring(0, expansionKey.length - 1);
  373. if (expansionKey.endsWith('*') && matchKey.startsWith(prefix)) {
  374. const target = matchObj[expansionKey];
  375. const subpath = matchKey.substring(expansionKey.length - 1);
  376. const resolved = await resolvePackageTarget(context, {
  377. target,
  378. subpath,
  379. pattern: true,
  380. internal
  381. });
  382. return resolved;
  383. }
  384. if (matchKey.startsWith(expansionKey)) {
  385. const target = matchObj[expansionKey];
  386. const subpath = matchKey.substring(expansionKey.length);
  387. const resolved = await resolvePackageTarget(context, { target, subpath, internal });
  388. return resolved;
  389. }
  390. }
  391. throw new InvalidModuleSpecifierError(context, internal);
  392. }
  393. async function resolvePackageExports(context, subpath, exports) {
  394. if (isMixedExports(exports)) {
  395. throw new InvalidConfigurationError(
  396. context,
  397. 'All keys must either start with ./, or without one.'
  398. );
  399. }
  400. if (subpath === '.') {
  401. let mainExport;
  402. // If exports is a String or Array, or an Object containing no keys starting with ".", then
  403. if (typeof exports === 'string' || Array.isArray(exports) || isConditions(exports)) {
  404. mainExport = exports;
  405. } else if (isMappings(exports)) {
  406. mainExport = exports['.'];
  407. }
  408. if (mainExport) {
  409. const resolved = await resolvePackageTarget(context, { target: mainExport, subpath: '' });
  410. if (resolved) {
  411. return resolved;
  412. }
  413. }
  414. } else if (isMappings(exports)) {
  415. const resolvedMatch = await resolvePackageImportsExports(context, {
  416. matchKey: subpath,
  417. matchObj: exports
  418. });
  419. if (resolvedMatch) {
  420. return resolvedMatch;
  421. }
  422. }
  423. throw new InvalidModuleSpecifierError(context);
  424. }
  425. async function resolvePackageImports({
  426. importSpecifier,
  427. importer,
  428. moduleDirs,
  429. conditions,
  430. resolveId
  431. }) {
  432. const result = await findPackageJson(importer, moduleDirs);
  433. if (!result) {
  434. throw new Error(createBaseErrorMsg('. Could not find a parent package.json.'));
  435. }
  436. const { pkgPath, pkgJsonPath, pkgJson } = result;
  437. const pkgURL = pathToFileURL(`${pkgPath}/`);
  438. const context = {
  439. importer,
  440. importSpecifier,
  441. moduleDirs,
  442. pkgURL,
  443. pkgJsonPath,
  444. conditions,
  445. resolveId
  446. };
  447. const { imports } = pkgJson;
  448. if (!imports) {
  449. throw new InvalidModuleSpecifierError(context, true);
  450. }
  451. if (importSpecifier === '#' || importSpecifier.startsWith('#/')) {
  452. throw new InvalidModuleSpecifierError(context, 'Invalid import specifier.');
  453. }
  454. return resolvePackageImportsExports(context, {
  455. matchKey: importSpecifier,
  456. matchObj: imports,
  457. internal: true
  458. });
  459. }
  460. const resolveImportPath = promisify(resolve$1);
  461. const readFile$1 = promisify(fs.readFile);
  462. async function getPackageJson(importer, pkgName, resolveOptions, moduleDirectories) {
  463. if (importer) {
  464. const selfPackageJsonResult = await findPackageJson(importer, moduleDirectories);
  465. if (selfPackageJsonResult && selfPackageJsonResult.pkgJson.name === pkgName) {
  466. // the referenced package name is the current package
  467. return selfPackageJsonResult;
  468. }
  469. }
  470. try {
  471. const pkgJsonPath = await resolveImportPath(`${pkgName}/package.json`, resolveOptions);
  472. const pkgJson = JSON.parse(await readFile$1(pkgJsonPath, 'utf-8'));
  473. return { pkgJsonPath, pkgJson };
  474. } catch (_) {
  475. return null;
  476. }
  477. }
  478. async function resolveId({
  479. importer,
  480. importSpecifier,
  481. exportConditions,
  482. warn,
  483. packageInfoCache,
  484. extensions,
  485. mainFields,
  486. preserveSymlinks,
  487. useBrowserOverrides,
  488. baseDir,
  489. moduleDirectories,
  490. rootDir,
  491. ignoreSideEffectsForRoot
  492. }) {
  493. let hasModuleSideEffects = () => null;
  494. let hasPackageEntry = true;
  495. let packageBrowserField = false;
  496. let packageInfo;
  497. const filter = (pkg, pkgPath) => {
  498. const info = getPackageInfo({
  499. cache: packageInfoCache,
  500. extensions,
  501. pkg,
  502. pkgPath,
  503. mainFields,
  504. preserveSymlinks,
  505. useBrowserOverrides,
  506. rootDir,
  507. ignoreSideEffectsForRoot
  508. });
  509. ({ packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = info);
  510. return info.cachedPkg;
  511. };
  512. const resolveOptions = {
  513. basedir: baseDir,
  514. readFile: readCachedFile,
  515. isFile: isFileCached,
  516. isDirectory: isDirCached,
  517. extensions,
  518. includeCoreModules: false,
  519. moduleDirectory: moduleDirectories,
  520. preserveSymlinks,
  521. packageFilter: filter
  522. };
  523. let location;
  524. const pkgName = getPackageName(importSpecifier);
  525. if (importSpecifier.startsWith('#')) {
  526. // this is a package internal import, resolve using package imports field
  527. const resolveResult = await resolvePackageImports({
  528. importSpecifier,
  529. importer,
  530. moduleDirs: moduleDirectories,
  531. conditions: exportConditions,
  532. resolveId(id, parent) {
  533. return resolveId({
  534. importSpecifier: id,
  535. importer: parent,
  536. exportConditions,
  537. warn,
  538. packageInfoCache,
  539. extensions,
  540. mainFields,
  541. preserveSymlinks,
  542. useBrowserOverrides,
  543. baseDir,
  544. moduleDirectories
  545. });
  546. }
  547. });
  548. location = fileURLToPath(resolveResult);
  549. } else if (pkgName) {
  550. // it's a bare import, find the package.json and resolve using package exports if available
  551. const result = await getPackageJson(importer, pkgName, resolveOptions, moduleDirectories);
  552. if (result && result.pkgJson.exports) {
  553. const { pkgJson, pkgJsonPath } = result;
  554. try {
  555. const subpath =
  556. pkgName === importSpecifier ? '.' : `.${importSpecifier.substring(pkgName.length)}`;
  557. const pkgDr = pkgJsonPath.replace('package.json', '');
  558. const pkgURL = pathToFileURL(pkgDr);
  559. const context = {
  560. importer,
  561. importSpecifier,
  562. moduleDirs: moduleDirectories,
  563. pkgURL,
  564. pkgJsonPath,
  565. conditions: exportConditions
  566. };
  567. const resolvedPackageExport = await resolvePackageExports(
  568. context,
  569. subpath,
  570. pkgJson.exports
  571. );
  572. location = fileURLToPath(resolvedPackageExport);
  573. } catch (error) {
  574. if (error instanceof ResolveError) {
  575. return error;
  576. }
  577. throw error;
  578. }
  579. }
  580. }
  581. if (!location) {
  582. // package has no imports or exports, use classic node resolve
  583. try {
  584. location = await resolveImportPath(importSpecifier, resolveOptions);
  585. } catch (error) {
  586. if (error.code !== 'MODULE_NOT_FOUND') {
  587. throw error;
  588. }
  589. return null;
  590. }
  591. }
  592. if (!preserveSymlinks) {
  593. if (await exists(location)) {
  594. location = await realpath(location);
  595. }
  596. }
  597. return {
  598. location,
  599. hasModuleSideEffects,
  600. hasPackageEntry,
  601. packageBrowserField,
  602. packageInfo
  603. };
  604. }
  605. // Resolve module specifiers in order. Promise resolves to the first module that resolves
  606. // successfully, or the error that resulted from the last attempted module resolution.
  607. async function resolveImportSpecifiers({
  608. importer,
  609. importSpecifierList,
  610. exportConditions,
  611. warn,
  612. packageInfoCache,
  613. extensions,
  614. mainFields,
  615. preserveSymlinks,
  616. useBrowserOverrides,
  617. baseDir,
  618. moduleDirectories,
  619. rootDir,
  620. ignoreSideEffectsForRoot
  621. }) {
  622. let lastResolveError;
  623. for (let i = 0; i < importSpecifierList.length; i++) {
  624. // eslint-disable-next-line no-await-in-loop
  625. const result = await resolveId({
  626. importer,
  627. importSpecifier: importSpecifierList[i],
  628. exportConditions,
  629. warn,
  630. packageInfoCache,
  631. extensions,
  632. mainFields,
  633. preserveSymlinks,
  634. useBrowserOverrides,
  635. baseDir,
  636. moduleDirectories,
  637. rootDir,
  638. ignoreSideEffectsForRoot
  639. });
  640. if (result instanceof ResolveError) {
  641. lastResolveError = result;
  642. } else if (result) {
  643. return result;
  644. }
  645. }
  646. if (lastResolveError) {
  647. // only log the last failed resolve error
  648. warn(lastResolveError);
  649. }
  650. return null;
  651. }
  652. function handleDeprecatedOptions(opts) {
  653. const warnings = [];
  654. if (opts.customResolveOptions) {
  655. const { customResolveOptions } = opts;
  656. if (customResolveOptions.moduleDirectory) {
  657. // eslint-disable-next-line no-param-reassign
  658. opts.moduleDirectories = Array.isArray(customResolveOptions.moduleDirectory)
  659. ? customResolveOptions.moduleDirectory
  660. : [customResolveOptions.moduleDirectory];
  661. warnings.push(
  662. 'node-resolve: The `customResolveOptions.moduleDirectory` option has been deprecated. Use `moduleDirectories`, which must be an array.'
  663. );
  664. }
  665. if (customResolveOptions.preserveSymlinks) {
  666. throw new Error(
  667. 'node-resolve: `customResolveOptions.preserveSymlinks` is no longer an option. We now always use the rollup `preserveSymlinks` option.'
  668. );
  669. }
  670. [
  671. 'basedir',
  672. 'package',
  673. 'extensions',
  674. 'includeCoreModules',
  675. 'readFile',
  676. 'isFile',
  677. 'isDirectory',
  678. 'realpath',
  679. 'packageFilter',
  680. 'pathFilter',
  681. 'paths',
  682. 'packageIterator'
  683. ].forEach((resolveOption) => {
  684. if (customResolveOptions[resolveOption]) {
  685. throw new Error(
  686. `node-resolve: \`customResolveOptions.${resolveOption}\` is no longer an option. If you need this, please open an issue.`
  687. );
  688. }
  689. });
  690. }
  691. return { warnings };
  692. }
  693. /* eslint-disable no-param-reassign, no-shadow, no-undefined */
  694. const builtins = new Set(builtinList);
  695. const ES6_BROWSER_EMPTY = '\0node-resolve:empty.js';
  696. const deepFreeze = (object) => {
  697. Object.freeze(object);
  698. for (const value of Object.values(object)) {
  699. if (typeof value === 'object' && !Object.isFrozen(value)) {
  700. deepFreeze(value);
  701. }
  702. }
  703. return object;
  704. };
  705. const baseConditions = ['default', 'module'];
  706. const baseConditionsEsm = [...baseConditions, 'import'];
  707. const baseConditionsCjs = [...baseConditions, 'require'];
  708. const defaults = {
  709. dedupe: [],
  710. // It's important that .mjs is listed before .js so that Rollup will interpret npm modules
  711. // which deploy both ESM .mjs and CommonJS .js files as ESM.
  712. extensions: ['.mjs', '.js', '.json', '.node'],
  713. resolveOnly: [],
  714. moduleDirectories: ['node_modules'],
  715. ignoreSideEffectsForRoot: false
  716. };
  717. const DEFAULTS = deepFreeze(deepMerge({}, defaults));
  718. function nodeResolve(opts = {}) {
  719. const { warnings } = handleDeprecatedOptions(opts);
  720. const options = { ...defaults, ...opts };
  721. const { extensions, jail, moduleDirectories, ignoreSideEffectsForRoot } = options;
  722. const conditionsEsm = [...baseConditionsEsm, ...(options.exportConditions || [])];
  723. const conditionsCjs = [...baseConditionsCjs, ...(options.exportConditions || [])];
  724. const packageInfoCache = new Map();
  725. const idToPackageInfo = new Map();
  726. const mainFields = getMainFields(options);
  727. const useBrowserOverrides = mainFields.indexOf('browser') !== -1;
  728. const isPreferBuiltinsSet = options.preferBuiltins === true || options.preferBuiltins === false;
  729. const preferBuiltins = isPreferBuiltinsSet ? options.preferBuiltins : true;
  730. const rootDir = resolve(options.rootDir || process.cwd());
  731. let { dedupe } = options;
  732. let rollupOptions;
  733. if (typeof dedupe !== 'function') {
  734. dedupe = (importee) =>
  735. options.dedupe.includes(importee) || options.dedupe.includes(getPackageName(importee));
  736. }
  737. const resolveOnly = options.resolveOnly.map((pattern) => {
  738. if (pattern instanceof RegExp) {
  739. return pattern;
  740. }
  741. const normalized = pattern.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
  742. return new RegExp(`^${normalized}$`);
  743. });
  744. const browserMapCache = new Map();
  745. let preserveSymlinks;
  746. return {
  747. name: 'node-resolve',
  748. buildStart(options) {
  749. rollupOptions = options;
  750. for (const warning of warnings) {
  751. this.warn(warning);
  752. }
  753. ({ preserveSymlinks } = options);
  754. },
  755. generateBundle() {
  756. readCachedFile.clear();
  757. isFileCached.clear();
  758. isDirCached.clear();
  759. },
  760. async resolveId(importee, importer, opts) {
  761. if (importee === ES6_BROWSER_EMPTY) {
  762. return importee;
  763. }
  764. // ignore IDs with null character, these belong to other plugins
  765. if (/\0/.test(importee)) return null;
  766. if (/\0/.test(importer)) {
  767. importer = undefined;
  768. }
  769. // strip query params from import
  770. const [importPath, params] = importee.split('?');
  771. const importSuffix = `${params ? `?${params}` : ''}`;
  772. importee = importPath;
  773. const baseDir = !importer || dedupe(importee) ? rootDir : dirname(importer);
  774. // https://github.com/defunctzombie/package-browser-field-spec
  775. const browser = browserMapCache.get(importer);
  776. if (useBrowserOverrides && browser) {
  777. const resolvedImportee = resolve(baseDir, importee);
  778. if (browser[importee] === false || browser[resolvedImportee] === false) {
  779. return ES6_BROWSER_EMPTY;
  780. }
  781. const browserImportee =
  782. browser[importee] ||
  783. browser[resolvedImportee] ||
  784. browser[`${resolvedImportee}.js`] ||
  785. browser[`${resolvedImportee}.json`];
  786. if (browserImportee) {
  787. importee = browserImportee;
  788. }
  789. }
  790. const parts = importee.split(/[/\\]/);
  791. let id = parts.shift();
  792. let isRelativeImport = false;
  793. if (id[0] === '@' && parts.length > 0) {
  794. // scoped packages
  795. id += `/${parts.shift()}`;
  796. } else if (id[0] === '.') {
  797. // an import relative to the parent dir of the importer
  798. id = resolve(baseDir, importee);
  799. isRelativeImport = true;
  800. }
  801. if (
  802. !isRelativeImport &&
  803. resolveOnly.length &&
  804. !resolveOnly.some((pattern) => pattern.test(id))
  805. ) {
  806. if (normalizeInput(rollupOptions.input).includes(importee)) {
  807. return null;
  808. }
  809. return false;
  810. }
  811. const importSpecifierList = [];
  812. if (importer === undefined && !importee[0].match(/^\.?\.?\//)) {
  813. // For module graph roots (i.e. when importer is undefined), we
  814. // need to handle 'path fragments` like `foo/bar` that are commonly
  815. // found in rollup config files. If importee doesn't look like a
  816. // relative or absolute path, we make it relative and attempt to
  817. // resolve it. If we don't find anything, we try resolving it as we
  818. // got it.
  819. importSpecifierList.push(`./${importee}`);
  820. }
  821. const importeeIsBuiltin = builtins.has(importee);
  822. if (importeeIsBuiltin) {
  823. // The `resolve` library will not resolve packages with the same
  824. // name as a node built-in module. If we're resolving something
  825. // that's a builtin, and we don't prefer to find built-ins, we
  826. // first try to look up a local module with that name. If we don't
  827. // find anything, we resolve the builtin which just returns back
  828. // the built-in's name.
  829. importSpecifierList.push(`${importee}/`);
  830. }
  831. // TypeScript files may import '.js' to refer to either '.ts' or '.tsx'
  832. if (importer && importee.endsWith('.js')) {
  833. for (const ext of ['.ts', '.tsx']) {
  834. if (importer.endsWith(ext) && extensions.includes(ext)) {
  835. importSpecifierList.push(importee.replace(/.js$/, ext));
  836. }
  837. }
  838. }
  839. importSpecifierList.push(importee);
  840. const warn = (...args) => this.warn(...args);
  841. const isRequire =
  842. opts && opts.custom && opts.custom['node-resolve'] && opts.custom['node-resolve'].isRequire;
  843. const exportConditions = isRequire ? conditionsCjs : conditionsEsm;
  844. const resolvedWithoutBuiltins = await resolveImportSpecifiers({
  845. importer,
  846. importSpecifierList,
  847. exportConditions,
  848. warn,
  849. packageInfoCache,
  850. extensions,
  851. mainFields,
  852. preserveSymlinks,
  853. useBrowserOverrides,
  854. baseDir,
  855. moduleDirectories,
  856. rootDir,
  857. ignoreSideEffectsForRoot
  858. });
  859. const resolved =
  860. importeeIsBuiltin && preferBuiltins
  861. ? {
  862. packageInfo: undefined,
  863. hasModuleSideEffects: () => null,
  864. hasPackageEntry: true,
  865. packageBrowserField: false
  866. }
  867. : resolvedWithoutBuiltins;
  868. if (!resolved) {
  869. return null;
  870. }
  871. const { packageInfo, hasModuleSideEffects, hasPackageEntry, packageBrowserField } = resolved;
  872. let { location } = resolved;
  873. if (packageBrowserField) {
  874. if (Object.prototype.hasOwnProperty.call(packageBrowserField, location)) {
  875. if (!packageBrowserField[location]) {
  876. browserMapCache.set(location, packageBrowserField);
  877. return ES6_BROWSER_EMPTY;
  878. }
  879. location = packageBrowserField[location];
  880. }
  881. browserMapCache.set(location, packageBrowserField);
  882. }
  883. if (hasPackageEntry && !preserveSymlinks) {
  884. const fileExists = await exists(location);
  885. if (fileExists) {
  886. location = await realpath(location);
  887. }
  888. }
  889. idToPackageInfo.set(location, packageInfo);
  890. if (hasPackageEntry) {
  891. if (importeeIsBuiltin && preferBuiltins) {
  892. if (!isPreferBuiltinsSet && resolvedWithoutBuiltins && resolved !== importee) {
  893. this.warn(
  894. `preferring built-in module '${importee}' over local alternative at '${resolvedWithoutBuiltins.location}', pass 'preferBuiltins: false' to disable this behavior or 'preferBuiltins: true' to disable this warning`
  895. );
  896. }
  897. return false;
  898. } else if (jail && location.indexOf(normalize(jail.trim(sep))) !== 0) {
  899. return null;
  900. }
  901. }
  902. if (options.modulesOnly && (await exists(location))) {
  903. const code = await readFile(location, 'utf-8');
  904. if (isModule(code)) {
  905. return {
  906. id: `${location}${importSuffix}`,
  907. moduleSideEffects: hasModuleSideEffects(location)
  908. };
  909. }
  910. return null;
  911. }
  912. const result = {
  913. id: `${location}${importSuffix}`,
  914. moduleSideEffects: hasModuleSideEffects(location)
  915. };
  916. return result;
  917. },
  918. load(importee) {
  919. if (importee === ES6_BROWSER_EMPTY) {
  920. return 'export default {};';
  921. }
  922. return null;
  923. },
  924. getPackageInfoForId(id) {
  925. return idToPackageInfo.get(id);
  926. }
  927. };
  928. }
  929. export default nodeResolve;
  930. export { DEFAULTS, nodeResolve };