| 1 | import Module from "node:module"; |
| 2 | |
| 3 | // The harness runs vite in-process inside the playwright worker. |
| 4 | // `@tailwindcss/node`'s ESM build registers an async module-customization |
| 5 | // loader (`esm-cache.loader.mjs`) at import time; on node >= 24 that loader |
| 6 | // combined with playwright's own sync transform hooks makes subsequent |
| 7 | // `require()` calls from ESM-imported CJS modules fail with `Expected a |
| 8 | // string ... for the "source" from the "load" hook but got undefined/null`, |
| 9 | // killing every in-process vite build/dev server. Tailwind skips the |
| 10 | // registration under bun (it is purely a config-import cache), so dropping |
| 11 | // it is safe. Imported for its side effect from Playwright.ts so every |
| 12 | // playwright worker process is guarded before vite loads tailwind. |
| 13 | let installed = false; |
| 14 | |
| 15 | export const installTailwindNodeCompat = (): void => { |
| 16 | if (installed) return; |
| 17 | installed = true; |
| 18 | const originalRegister = Module.register.bind(Module); |
| 19 | Module.register = ((specifier: unknown, ...rest: Array<never>) => { |
| 20 | if (String(specifier).includes("esm-cache")) return; |
| 21 | return (originalRegister as (...args: Array<unknown>) => unknown)( |
| 22 | specifier, |
| 23 | ...rest, |
| 24 | ); |
| 25 | }) as typeof Module.register; |
| 26 | // Propagate the patched `register` into the `node:module` ESM namespace — |
| 27 | // tailwind calls it through an ESM named-import binding, which snapshots |
| 28 | // builtin exports at namespace creation. |
| 29 | Module.syncBuiltinESMExports(); |
| 30 | }; |