bogeychan
bogeychanβ€’9mo ago

Help with npm peerDependencies

Hi πŸ‘‹ I am using an npm library that has @sinclair/typebox listed under peerDependencies. It gives the following runtime error whenever I import/use the library:
Uncaught Error: Cannot find module '@sinclair/typebox/value'
Uncaught Error: Cannot find module '@sinclair/typebox/value'
I tried to add this peer to my imports in deno.jsonc, but the error persists. I've read some comments claiming that peer dependencies work. am I missing something?
deno 1.38.3 (release, x86_64-unknown-linux-gnu)
v8 12.0.267.1
typescript 5.2.2
deno 1.38.3 (release, x86_64-unknown-linux-gnu)
v8 12.0.267.1
typescript 5.2.2
10 Replies
Deno AI Helper
Deno AI Helperβ€’9mo ago
Based on the documentation, Deno has added support for npm packages, including those with peer dependencies. However, the error you're encountering suggests that the module '@sinclair/typebox/value' cannot be found. Here are a few things you could try: 1. Check the version of the peer dependency: Ensure that the version of '@sinclair/typebox' listed under peerDependencies in the npm library's package.json file is compatible with the version you're using. 2. Check the import specifier: Make sure you're using the correct import specifier for '@sinclair/typebox'. In Deno, you should use the npm specifier format, which looks like this: npm:@sinclair/typebox@version. 3. Check your deno.jsonc file: Ensure that you've correctly added '@sinclair/typebox' to the imports field in your deno.jsonc file. The entry should look something like this:
{
"imports": {
"@sinclair/typebox/": "npm:@sinclair/typebox@version/"
}
}
{
"imports": {
"@sinclair/typebox/": "npm:@sinclair/typebox@version/"
}
}
4. Check for type errors: If the npm library doesn't distribute types, you might need to specify the corresponding @types package using a @deno-types directive above the import. However, this is usually not necessary for runtime errors. If you've checked all of these and the issue persists, it might be a limitation or bug in Deno's npm package support. In that case, I would recommend reporting the issue to the Deno team for further assistance.
Danielduel
Danielduelβ€’9mo ago
Hi @bogeychan, could you check if issue persists if you add import "npm:@sinclair/typebox@versionfrompeer" At the very start of your app? Imports field in deno.json is more like a mapping for aliases for things that will be imported (import map), they aren't importing anything alone
marvinh.
marvinh.β€’9mo ago
@bogeychan Can you share which dependency uses @sinclair/typebox as a peerDependency?
bogeychan
bogeychanβ€’8mo ago
Hi all πŸ‘‹ , @Danielduel, that makes it kinda worse... @marvinh., the dependency is npm:elysia@0.7.29 --- you can reproduce it like:
// main.ts
import 'npm:@bogeychan/elysia-polyfills/deno/index.js';

import 'npm:@sinclair/typebox@0.31.17';

import { cors } from 'npm:@elysiajs/cors@0.7.2';
import { html } from 'npm:@elysiajs/html@0.7.3';
import { bearer } from 'npm:@elysiajs/bearer@0.7.0';
import { swagger } from 'npm:@elysiajs/swagger@0.7.4';

import { Elysia } from 'npm:elysia@0.7.29';

new Elysia()
.use(cors())
.use(html())
.use(bearer())
.use(swagger())
.get('/', () => ({ hello: 'DenoπŸ‘‹' }))
.listen(8080);
// main.ts
import 'npm:@bogeychan/elysia-polyfills/deno/index.js';

import 'npm:@sinclair/typebox@0.31.17';

import { cors } from 'npm:@elysiajs/cors@0.7.2';
import { html } from 'npm:@elysiajs/html@0.7.3';
import { bearer } from 'npm:@elysiajs/bearer@0.7.0';
import { swagger } from 'npm:@elysiajs/swagger@0.7.4';

import { Elysia } from 'npm:elysia@0.7.29';

new Elysia()
.use(cors())
.use(html())
.use(bearer())
.use(swagger())
.get('/', () => ({ hello: 'DenoπŸ‘‹' }))
.listen(8080);
running the following commands works 50% of the time (checkout the screenshots): no change to code
rm -fr ~/.cache/deno/ deno.lock node_modules/
deno run --node-modules-dir --allow-net main.ts
rm -fr ~/.cache/deno/ deno.lock node_modules/
deno run --node-modules-dir --allow-net main.ts
doesn't work with or without --node-modules-dir idk why but sometimes deno decides to download the elysia dependency multiple times (with _1) suffix (checkout the screenshots). therefore some dependencies use/reference elysia_01 as it's peer). that's bad because both elysia's reference the same @sinclair/typebox package and it throws the error Duplicate type kind 'Files' detected because its executed twice, ... https://github.com/elysiajs/elysia/blob/757357f28749674844fc848e4ddd715134f7714f/src/type-system.ts#L144 the dependency tree looks something like this: - main.ts - elysia - @sinclair/typebox (peer) - @elysiajs/cors - elysia (peer) - @elysiajs/html - elysia (peer) - @elysiajs/bearer - elysia (peer) - @elysiajs/swagger - elysia (peer)
GitHub
elysia/src/type-system.ts at 757357f28749674844fc848e4ddd715134f771...
Ergonomic Framework for Humans. Contribute to elysiajs/elysia development by creating an account on GitHub.
No description
No description
marvinh.
marvinh.β€’8mo ago
That sounds like a bug. Filed an issue here https://github.com/denoland/deno/issues/21394
dsherret
dsherretβ€’8mo ago
bogeychan
bogeychanβ€’8mo ago
ooh, that makes sense, it works! thanks everyone <:hooray_deno:1035517542200004688> <:chun_happy:1076036980334415882>
marvinh.
marvinh.β€’8mo ago
We should file an issue on their tracker to make them aware of the missing depedency declaration
dsherret
dsherretβ€’8mo ago
i'm not sure about that in this case. I feel like Deno should just be able to figure it out
bogeychan
bogeychanβ€’8mo ago
this dependency resolution should work if deno wanna be fully compatible with node.js. in case you wanna try it out for yourself:
// main.js
import '@bogeychan/elysia-polyfills/node/index.js';

import { cors } from '@elysiajs/cors';
import { html } from '@elysiajs/html';
import { bearer } from '@elysiajs/bearer';
import { swagger } from '@elysiajs/swagger';

import { Elysia } from 'elysia';

const app = new Elysia()
.use(cors())
.use(html())
.use(bearer())
.use(swagger())
.get('/', () => ({ hello: 'Node.jsπŸ‘‹' }))
.listen(8080);

console.log('Listening on http://localhost:8080');
// main.js
import '@bogeychan/elysia-polyfills/node/index.js';

import { cors } from '@elysiajs/cors';
import { html } from '@elysiajs/html';
import { bearer } from '@elysiajs/bearer';
import { swagger } from '@elysiajs/swagger';

import { Elysia } from 'elysia';

const app = new Elysia()
.use(cors())
.use(html())
.use(bearer())
.use(swagger())
.get('/', () => ({ hello: 'Node.jsπŸ‘‹' }))
.listen(8080);

console.log('Listening on http://localhost:8080');
// package.json
{
"private": true,
"type": "module",
"main": "main.js",
"dependencies": {
"@bogeychan/elysia-polyfills": "0.6.1",
"@elysiajs/cors": "0.7.2",
"@elysiajs/html": "0.7.3",
"@elysiajs/bearer": "0.7.0",
"@elysiajs/swagger": "0.7.4",
"elysia": "0.7.29"
}
}
// package.json
{
"private": true,
"type": "module",
"main": "main.js",
"dependencies": {
"@bogeychan/elysia-polyfills": "0.6.1",
"@elysiajs/cors": "0.7.2",
"@elysiajs/html": "0.7.3",
"@elysiajs/bearer": "0.7.0",
"@elysiajs/swagger": "0.7.4",
"elysia": "0.7.29"
}
}
npm i && node . # v18.16.0
npm i && node . # v18.16.0
I'm fine with the workaround, since the polyfills are experimental anyway