Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Absolute imports do not work correctly #25691

Open
happyhunter7 opened this issue Sep 17, 2024 · 12 comments
Open

Absolute imports do not work correctly #25691

happyhunter7 opened this issue Sep 17, 2024 · 12 comments
Labels
needs info needs further information to be properly triaged question a question about the use of Deno

Comments

@happyhunter7
Copy link

happyhunter7 commented Sep 17, 2024

Version: Deno 1.46.3

I'm getting this error , when importing a file using dynamic import

TypeError: Relative import path "react" not prefixed with / or ./ or ../

How to reproduce:
let's say I have folder A which is a deno project and has a deno.json file
and then I have project B which also have a deno.json file

Now in project A in some file I'm using a dynamic import I'm trying to import a file from project B and that file in project B has (import react from 'react') inside

Now I have in both projects in deno.json in imports section this "react": "npm:[email protected]"
But even that doesn't help and I get the error that it is a relative import and react needs to be prefixed

But why is that if both projects have the dependency in the imports?

Is that I'm using a dynamic import with a absolte path in it?
like that

const a = await import(absolutePathToFile)

And the in that absolutePathToFile in that file I have (import react)

@lucacasonato
Copy link
Member

I can not reproduce the issue that you are describing, however I have some ideas that may be able to help you. Firstly, this what I am trying:

// a/deno.json
{
  "imports": {
    "react": "npm:react"
  }
}
// a/main.ts
await import("../b/mod.ts");
// b/mod.ts
import react from "react";
console.log(react);

Then when I run deno run -A a/main.ts, I get:

{
  Children: { ... },
  ...
  useTransition: [Function: useTransition],
  version: "18.3.1"
}

So this is working. However, if you move the deno.json into b/ rather than in a/, then it stops working:

error: Uncaught (in promise) TypeError: Relative import path "react" not prefixed with / or ./ or ../
    at file:///tmp/test/b/mod.ts:1:19
await import("../b/mod.ts");
^
    at async file:///tmp/test/a/main.ts:1:1

This happens because Deno resolves the config file only from the entrypoint, not from all files in your graph. What you want is a workspace. This is a collection of multiple packages, that all have their own import maps. And example how this could look in your example:

// deno.json
{
  "workspace": ["./a", "./b"]
}
// a/deno.json
{}
// b/deno.json
{
  "imports": {
    "react": "npm:react"
  }
}

Do let me know if this helps. If your issue is resolved, please close the issue.

@lucacasonato lucacasonato added question a question about the use of Deno needs info needs further information to be properly triaged labels Sep 18, 2024
@happyhunter7
Copy link
Author

Thanks @lucacasonato
So I can't use a workspace because I'm building a library that needs to import user files from their project, so workspace is not an option here.

I resolved it by using the old trick with deps.ts, the only cons is that users also will have to use deps.ts in their project if they'll want to use my library

But in a ideal way I would expect it to work similar to how node resolves the dependencies
if you import file B for example then node is doing a inverse Recursive walk and check for a node_modules in parent folders and imports from there, in this case it should check for a deno.json

Because at the moment to build a library similar to Next.js for example is super hard in deno, because your library should be able to import user dependencies not from your library, otherwise users will not be able to add other imports than the ones you have in your library

I'll try to create a repo that reproduces the issue, Thanks

@lucacasonato
Copy link
Member

Yes, please create a reproduction.

@happyhunter7
Copy link
Author

happyhunter7 commented Sep 18, 2024

@lucacasonato
here is a repo and in the Readme I added the steps to reproduce
https://github.com/happyhunter7/deno-imports-bug

Also as I said making this a workspace is not a posibility) even if it look like a workspace
Think of A as a shareable public lib which needs to be installed on user machine and then be able to import files from the user project

cc @lucacasonato

@lucacasonato
Copy link
Member

lucacasonato commented Sep 18, 2024

I don't understand. Are you saying your user would be running in b/, which then imports from a/, which then imports from b/ again? Or is the entrypoint actually a/?

The latter is not a supported use case for config file auto discovery - you have to then pass the config file from b/ manually using --config=b/deno.json. The former will just work.

@happyhunter7
Copy link
Author

No as you can see in the readme user just changes directory to B but the entry point is A , in B it just runs a command from A)
Is a weird use case, but it works in node, because I'm migrating a node project to deno and thats a bloker

Btw were you able to reproduce using the repo I shared?

@happyhunter7
Copy link
Author

And I cant pass a config because this is a dynamic import in the code as you can see in the repo I shared

Also I cant pass a config because if B has a import in config but A not and uses another lib then that again would not work

As you mentioned in node this is autodiscovery, thats what I kinda need

@happyhunter7
Copy link
Author

And no is not a circular dependency as you can see in the example there is no circula deps, the code just uses a diferent CWD
If it would be a circular thing then the code would not even work and throw another error

@lucacasonato
Copy link
Member

If the user wants to run code in a/ with the config file in b/ the user will have to manually specify the --config flag.

If they do not do this we will discover the config file based on the entrypoint (in a/), and thus use the config file in a/.

@happyhunter7
Copy link
Author

happyhunter7 commented Sep 18, 2024

That I think is not correct behavior
Because if A has a dependency in imports and needs it and B not or reverse, this strategy is not going to work
Which means you can't build in Deno tools that loads user code
Well you can but with the only limitation that your library doesn't depend on any external library and user pass --config

Which also means that there is no concept of peerDependencies and also you may run in problems like 2 different versions of react being used in same project basically if you are required to have react in both projects

@happyhunter7
Copy link
Author

happyhunter7 commented Sep 18, 2024

The problem I described above gets resolved only by using the deps.ts strategy
But now you have to insure that react version users use should be the exact as your library use
Otherwise a lot of popular libraries throws error when encounters 2 different versions being used
And again when you build a developer tool you can't force user to install a dependency of a version they may not want

And that leads us to the fact that in Deno there is no concept of peerDependencies)

@happyhunter7
Copy link
Author

BTW is there a plan to support recursive dependency resolve? which is kinda what can fix this issue same as Node does?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs info needs further information to be properly triaged question a question about the use of Deno
Projects
None yet
Development

No branches or pull requests

2 participants