Closed nalply closed 4 years ago
Relative specifiers are resolved as URLs, so the result you're observing in Chrome matches the spec. To make use of a bare specifier mapping like you have in your map, you need to use bare specifiers in your import statement.
Hope this helps!
Yes, this is what I have done, see "some_pkg/b": "/node_modules/some_pkg/b.js
and import * as b from './b'
in a.js
, however Chrome doesn't load with the extension.
Could you give an universal explanation how bare relative specifiers inside packages are resolved?
You can read the spec for a universal explanation.
Because you are using ./, it will not apply your mappings, because your mappings are bare specifier mappings, but bare specifiers do not start with ./
Thanks for the clarification, I see now my mistake. What I meant is extension-less relative specifiers. Sorry for the confusion.
However I still don't see how to apply an import map to relative extension-less imports inside a package. Is this possible at all?
Closing this because I found another way to map extension-less specifiers: let the webserver redirect to the file with the extension instead.
To remap URLs, you need to specify the full URL, not a bare specifier. E.g.
{
"imports": {
"/node_modules/some_pkg/b": "/node_modules/some_pkg/b.js"
}
}
Thanks for helping me to understand import map better! However after rereading the spec, especially the section https://github.com/WICG/import-maps#extension-less-imports, I feel that handling extension-less specifiers in the import map is not a good idea (combinatorial explosion). My small experimental project already has more than 100 mappings, and I have just begun.
Tarp.require inspired me to let the web server help resolving, because the web server already knows about the files it serves (details: https://github.com/letorbi/tarp.require#http-redirects). It doesn't have to be redirects (in fact I plan to let just deliver the source without any redirects to save round-trip time).
Edit: In fact I think now that a hot dev server should do both: generate an import map (walk through dependencies, read their package.json files and evaluate the "main"
, "files"
and "exports"
fields to get mappings) but also handle some typical cases (like extension-less specifiers) directly.
I would suggest instead just including the file extensions in your import statements. Making your users sit through a server round trip for the 100+ files is going to be a bad experience.
let the webserver redirect to the file with the extension instead.
For future reference: This may not do what most people are expecting. Redirects may lead to two different instances of the "same" module, executing the module multiple times. Because module execution is determined by the URL before redirects happen.
Example:
// target.mjs
console.log('target executed');
// app.mjs
import './target';
import './target.mjs';
If /target
redirects to /target.mjs
, the console statement will be logged twice. If target.mjs
exports symbols / classes / etc. there will be two conflicting versions of those. So generally it's not a great developer experience to redirect and it may lead to subtle bugs.
As @domenic wrote above, the most reliable option is to add extensions to imports.
Thanks for the head-ups. This seems a lot more complicated than I thought.
Edit: s/bare/extension-less/
First let me give a detailed example:
some_pkg
a.js
andb.js
in the packagea.js
has as first lineimport * as b from './b'
in the source (note the relative extension-less specifier)node_modules
in the web rootThe web server delivers
b.js
for the URL http://example.com/node_modules/some_pkg/b.js.Should
a.js
be able to importb.js
with this setup? Or did I miss something?Sorry if this is a noob question, however for a project of mine with an import map, the application is trying to load http://example.com/node_modules/some_pkg/b (on macOS Google Chrome Canary version 81.0.4020.0 with experimental flag enabled).