Skip to content

Issue after upgrade using jsdom with optional dependencies #7045

Closed
@robpc

Description

@robpc

Describe the bug

I found this issue when upgrading a project that was using jsdom in server pages when upgrading from @sveltejs/kit@1.0.0-next.401 to @sveltejs/kit@1.0.0-next.491 but I have also seen this in newer versions like @sveltejs/kit@1.0.0-next.501.

When loading a page where the +page.server.ts includes jsdom, it throws an error in the console about an optional dependency for canvas

ENOENT: no such file or directory, open '__vite-optional-peer-dep:canvas:jsdom'
Error: ENOENT: no such file or directory, open '__vite-optional-peer-dep:canvas:jsdom'
    at Object.openSync (node:fs:585:3)
    at Object.readFileSync (node:fs:453:35)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1122:18)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (./node_modules/jsdom/lib/jsdom/utils.js:158:18)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)

Of note in the stacktrace is this line ./node_modules/jsdom/lib/jsdom/utils.js:158. Which looks like this

exports.Canvas = null;
let canvasInstalled = false;
try {
  require.resolve('canvas');
  canvasInstalled = true;
} catch (e) {
  // canvas is not installed
}
if (canvasInstalled) {
  ////// 👇 This is the line that causes the error //////
  const Canvas = require('canvas');
  if (typeof Canvas.createCanvas === 'function') {
    // In browserify, the require will succeed but return an empty object
    exports.Canvas = Canvas;
  }
}

I was unable to reproduce this error in vite alone, and before the upgrade it was not an issue.

Reproduction

This problem can be reproduced by

  1. Creating a new sveltekit project
  2. Adding the jsdom dependency
  3. Adding an import to jsdom to a new +page.server.ts file
  4. Loading that page in the browser

I have a repo made with the above steps

In that repo, you can see the issue by running npm run dev

If you replace the require.resolve('canvas'); line in ./node_modules/jsdom/lib/jsdom/utils.js:158, with the below

const r = require.resolve('canvas');
console.log('I RESOLVED CANVAS', JSON.stringify(r, null, 2));

You can see that it returns a string like in the error

I RESOLVED CANVAS "__vite-optional-peer-dep:canvas:jsdom"

If you comment out the import jsdom... the error goes away and the page loads the code that mimics the code in the jsdom modules, but require.resolve throws the exception that jsdom expects and so the require is skipped and there is no issue.

Logs

No response

System Info

System:
    OS: macOS 12.6
    CPU: (8) x64 Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
    Memory: 32.01 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.16.0 - ~/.nvm/versions/node/v16.16.0/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 8.11.0 - ~/.nvm/versions/node/v16.16.0/bin/npm
  Browsers:
    Chrome: 105.0.5195.125
    Firefox: 104.0.1
    Safari: 16.0
  npmPackages:
    @sveltejs/adapter-auto: next => 1.0.0-next.76
    @sveltejs/kit: next => 1.0.0-next.491
    svelte: ^3.44.0 => 3.50.1
    vite: ^3.1.0 => 3.1.3

Severity

blocking an upgrade

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions