DEV Community

Erick Sosa Garcia
Erick Sosa Garcia

Posted on

Rethinking the way we handle dependency imports in deno

I've been using deno for a while and I must say I love it, using typescript without compiling it first, using import / export instead of require and the other facilities that deno allows, I love it.

One of the main premises is the non-use of a package manager, since as in a browser you can import locally or from a url, this is a total paradigm shift with respect to nodejs, This has its advantages, since packages and dependencies can be imported literally from anywhere, which fulfills the role of decentralizing the location of the dependencies, now here I want to share some of the disadvantages that the use of urls entails.

using packages in deno is very simple, just import the library or package.


import {/* ... */} from "https://deno.land/std@0.65.0/fs/mod.ts";

Enter fullscreen mode Exit fullscreen mode

So far so good, but let's say that now we have 50 files that import from the fs package, here it becomes a bit complicated since if we want to update to another version of the package we would have to go to each of the 50 files to change the url. a solution for this that deno offers is to use import maps, which is a way of giving name aliases to urls in order to shorten and reuse the package.

then it would look like this.

import_map.json

{
  "imports": {
    "fs/": "https://deno.land/std@0.65.0/fs/"
  }
}
Enter fullscreen mode Exit fullscreen mode

example file


import {/* ... */} from "fs/mod.ts";

Enter fullscreen mode Exit fullscreen mode

much better now, we can use the packages in all the files we want and we just have to update them in one place in the import_map.json. actually create a command line tool for deno that wraps all this functionality and creates an experience similar to npm when searching and installing packages (Trex).

But with import maps there are some disadvantages, they cannot be used in packages that are distributed, and also they are still under the unstable flag since as it is not yet a web standard there is much doubt if it deno will continue to support import maps.

Another solution that they recommend and I think is the most used is to use a single deps.ts file where all the imports are and from this import everything.

then it would be something like this.

deps.ts

export * from "https://deno.land/std@0.65.0/fs/mod.ts";
Enter fullscreen mode Exit fullscreen mode

example file


import {/* ... */} from "./deps.ts";

Enter fullscreen mode Exit fullscreen mode

here comes the problems of using deps.ts, I have these two imports.


import { Application } from "./deps.ts";

Enter fullscreen mode Exit fullscreen mode

import { Application } from "./deps.ts";

Enter fullscreen mode Exit fullscreen mode

they look exactly the same, let's look at the deps.ts file

export * from "https://deno.land/x/abc@v1.0.3/mod.ts";

export * from "https://deno.land/x/oak@v6.0.1/mod.ts";
Enter fullscreen mode Exit fullscreen mode

oak and abc have some methods and functions with the same names,
this can be fixed as follows.

export * as abc from "https://deno.land/x/abc@v1.0.3/mod.ts";

export * as oak from "https://deno.land/x/oak@v6.0.1/mod.ts";
Enter fullscreen mode Exit fullscreen mode

import { oak } from "./deps.ts";

oak.Application;
Enter fullscreen mode Exit fullscreen mode

import { abc } from "./deps.ts";

abc.Application;
Enter fullscreen mode Exit fullscreen mode

but with this we lose explicitness, since everything is imported from a single deps.ts file, reading and having a clear idea of ​​what is being imported and what package it is becomes more confusing.

A solution

As the future of using import maps is not clear within deno and that it has some shortcomings, we created a version of Trex which does not use import maps as the central axis. This version focuses on being as explicit and readable as possible when importing.

It works in the following way.

install a package

trex install --map fs@0.65.0
Enter fullscreen mode Exit fullscreen mode

this creates the following structure.

imports/
 |- fs.ts
 |- deps.json
Enter fullscreen mode Exit fullscreen mode

where for each installed package a file with the same name is created that exports the complete package.

fs.ts

export * from "https://deno.land/std@0.65.0/fs/mod.ts"
Enter fullscreen mode Exit fullscreen mode

the deps.json file is generated for Trex interoperability,
to import it would be as follows.


import {/* ... */} from "./imports/fs.ts";
                          ^^^^^^^^^^^^^^^
Enter fullscreen mode Exit fullscreen mode

This makes it more explicit from where we are importing and helps when reading the code, of course it adds a file for each package but if you don't want to upload this to the repository you just have to add this to the .gitignore

imports/*.ts
Enter fullscreen mode Exit fullscreen mode

you only have to preserve the deps.json file and when the project is downloaded do a trex install and this will download and generate the files again.

The advantage of using imports in this way is that it is more explicit, easier to read and can be used by libraries instead of using import maps or deps.ts. For now this version is not available yet, but we already have all the functionalities adapted to this system and we hope to launch it soon.

If you have any opinion or comment I will gladly listen 😊

Discussion (5)

Collapse
robdwaller profile image
Rob Waller

How do you think this differs from having a deps.ts file and or a dev_deps.ts file?

Collapse
patarapolw profile image
Pacharapol Withayasakpunt • Edited on

Why not deps_dev.ts? VSCode is better at sorting files alphabetically.

Also, deps.ts would support dynamic imports, as well as other TypeScript/JavaScript features.

Collapse
buttercubz profile image
Erick Sosa Garcia Author

in the way in which imports are imported and imports are read, since that way it is more explicit, but in practice they are the same

Collapse
craigphickspublic profile image
craigphicks-public

This means you have to explicitly download the files instead of relying only on Deno caching. Does it mean you know have two local copies - one for Trex and one in the Deno cache (which reads from the Trex one)?

Collapse
buttercubz profile image
Erick Sosa Garcia Author

currently I no longer use this approach but instead bet on import maps since it is definitively in deno. on the other hand answering your question, it will always be read from the deno cache since the files that were generated in that version were a separation of each url in separate files an example where I used this approach was this project snel