From b406131bf3b8d5111bb04c4f45f5196a907c3bc7 Mon Sep 17 00:00:00 2001
From: Filip Malinowski <crimhead@gmail.com>
Date: Thu, 20 Jun 2024 18:01:17 +0200
Subject: [PATCH] fix: support yarn pnp with node 20

https://github.com/un-ts/synckit/issues/174
---
 src/index.ts | 30 ++++++++++++++++++++++++------
 src/types.ts |  1 +
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/src/index.ts b/src/index.ts
index 8ef71b1f4..a6bded57a 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,6 +1,6 @@
 import { createHash } from 'node:crypto'
 import fs from 'node:fs'
-import { createRequire } from 'node:module'
+import module from 'node:module'
 import path from 'node:path'
 import { fileURLToPath, pathToFileURL } from 'node:url'
 import {
@@ -53,6 +53,8 @@ const {
   SYNCKIT_TS_RUNNER,
 } = process.env
 
+const IS_NODE_20 = Number(process.versions.node.split('.')[0]) >= 20
+
 export const DEFAULT_TIMEOUT = SYNCKIT_TIMEOUT ? +SYNCKIT_TIMEOUT : undefined
 
 /* istanbul ignore next */
@@ -133,7 +135,7 @@ export function createSyncFn<T extends AnyAsyncFn<R>, R = unknown>(
 
 const cjsRequire =
   typeof require === 'undefined'
-    ? createRequire(import.meta.url)
+    ? module.createRequire(import.meta.url)
     : /* istanbul ignore next */ require
 
 const dataUrl = (code: string) =>
@@ -252,6 +254,8 @@ const setupTsRunner = (
     }
   }
 
+  let pnpExperimentalLoaderPath: string | undefined
+
   /* istanbul ignore if -- https://github.com/facebook/jest/issues/5274 */
   if (process.versions.pnp) {
     const nodeOptions = NODE_OPTIONS?.split(/\s+/)
@@ -275,8 +279,15 @@ const setupTsRunner = (
         // Transform path to file URL because nodejs does not accept
         // absolute Windows paths in the --experimental-loader option.
         // https://github.com/un-ts/synckit/issues/123
-        const experimentalLoader = pathToFileURL(pnpLoaderPath).toString()
-        execArgv = ['--experimental-loader', experimentalLoader, ...execArgv]
+        pnpExperimentalLoaderPath = pathToFileURL(pnpLoaderPath).toString()
+
+        if (!IS_NODE_20) {
+          execArgv = [
+            '--experimental-loader',
+            pnpExperimentalLoaderPath,
+            ...execArgv,
+          ]
+        }
       }
     }
   }
@@ -288,6 +299,7 @@ const setupTsRunner = (
     tsRunner,
     tsUseEsm,
     workerPath,
+    pnpExperimentalLoaderPath,
     execArgv,
   }
 }
@@ -428,6 +440,7 @@ function startWorkerThread<R, T extends AnyAsyncFn<R>>(
     tsUseEsm,
     tsRunner: finalTsRunner,
     workerPath: finalWorkerPath,
+    pnpExperimentalLoaderPath,
     execArgv: finalExecArgv,
   } = setupTsRunner(workerPath, { execArgv, tsRunner })
 
@@ -501,7 +514,7 @@ function startWorkerThread<R, T extends AnyAsyncFn<R>>(
         : workerPathUrl,
     {
       eval: useEval,
-      workerData: { sharedBuffer, workerPort },
+      workerData: { sharedBuffer, workerPort, pnpExperimentalLoaderPath },
       transferList: [workerPort, ...transferList],
       execArgv: finalExecArgv,
     },
@@ -561,7 +574,12 @@ export function runAsWorker<
     return
   }
 
-  const { workerPort, sharedBuffer } = workerData as WorkerData
+  const { workerPort, sharedBuffer, pnpExperimentalLoaderPath } =
+    workerData as WorkerData
+
+  if (pnpExperimentalLoaderPath && IS_NODE_20) {
+    module.register(pnpExperimentalLoaderPath, import.meta.url)
+  }
 
   const sharedBufferView = new Int32Array(sharedBuffer, 0, 1)
 
diff --git a/src/types.ts b/src/types.ts
index 79dfdb4c0..8305653e4 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -28,6 +28,7 @@ export interface MainToWorkerMessage<T extends unknown[]> {
 export interface WorkerData {
   sharedBuffer: SharedArrayBuffer
   workerPort: MessagePort
+  pnpExperimentalLoaderPath: string | undefined
 }
 
 export interface DataMessage<T> {