native.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. const { existsSync } = require('node:fs');
  2. const path = require('node:path');
  3. const { platform, arch, report } = require('node:process');
  4. const { spawnSync } = require('node:child_process');
  5. const getReportHeader = () => {
  6. try {
  7. if (platform !== 'win32') {
  8. return report.getReport().header;
  9. }
  10. // This is needed because report.getReport() crashes the process on Windows sometimes.
  11. const script =
  12. "console.log(JSON.stringify(require('node:process').report.getReport().header));";
  13. const child = spawnSync(process.execPath, ['-p', script], {
  14. encoding: 'utf8',
  15. timeout: 3000,
  16. windowsHide: true
  17. });
  18. if (child.status !== 0) {
  19. return null;
  20. }
  21. // The output from node -p might include a trailing 'undefined' and newline
  22. const stdout = child.stdout?.replace(/undefined\r?\n?$/, '').trim();
  23. if (!stdout) {
  24. return null;
  25. }
  26. return JSON.parse(stdout);
  27. } catch {
  28. return null;
  29. }
  30. };
  31. let reportHeader;
  32. const isMingw32 = () => {
  33. reportHeader ??= getReportHeader();
  34. return reportHeader?.osName?.startsWith('MINGW32_NT') ?? false;
  35. };
  36. const isMusl = () => {
  37. reportHeader ??= getReportHeader();
  38. return reportHeader ? !reportHeader.glibcVersionRuntime : false;
  39. };
  40. const bindingsByPlatformAndArch = {
  41. android: {
  42. arm: { base: 'android-arm-eabi' },
  43. arm64: { base: 'android-arm64' }
  44. },
  45. darwin: {
  46. arm64: { base: 'darwin-arm64' },
  47. x64: { base: 'darwin-x64' }
  48. },
  49. freebsd: {
  50. arm64: { base: 'freebsd-arm64' },
  51. x64: { base: 'freebsd-x64' }
  52. },
  53. linux: {
  54. arm: { base: 'linux-arm-gnueabihf', musl: 'linux-arm-musleabihf' },
  55. arm64: { base: 'linux-arm64-gnu', musl: 'linux-arm64-musl' },
  56. loong64: { base: 'linux-loong64-gnu', musl: 'linux-loong64-musl' },
  57. ppc64: { base: 'linux-ppc64-gnu', musl: 'linux-ppc64-musl' },
  58. riscv64: { base: 'linux-riscv64-gnu', musl: 'linux-riscv64-musl' },
  59. s390x: { base: 'linux-s390x-gnu', musl: null },
  60. x64: { base: 'linux-x64-gnu', musl: 'linux-x64-musl' }
  61. },
  62. openbsd: {
  63. x64: { base: 'openbsd-x64' }
  64. },
  65. openharmony: {
  66. arm64: { base: 'openharmony-arm64' }
  67. },
  68. win32: {
  69. arm64: { base: 'win32-arm64-msvc' },
  70. ia32: { base: 'win32-ia32-msvc' },
  71. x64: {
  72. base: isMingw32() ? 'win32-x64-gnu' : 'win32-x64-msvc'
  73. }
  74. }
  75. };
  76. const msvcLinkFilenameByArch = {
  77. arm64: 'vc_redist.arm64.exe',
  78. ia32: 'vc_redist.x86.exe',
  79. x64: 'vc_redist.x64.exe'
  80. };
  81. const packageBase = getPackageBase();
  82. const localName = `./rollup.${packageBase}.node`;
  83. const requireWithFriendlyError = id => {
  84. try {
  85. return require(id);
  86. } catch (error) {
  87. if (
  88. platform === 'win32' &&
  89. error instanceof Error &&
  90. error.code === 'ERR_DLOPEN_FAILED' &&
  91. error.message.includes('The specified module could not be found')
  92. ) {
  93. const msvcDownloadLink = `https://aka.ms/vs/17/release/${msvcLinkFilenameByArch[arch]}`;
  94. throw new Error(
  95. `Failed to load module ${id}. ` +
  96. 'Required DLL was not found. ' +
  97. 'This error usually happens when Microsoft Visual C++ Redistributable is not installed. ' +
  98. `You can download it from ${msvcDownloadLink}`,
  99. { cause: error }
  100. );
  101. }
  102. throw new Error(
  103. `Cannot find module ${id}. ` +
  104. `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` +
  105. 'Please try `npm i` again after removing both package-lock.json and node_modules directory.',
  106. { cause: error }
  107. );
  108. }
  109. };
  110. const { parse, parseAsync, xxhashBase64Url, xxhashBase36, xxhashBase16 } = requireWithFriendlyError(
  111. existsSync(path.join(__dirname, localName)) ? localName : `@rollup/rollup-${packageBase}`
  112. );
  113. function getPackageBase() {
  114. const imported = bindingsByPlatformAndArch[platform]?.[arch];
  115. if (!imported) {
  116. throwUnsupportedError(false);
  117. }
  118. if ('musl' in imported && isMusl()) {
  119. return imported.musl || throwUnsupportedError(true);
  120. }
  121. return imported.base;
  122. }
  123. function throwUnsupportedError(isMusl) {
  124. throw new Error(
  125. `Your current platform "${platform}${isMusl ? ' (musl)' : ''}" and architecture "${arch}" combination is not yet supported by the native Rollup build. Please use the WASM build "@rollup/wasm-node" instead.
  126. The following platform-architecture combinations are supported:
  127. ${Object.entries(bindingsByPlatformAndArch)
  128. .flatMap(([platformName, architectures]) =>
  129. Object.entries(architectures).flatMap(([architectureName, { musl }]) => {
  130. const name = `${platformName}-${architectureName}`;
  131. return musl ? [name, `${name} (musl)`] : [name];
  132. })
  133. )
  134. .join('\n')}
  135. If this is important to you, please consider supporting Rollup to make a native build for your platform and architecture available.`
  136. );
  137. }
  138. module.exports.parse = parse;
  139. module.exports.parseAsync = parseAsync;
  140. module.exports.xxhashBase64Url = xxhashBase64Url;
  141. module.exports.xxhashBase36 = xxhashBase36;
  142. module.exports.xxhashBase16 = xxhashBase16;