sveltejs / kit

web development, streamlined
https://svelte.dev/docs/kit
MIT License
18.69k stars 1.93k forks source link

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '<npm package>' imported from... #9403

Closed maietta closed 1 year ago

maietta commented 1 year ago

Describe the bug

In my "Minimum reproducible example", I use a bare minimum fresh install of SvelteKit based on the current docs and then add my single server-side page called src/routes/+server.ts. This file uses the "canvas" library to let me draw an image and place some text on it, then render that image out to the client. This must be done server side and it works perfectly fine in development.

I've experience on numerous occasions trying to build with SvelteKit, modules not being found despite running the required commands to install them. Clearing NPM cache doesn't help. Dumping and re-creating node_modules/ doesn't work either. Even switching out npm for yarn doesn't make any difference.

Because the code runs perfectly fine in development, using npm run dev and even using the preview option after build, such as npm run preview, I am confident I've done everything correctly. HOWEVER, when deploying the site to my servers using the node adaptor, i.e., "production", I get an error about a missing "canvas".

I NEED TO HIGHLIGHT THAT THIS IS NOT JUST RELATED TO "canvas". THIS ERROR ALSO APPLIED TO "sharp" and "zod" LIBRARIES AS WELL.

I've even switched out node-canvas library with another called sharp, rewriting my code to use that and had the exact same problem. I even went as far as changing out my Dockerfile's base image from node on alpine, to node on Debian slim.

Reproduction

HERE IS A LINK TO THE EXAMPLE PROJECT: https://github.com/maietta/mre-sveltekit-canvas

To reproduce the issue, run the following commands:

First, create the build:

npm install npm run build

Test the build locally:

npm run dev

Visit http://localhost:5173 and see that an image loads correctly. This is not a page, but rather an image with some text on it. As you can see, it works fine.

Then,

Simulate "production" environment:

docker build -t test . && docker run -p 80:80 test

Logs

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'canvas' imported from /server/chunks/_server.ts-xxxxxxx.js
    at new NodeError (node:internal/errors:387:5)
    at packageResolve (node:internal/modules/esm/resolve:852:9)
    at moduleResolve (node:internal/modules/esm/resolve:901:20)
    at defaultResolve (node:internal/modules/esm/resolve:1115:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:841:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)
    at link (node:internal/modules/esm/module_job:75:36)
Error: Not found: /favicon.ico
    at resolve (file:///server/index.js:3898:18)
    at resolve (file:///server/index.js:3773:34)
    at Object.#options.hooks.handle (file:///server/index.js:3942:59)
    at respond (file:///server/index.js:3771:43)

System Info

System:
    OS: Windows 10 10.0.22621
    CPU: (8) x64 Intel(R) Core(TM) i7-1065G7 CPU @ 1.80GHz
    Memory: 13.28 GB / 63.77 GB
  Binaries:
    Node: 16.16.0 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 9.4.1 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: Spartan (44.22621.1344.0), Chromium (110.0.1587.63)
    Internet Explorer: 11.0.22621.1
  npmPackages:
    @sveltejs/adapter-auto: ^2.0.0 => 2.0.0 
    @sveltejs/adapter-node: ^1.2.2 => 1.2.2 
    @sveltejs/kit: ^1.5.0 => 1.11.0 
    svelte: ^3.54.0 => 3.56.0 
    vite: ^4.0.0 => 4.1.4

Severity

blocking all usage of SvelteKit

Additional Information

I have been trying to solve this problem for more than a full month. Nobody else seems to have my exact problem because they are not using the "node adaptor".

manuganji commented 1 year ago

In your docker file, I don't see an npm install command?

maietta commented 1 year ago

In your docker file, I don't see an npm install command?

I should be able to build my apps elsewhere and deploy them to cheap, low resource servers.

The dockerfile is only here to replicate my hosting environment.

I use CapRover and will soon be deploying directly to Docker Swarm using Traefik and these lightweight containers.

Conduitry commented 1 year ago

The Node adapter only bundles dev dependencies. canvas is a prod dependency, and so needs to be present at runtime. See https://kit.svelte.dev/docs/adapter-node#deploying

maietta commented 1 year ago

Why did you close it?

I studied the difference between dev dependencies vs non-dev dependencies use-case. The official library docs all cited the proper way to install the packages and I followed them. So what you are telling me is that I learned it wrong and the authors of the libraries also got it wrong?

I re-installed with npm i --save-dev canvas and now this is my error:

Using @sveltejs/adapter-node error during build: RollupError: Unexpected character '�' (Note that you need plugins to import files that are not JavaScript) at error (file:///C:/Users/nick/Documents/GitHub/mre-sveltekit-canvas/node_modules/rollup/dist/es/shared/node-entry.js:2125:30) at Module.error (file:///C:/Users/nick/Documents/GitHub/mre-sveltekit-canvas/node_modules/rollup/dist/es/shared/node-entry.js:13316:16) at Module.tryParse (file:///C:/Users/nick/Documents/GitHub/mre-sveltekit-canvas/node_modules/rollup/dist/es/shared/node-entry.js:13993:25) at Module.setSource (file:///C:/Users/nick/Documents/GitHub/mre-sveltekit-canvas/node_modules/rollup/dist/es/shared/node-entry.js:13603:39) at ModuleLoader.addModuleSource (file:///C:/Users/nick/Documents/GitHub/mre-sveltekit-canvas/node_modules/rollup/dist/es/shared/node-entry.js:23569:20)

maietta commented 1 year ago

Sticking with how the libraries are supposed to be installed, i.e., installing as a regular dependency, it does work now.

The difference that resolved my issue was running two commands: npm build outside my container and npm ci --omit-dev inside my container. I have no clue why this triggers it working and it makes no sense to me.

I would think that npm build would effectively bundle everything I need. The secondary npm ci --omit-dev would only get rid of the dev dependencies, which would have included canvas had I been successful in getting it to work as a dev dependency. There must be sort of magic behind the npm ci --omit-dev command that changes linking.

Either way, it's sort of working now. I can finally consider this closed. I will have to further refine my deployment strategy.

Thanks for pointing me to the page I already reviewed, but doesn't explain how this fixes the problem.

joethompson1 commented 7 months ago

The Node adapter only bundles dev dependencies. canvas is a prod dependency, and so needs to be present at runtime. See https://kit.svelte.dev/docs/adapter-node#deploying

I can confirm this solves it.

I was having real trouble with using the stripe package in production when it was deployed to Gcloud but it worked fine when running locally.

You need to make sure you specifically install dependencies when you build for production ie for me it was in my dockerfile, adding this line to my dockerfile fixed the problem: RUN npm ci --omit=dev