index.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.loadBindings = loadBindings;
  6. exports.isWasm = isWasm;
  7. exports.transform = transform;
  8. exports.transformSync = transformSync;
  9. exports.minify = minify;
  10. exports.minifySync = minifySync;
  11. exports.bundle = bundle;
  12. exports.parse = parse;
  13. exports.getBinaryMetadata = getBinaryMetadata;
  14. exports.teardownCrashReporter = exports.teardownTraceSubscriber = exports.initCustomTraceSubscriber = exports.lockfilePatchPromise = void 0;
  15. var _path = _interopRequireDefault(require("path"));
  16. var _url = require("url");
  17. var _os = require("os");
  18. var _triples = require("next/dist/compiled/@napi-rs/triples");
  19. var Log = _interopRequireWildcard(require("../output/log"));
  20. var _options = require("./options");
  21. var _swcLoadFailure = require("../../telemetry/events/swc-load-failure");
  22. var _patchIncorrectLockfile = require("../../lib/patch-incorrect-lockfile");
  23. var _downloadWasmSwc = require("../../lib/download-wasm-swc");
  24. var _packageJson = require("next/package.json");
  25. function _interopRequireDefault(obj) {
  26. return obj && obj.__esModule ? obj : {
  27. default: obj
  28. };
  29. }
  30. function _getRequireWildcardCache() {
  31. if (typeof WeakMap !== "function") return null;
  32. var cache = new WeakMap();
  33. _getRequireWildcardCache = function() {
  34. return cache;
  35. };
  36. return cache;
  37. }
  38. function _interopRequireWildcard(obj) {
  39. if (obj && obj.__esModule) {
  40. return obj;
  41. }
  42. if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
  43. return {
  44. default: obj
  45. };
  46. }
  47. var cache = _getRequireWildcardCache();
  48. if (cache && cache.has(obj)) {
  49. return cache.get(obj);
  50. }
  51. var newObj = {};
  52. var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
  53. for(var key in obj){
  54. if (Object.prototype.hasOwnProperty.call(obj, key)) {
  55. var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
  56. if (desc && (desc.get || desc.set)) {
  57. Object.defineProperty(newObj, key, desc);
  58. } else {
  59. newObj[key] = obj[key];
  60. }
  61. }
  62. }
  63. newObj.default = obj;
  64. if (cache) {
  65. cache.set(obj, newObj);
  66. }
  67. return newObj;
  68. }
  69. const ArchName = (0, _os).arch();
  70. const PlatformName = (0, _os).platform();
  71. const triples = _triples.platformArchTriples[PlatformName][ArchName] || [];
  72. // These are the platforms we'll try to load wasm bindings first,
  73. // only try to load native bindings if loading wasm binding somehow fails.
  74. // Fallback to native binding is for migration period only,
  75. // once we can verify loading-wasm-first won't cause visible regressions,
  76. // we'll not include native bindings for these platform at all.
  77. const knownDefaultWasmFallbackTriples = [
  78. "aarch64-linux-android",
  79. "x86_64-unknown-freebsd",
  80. "aarch64-pc-windows-msvc",
  81. "arm-linux-androideabi",
  82. "armv7-unknown-linux-gnueabihf",
  83. "i686-pc-windows-msvc",
  84. ];
  85. let nativeBindings;
  86. let wasmBindings;
  87. let downloadWasmPromise;
  88. let pendingBindings;
  89. let swcTraceFlushGuard;
  90. let swcCrashReporterFlushGuard;
  91. const lockfilePatchPromise = {};
  92. exports.lockfilePatchPromise = lockfilePatchPromise;
  93. async function loadBindings() {
  94. if (pendingBindings) {
  95. return pendingBindings;
  96. }
  97. pendingBindings = new Promise(async (resolve, reject)=>{
  98. if (!lockfilePatchPromise.cur) {
  99. // always run lockfile check once so that it gets patched
  100. // even if it doesn't fail to load locally
  101. lockfilePatchPromise.cur = (0, _patchIncorrectLockfile).patchIncorrectLockfile(process.cwd()).catch(console.error);
  102. }
  103. let attempts = [];
  104. const shouldLoadWasmFallbackFirst = triples.some((triple)=>{
  105. return !!(triple == null ? void 0 : triple.raw) && knownDefaultWasmFallbackTriples.includes(triple.raw);
  106. });
  107. if (shouldLoadWasmFallbackFirst) {
  108. const fallbackBindings = await tryLoadWasmWithFallback(attempts);
  109. if (fallbackBindings) {
  110. return resolve(fallbackBindings);
  111. }
  112. }
  113. try {
  114. return resolve(loadNative());
  115. } catch (a) {
  116. attempts = attempts.concat(a);
  117. }
  118. // For these platforms we already tried to load wasm and failed, skip reattempt
  119. if (!shouldLoadWasmFallbackFirst) {
  120. const fallbackBindings = await tryLoadWasmWithFallback(attempts);
  121. if (fallbackBindings) {
  122. return resolve(fallbackBindings);
  123. }
  124. }
  125. logLoadFailure(attempts, true);
  126. });
  127. return pendingBindings;
  128. }
  129. async function tryLoadWasmWithFallback(attempts) {
  130. try {
  131. let bindings = await loadWasm();
  132. (0, _swcLoadFailure).eventSwcLoadFailure({
  133. wasm: "enabled"
  134. });
  135. return bindings;
  136. } catch (a) {
  137. attempts = attempts.concat(a);
  138. }
  139. try {
  140. // if not installed already download wasm package on-demand
  141. // we download to a custom directory instead of to node_modules
  142. // as node_module import attempts are cached and can't be re-attempted
  143. // x-ref: https://github.com/nodejs/modules/issues/307
  144. const wasmDirectory = _path.default.join(_path.default.dirname(require.resolve("next/package.json")), "wasm");
  145. if (!downloadWasmPromise) {
  146. downloadWasmPromise = (0, _downloadWasmSwc).downloadWasmSwc(_packageJson.version, wasmDirectory);
  147. }
  148. await downloadWasmPromise;
  149. let bindings = await loadWasm((0, _url).pathToFileURL(wasmDirectory).href);
  150. (0, _swcLoadFailure).eventSwcLoadFailure({
  151. wasm: "fallback"
  152. });
  153. // still log native load attempts so user is
  154. // aware it failed and should be fixed
  155. for (const attempt of attempts){
  156. Log.warn(attempt);
  157. }
  158. return bindings;
  159. } catch (a1) {
  160. attempts = attempts.concat(a1);
  161. }
  162. }
  163. function loadBindingsSync() {
  164. let attempts = [];
  165. try {
  166. return loadNative();
  167. } catch (a) {
  168. attempts = attempts.concat(a);
  169. }
  170. // we can leverage the wasm bindings if they are already
  171. // loaded
  172. if (wasmBindings) {
  173. return wasmBindings;
  174. }
  175. logLoadFailure(attempts);
  176. }
  177. let loggingLoadFailure = false;
  178. function logLoadFailure(attempts, triedWasm = false) {
  179. // make sure we only emit the event and log the failure once
  180. if (loggingLoadFailure) return;
  181. loggingLoadFailure = true;
  182. for (let attempt of attempts){
  183. Log.warn(attempt);
  184. }
  185. (0, _swcLoadFailure).eventSwcLoadFailure({
  186. wasm: triedWasm ? "failed" : undefined
  187. }).then(()=>lockfilePatchPromise.cur || Promise.resolve()).finally(()=>{
  188. Log.error(`Failed to load SWC binary for ${PlatformName}/${ArchName}, see more info here: https://nextjs.org/docs/messages/failed-loading-swc`);
  189. process.exit(1);
  190. });
  191. }
  192. async function loadWasm(importPath = "") {
  193. if (wasmBindings) {
  194. return wasmBindings;
  195. }
  196. let attempts = [];
  197. for (let pkg of [
  198. "@next/swc-wasm-nodejs",
  199. "@next/swc-wasm-web"
  200. ]){
  201. try {
  202. let pkgPath = pkg;
  203. if (importPath) {
  204. // the import path must be exact when not in node_modules
  205. pkgPath = _path.default.join(importPath, pkg, "wasm.js");
  206. }
  207. let bindings = await import(pkgPath);
  208. if (pkg === "@next/swc-wasm-web") {
  209. bindings = await bindings.default();
  210. }
  211. Log.info("Using wasm build of next-swc");
  212. // Note wasm binary does not support async intefaces yet, all async
  213. // interface coereces to sync interfaces.
  214. wasmBindings = {
  215. isWasm: true,
  216. transform (src, options) {
  217. // TODO: we can remove fallback to sync interface once new stable version of next-swc gets published (current v12.2)
  218. return (bindings == null ? void 0 : bindings.transform) ? bindings.transform(src.toString(), options) : Promise.resolve(bindings.transformSync(src.toString(), options));
  219. },
  220. transformSync (src, options) {
  221. return bindings.transformSync(src.toString(), options);
  222. },
  223. minify (src, options) {
  224. return (bindings == null ? void 0 : bindings.minify) ? bindings.minify(src.toString(), options) : Promise.resolve(bindings.minifySync(src.toString(), options));
  225. },
  226. minifySync (src, options) {
  227. return bindings.minifySync(src.toString(), options);
  228. },
  229. parse (src, options) {
  230. return (bindings == null ? void 0 : bindings.parse) ? bindings.parse(src.toString(), options) : Promise.resolve(bindings.parseSync(src.toString(), options));
  231. },
  232. parseSync (src, options) {
  233. const astStr = bindings.parseSync(src.toString(), options);
  234. return astStr;
  235. },
  236. getTargetTriple () {
  237. return undefined;
  238. }
  239. };
  240. return wasmBindings;
  241. } catch (e) {
  242. // Only log attempts for loading wasm when loading as fallback
  243. if (importPath) {
  244. if ((e == null ? void 0 : e.code) === "ERR_MODULE_NOT_FOUND") {
  245. attempts.push(`Attempted to load ${pkg}, but it was not installed`);
  246. } else {
  247. var _message;
  248. attempts.push(`Attempted to load ${pkg}, but an error occurred: ${(_message = e.message) != null ? _message : e}`);
  249. }
  250. }
  251. }
  252. }
  253. throw attempts;
  254. }
  255. function loadNative() {
  256. if (nativeBindings) {
  257. return nativeBindings;
  258. }
  259. let bindings;
  260. let attempts = [];
  261. for (const triple of triples){
  262. try {
  263. bindings = require(`@next/swc/native/next-swc.${triple.platformArchABI}.node`);
  264. Log.info("Using locally built binary of @next/swc");
  265. break;
  266. } catch (e) {}
  267. }
  268. if (!bindings) {
  269. for (const triple of triples){
  270. let pkg = `@next/swc-${triple.platformArchABI}`;
  271. try {
  272. bindings = require(pkg);
  273. break;
  274. } catch (e) {
  275. if ((e == null ? void 0 : e.code) === "MODULE_NOT_FOUND") {
  276. attempts.push(`Attempted to load ${pkg}, but it was not installed`);
  277. } else {
  278. var _message;
  279. attempts.push(`Attempted to load ${pkg}, but an error occurred: ${(_message = e.message) != null ? _message : e}`);
  280. }
  281. }
  282. }
  283. }
  284. if (bindings) {
  285. // Initialize crash reporter, as earliest as possible from any point of import.
  286. // The first-time import to next-swc is not predicatble in the import tree of next.js, which makes
  287. // we can't rely on explicit manual initialization as similar to trace reporter.
  288. if (!swcCrashReporterFlushGuard) {
  289. // Crash reports in next-swc should be treated in the same way we treat telemetry to opt out.
  290. /* TODO: temporarily disable initialization while confirming logistics.
  291. let telemetry = new Telemetry({ distDir: process.cwd() })
  292. if (telemetry.isEnabled) {
  293. swcCrashReporterFlushGuard = bindings.initCrashReporter?.()
  294. }*/ }
  295. nativeBindings = {
  296. isWasm: false,
  297. transform (src, options) {
  298. var ref;
  299. const isModule = typeof src !== undefined && typeof src !== "string" && !Buffer.isBuffer(src);
  300. options = options || {};
  301. if (options == null ? void 0 : (ref = options.jsc) == null ? void 0 : ref.parser) {
  302. var _syntax;
  303. options.jsc.parser.syntax = (_syntax = options.jsc.parser.syntax) != null ? _syntax : "ecmascript";
  304. }
  305. return bindings.transform(isModule ? JSON.stringify(src) : src, isModule, toBuffer(options));
  306. },
  307. transformSync (src, options) {
  308. var ref;
  309. if (typeof src === undefined) {
  310. throw new Error("transformSync doesn't implement reading the file from filesystem");
  311. } else if (Buffer.isBuffer(src)) {
  312. throw new Error("transformSync doesn't implement taking the source code as Buffer");
  313. }
  314. const isModule = typeof src !== "string";
  315. options = options || {};
  316. if (options == null ? void 0 : (ref = options.jsc) == null ? void 0 : ref.parser) {
  317. var _syntax;
  318. options.jsc.parser.syntax = (_syntax = options.jsc.parser.syntax) != null ? _syntax : "ecmascript";
  319. }
  320. return bindings.transformSync(isModule ? JSON.stringify(src) : src, isModule, toBuffer(options));
  321. },
  322. minify (src, options) {
  323. return bindings.minify(toBuffer(src), toBuffer(options != null ? options : {}));
  324. },
  325. minifySync (src, options) {
  326. return bindings.minifySync(toBuffer(src), toBuffer(options != null ? options : {}));
  327. },
  328. bundle (options) {
  329. return bindings.bundle(toBuffer(options));
  330. },
  331. parse (src, options) {
  332. return bindings.parse(src, toBuffer(options != null ? options : {}));
  333. },
  334. getTargetTriple: bindings.getTargetTriple,
  335. initCustomTraceSubscriber: bindings.initCustomTraceSubscriber,
  336. teardownTraceSubscriber: bindings.teardownTraceSubscriber,
  337. teardownCrashReporter: bindings.teardownCrashReporter
  338. };
  339. return nativeBindings;
  340. }
  341. throw attempts;
  342. }
  343. function toBuffer(t) {
  344. return Buffer.from(JSON.stringify(t));
  345. }
  346. async function isWasm() {
  347. let bindings = await loadBindings();
  348. return bindings.isWasm;
  349. }
  350. async function transform(src, options) {
  351. let bindings = await loadBindings();
  352. return bindings.transform(src, options);
  353. }
  354. function transformSync(src, options) {
  355. let bindings = loadBindingsSync();
  356. return bindings.transformSync(src, options);
  357. }
  358. async function minify(src, options) {
  359. let bindings = await loadBindings();
  360. return bindings.minify(src, options);
  361. }
  362. function minifySync(src, options) {
  363. let bindings = loadBindingsSync();
  364. return bindings.minifySync(src, options);
  365. }
  366. async function bundle(options) {
  367. let bindings = loadBindingsSync();
  368. return bindings.bundle(toBuffer(options));
  369. }
  370. async function parse(src, options) {
  371. let bindings = await loadBindings();
  372. let parserOptions = (0, _options).getParserOptions(options);
  373. return bindings.parse(src, parserOptions).then((astStr)=>JSON.parse(astStr));
  374. }
  375. function getBinaryMetadata() {
  376. let bindings;
  377. try {
  378. bindings = loadNative();
  379. } catch (e) {
  380. // Suppress exceptions, this fn allows to fail to load native bindings
  381. }
  382. return {
  383. target: bindings == null ? void 0 : bindings.getTargetTriple == null ? void 0 : bindings.getTargetTriple()
  384. };
  385. }
  386. const initCustomTraceSubscriber = (()=>{
  387. return (filename)=>{
  388. if (!swcTraceFlushGuard) {
  389. // Wasm binary doesn't support trace emission
  390. let bindings = loadNative();
  391. swcTraceFlushGuard = bindings.initCustomTraceSubscriber(filename);
  392. }
  393. };
  394. })();
  395. exports.initCustomTraceSubscriber = initCustomTraceSubscriber;
  396. const teardownTraceSubscriber = (()=>{
  397. let flushed = false;
  398. return ()=>{
  399. if (!flushed) {
  400. flushed = true;
  401. try {
  402. let bindings = loadNative();
  403. if (swcTraceFlushGuard) {
  404. bindings.teardownTraceSubscriber(swcTraceFlushGuard);
  405. }
  406. } catch (e) {
  407. // Suppress exceptions, this fn allows to fail to load native bindings
  408. }
  409. }
  410. };
  411. })();
  412. exports.teardownTraceSubscriber = teardownTraceSubscriber;
  413. const teardownCrashReporter = (()=>{
  414. let flushed = false;
  415. return ()=>{
  416. if (!flushed) {
  417. flushed = true;
  418. try {
  419. let bindings = loadNative();
  420. if (swcCrashReporterFlushGuard) {
  421. bindings.teardownCrashReporter(swcCrashReporterFlushGuard);
  422. }
  423. } catch (e) {
  424. // Suppress exceptions, this fn allows to fail to load native bindings
  425. }
  426. }
  427. };
  428. })();
  429. exports.teardownCrashReporter = teardownCrashReporter;
  430. //# sourceMappingURL=index.js.map