When coupled with Deno friendly import maps can be a powerful tool in managing code and dependencies without need of a package management tool.
Deno will only load a fully qualified module, including the extension. The
import specifier needs to either be relative or absolute. Specifiers that are
neither relative or absolute are often called “bare” specifiers. For example
is a relative specifier and
https://cdn.skypack.dev/lodash
is an absolute specifier. Where is "lodash"
would be a bare specifier.
Also Deno requires that for local modules, the module to load is fully
resolve-able. When an extension is not present, Deno would have to “guess” what
the author intended to be loaded. For example does "./lodash"
mean
./lodash.js
, , ./lodash.tsx
, ./lodash.jsx
,
./lodash/index.js
, ./lodash/index.ts
, , or
./lodash/index.tsx
?
Node.js does have defined semantics for resolving specifiers, but they are complex, assume unfettered access to the local file system to query it. Deno has chosen not to go down that path.
But, import maps can be used to provide some of the ease of the developer experience if you wish to use bare specifiers. For example, if we want to do the following in our code:
We can accomplish this using an import map, and we don’t even have to install
the lodash
package locally. We would want to create a JSON file (for example
import_map.json) with the following:
If you wanted to manage the versions in the import map, you could do this as well. For example if you were using Skypack CDN, you can used a pinned URL for the dependency in your import map. For example, to pin to lodash version 4.17.21 (and minified production ready version), you would do this:
Overriding imports
The other situation where import maps can be very useful is the situation where you have tried your best to make something work, but have failed. For example you are using an npm package which has a dependency on some code that just doesn’t work under Deno, and you want to substitute another module that “polyfills” the incompatible APIs.
For example, let’s say we have a package that is using a version of the built in
"fs"
module that we have a local module we want to replace it with when it
tries to import it, but we want other code we are loading to use the standard
library replacement module for "fs"
. We would want to create an import map
that looked something like this: