vitest-dev / vscode

VS Code extension for Vitest
https://vitest.dev/vscode
MIT License
744 stars 84 forks source link

Crash at startup on Windows when using Yarn PnP #416

Closed Nithanim-Work closed 1 month ago

Nithanim-Work commented 3 months ago

Describe the bug

We are using Yarn 4.3.0 with PnP on Windows 11 with Node.js v20.11.0. On opening project folder in VS Code, the Vitest extension fails to start with the error seen below in the "Output" section.

Debugging this issue I extracted the following error message:

[Error 2:50:01 PM] {"type":"error","errors":["","Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme in: file, data, and node are supported by the default ESM loader. On Windows, absolute paths must be valid file:// URLs. Received protocol 'c:'\n    at throwIfUnsupportedURLScheme (node:internal/modules/esm/load:239:11)\n    at defaultLoad (node:internal/modules/esm/load:130:3)\n    at nextLoad (node:internal/modules/esm/hooks:865:28)\n    at load$1 (file:///c:/d/r/.pnp.loader.mjs:1514:12)\n    at nextLoad (node:internal/modules/esm/hooks:865:28)\n    at Hooks.load (node:internal/modules/esm/hooks:448:26)\n    at ModuleLoader.load (node:internal/modules/esm/loader:408:34)\n    at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:291:56)\n    at new ModuleJob (node:internal/modules/esm/module_job:65:26)\n    at #createModuleJob (node:internal/modules/esm/loader:303:17)"]}

I traced this back to the following line: https://github.com/vitest-dev/vscode/blob/v0.12.2/src/worker/worker.ts#L15 The source of the path comes from here: https://github.com/vitest-dev/vscode/blob/v0.12.2/src/api.ts#L249 When used in execArgv, it is first passed to pathToFileURL() but not later. Therefore, I added it to the worker.ts too.

But that only resolved that error. Next, it failed on this line: https://github.com/vitest-dev/vscode/blob/v0.12.2/src/worker/init.ts#L6 with the following extracted error:

[Error 3:08:33 PM] {"type":"error","errors":["","Error: ENOENT: no such file or directory, open 'C:\\d\\r\\.yarn\\cache\\picocolors-npm-1.0.1-39442f3da8-fa68166d1f.zip\\node_modules\\picocolors\\picocolors.js'\n    at Object.openSync (node:fs:581:18)\n    at readFileSync (node:fs:457:35)\n    at getSourceSync (node:internal/modules/esm/load:85:14)\n    at getSource (node:internal/modules/esm/translators:70:10)\n    at createCJSModuleWrap (node:internal/modules/esm/translators:290:32)\n    at ModuleLoader.commonjsStrategy (node:internal/modules/esm/translators:369:10)"]}

I found out that https://github.com/vitest-dev/vscode/issues/285 which now seems to be the identical issue. For testing, I changed await import(meta.vitestNodePath) to await import('vitest/node') but that would not even compile. So I tried await import((() => 'vitest/node')()) to prevent possible static resolve which worked. But then it crashed somewhere down in vitest itself for not finding stuff (rollup). I did not chase that further because vitest itself works so that must not be the problem.

Then I stumbled upon a this interesting issue here: https://github.com/yarnpkg/berry/issues/6157 This might be the root problem since it states that import differs from require when using register. It basically shows, that import "ignores" the loader and we use import here.

I then went back to execArgv (https://github.com/vitest-dev/vscode/blob/v0.12.2/src/api.ts#L257) to use the loader all the time by replacing undefined:

  const execArgv = pnpLoader && pnp && !gte(process.version, '18.19.0')
    ? [
        '--require',
        pnp,
        '--experimental-loader',
        pathToFileURL(pnpLoader).toString(),
      ]
    : [
        '--require',
        pnp,
        '--loader',
        pathToFileURL(pnpLoader!).toString(),
      ]

(Very bad code but I just needed it to work.) I also removed the now useless register on https://github.com/vitest-dev/vscode/blob/v0.12.2/src/worker/worker.ts#L15

Finally the extension loads successfully and also shows tests in the "Testing" tab in VS Code!

However, the --loader seems to be discouraged also. It is discussed in this issue: https://github.com/nodejs/node/issues/51196

BUT it still crashes when interacting with a test:

[INFO 3:36:15 PM] [API] Collecting tests: test/Dummy.test.ts
[Worker] 
node:internal/event_target:1100
  process.nextTick(() => { throw err; });
                           ^
[Worker] Error: Cannot find module 'C:\d\r\.yarn\cache\tinypool-npm-0.8.4-043dfecb16-7365944c25.zip\node_modules\tinypool\dist\esm\entry\worker.js'
    at Module._resolveFilename (node:internal/modules/cjs/loader:1144:15)
    at Module._load (node:internal/modules/cjs/loader:985:27)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at MessagePort.<anonymous> (node:internal/main/worker_thread:186:26)
    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:826:20)
    at exports.emitMessage (node:internal/per_context/messageport:23:28)
Emitted 'error' event on Tinypool instance at:
    at EventEmitterReferencingAsyncResource.runInAsyncScope (node:async_hooks:206:9)
    at Tinypool.emit (file:///C:/d/r/.yarn/cache/tinypool-npm-0.8.4-043dfecb16-7365944c25.zip/node_modules/tinypool/dist/esm/index.js:61:31)
    at Worker.<anonymous> (file:///C:/d/r/.yarn/cache/tinypool-npm-0.8.4-043dfecb16-7365944c25.zip/node_modules/tinypool/dist/esm/index.js:752:30)
    at Worker.emit (node:events:518:28)
    at [kOnErrorMessage] (node:internal/worker:326:10)
    at [kOnMessage] (node:internal/worker:337:37)
    at MessagePort.<anonymous> (node:internal/worker:232:57)
    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:826:20)
    at exports.emitMessage (node:internal/per_context/messageport:23:28) {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}

I assume that the same issue is in "tinypool" since it allows "child_process" as stated in its readme.

However, I am ending it here for now. Maybe there is something helpful for somebody that helps tracking down the problems fully. Thank you!

Reproduction

Repository for minimal example: https://github.com/Nithanim-Work/vitest-reproducer Must be on Windows (11). Also assumes you have Yarn 4.3.0 (or using corepack), although I do not think that makes a difference.

Output

[INFO 2:33:01 PM] [v0.12.2] Vitest extension is activated because Vitest is installed or there is a Vite/Vitest config file in the workspace.
[INFO 2:33:02 PM] [API] Running Vitest vpnp (r/vitest.config.ts) with Node.js: C:\Program Files\nodejs\node.EXE
[Error 2:33:02 PM] [Error Error] Vitest failed to start: 

r
Error: Vitest failed to start: 

r
    at ChildProcess.f (c:\Users\Redacted\.vscode\extensions\vitest.explorer-0.12.2\dist\extension.js:18:5392)
    at ChildProcess.emit (node:events:514:28)
    at emit (node:internal/child_process:951:14)
    at process.processTicksAndRejections (node:internal/process/task_queues:83:21)

Version

v0.12.2

Validations

sheremet-va commented 1 month ago

Should be fixed by https://github.com/vitest-dev/vscode/pull/456