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";
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/"
}
}
example file
import {/* ... */} from "fs/mod.ts";
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";
example file
import {/* ... */} from "./deps.ts";
here comes the problems of using deps.ts
, I have these two imports.
import { Application } from "./deps.ts";
import { Application } from "./deps.ts";
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";
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";
import { oak } from "./deps.ts";
oak.Application;
import { abc } from "./deps.ts";
abc.Application;
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
this creates the following structure.
imports/
|- fs.ts
|- deps.json
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"
the deps.json file is generated for Trex interoperability,
to import it would be as follows.
import {/* ... */} from "./imports/fs.ts";
^^^^^^^^^^^^^^^
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
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 😊
Top comments (5)
How do you think this differs from having a
deps.ts
file and or adev_deps.ts
file?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.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
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)?
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