Closed NfNitLoop closed 2 weeks ago
Yeah, there needs to be a solution for this problem.
There is some preliminary work on this here: https://github.com/denoland/deno_config/pull/100
Hoping to get it into Deno 1.46 next week (probably as considered unstable)
We didn't talk about this feature in the 1.46 blog post, but would someone be able to try it out and give some feedback? You just need to add a relative path under the "patch"
key like the following to your deno.json and it should use the local path instead (available in Deno 1.46--deno upgrade
):
{
"patch": [
"../some-package-or-workspace"
]
}
It should work even if you specify a workspace. There's a tracking issue for this feature here: https://github.com/denoland/deno/issues/25110
Feature Request
Deno needs a way to (temporarily?) depend on another local project that uses an import map.
Context
Deno docs have an example of overriding a dependency with a local one for local development:
But I'm pretty sure that only works for dependencies that inline their dependencies in source files (or use the deps.ts pattern).
Let's put aside the
"scopes"
/ override aspect of the above example for now. I don't care about overriding dependencies upstream, or limiting those overrides to a specific scope. I'm mostly concerned with supporting any way to (temporarily or not) depend on another local project that uses import maps.For example, if I have a
bar/main.ts
:with a deno.json including:
deno
is unable to resolve the transitive dependencies. (i.e.: those defined in../foo/deno.json
.)If this worked, it would be an easy way for users to download a dependency and update their code to depend on it locally for testing/development.
The fact that it currently doesn't is one of the reasons I'm still avoiding import maps in my projects and would recommend others do the same.
Insufficient Workaround
The problem is that deno isn't taking into account the local dependency's deno.json , or other locations where an import map might be specified. In the example above, I could "make it work" by re-declaring all of
foo
's import map inside my own, so that imports are correctly resolved.But as projects grow, and dependency trees get larger, and deeper, that's not a workable solution. Especially if I only want to do that temporarily to do integration testing between a dependency and my library before pushing my changes up into a PR.
Workspaces
There's also the in-development workspace feature, which can handle some use cases for this. But what I've seen of it so far seems to be targeted more to developing a set of interdependent libraries like those in
@std/
. There are a couple problems I think that that work won't solve:From what I've seen, in a workspace all dependencies are pushed to the top level directory of the workspace, so if I wanted to temporarily bring a third-party module into my workspace, I'd still have to manually inline its dependencies into my workspace, if I'm using one, or completely modify my project structure to work as a workspace to be able to patch in a third-party dependency.
If the dependency I want to patch is itself contained in a workspace, we're back to the same issue.
If there were just a general-purpose solution for transitively resolving dependencies in this case, it might be simpler than trying to work around the issue w/ workspaces.
Example from Node
The
npm
command hasnpm link
to temporarily (sym)link a local dependency into your dependency graph for testing. It does work, but sometimes has unexpected behavior.There are more complicated cases where you might want something like this in Deno (ex: where a dependency
foo
is used not just by your own project, but as a common dependency among many of your dependencies, and you need to override it in all cases.)But it feels like the simpler case of "I need to fix this dependency I'm using" is probably more common, and an easier fix to start with.
Brainstorming Implementation
I see one problem that might be why transitively resolving dependencies via import maps might not be supported -- the same reason that HTTP imports don't automatically use import maps -- there's no standard for where the import map should be found.
JSR.io solves this by having a standard location. Given
jsr:@namespace/package/path
, tools can know where to find the import map & dependencies for that package.To do something similar locally, there might need to be an import prefix/syntax that conveys:
path
, above)deno publish
does.Something like:
jsr-local:../foo::path
jsr-local:
is # 3.../foo
specifies # 1.path
is optionally # 2, the exported module path within the package. There will need to be some separator to distinguish it from a continuation of # 1. (I'm using::
here but not stuck on that.)Alternatively, if
jsr:
always expects to be followed by@
for a namespace, a following.
could be taken to mean we're using jsr-style resolution locally, then the above could be written as:jsr:../foo@local/path
This (ab|re)uses the
@version
specifier from jsr.io with a version of@local
to act as a separator between # 1 and # 2.