Provide an actionable error when import map is missing (CDN usage)
- Dominant language
- JavaScript
- Stars
- 30
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Description
## Problem
After the switch to Nudeps (#218), importing components directly from the Netlify CDN (`elements.colorjs.io`) without an import map produces a cryptic browser error:
> Uncaught TypeError: The specifier "colorjs.io" was a bare specifier, but was not remapped to anything. Relative module specifiers must start with "./", "../" or "/".
This was reported in #225 and affected `apps.colorjs.io` (see [color-js/apps#28](https://github.com/color-js/apps/issues/28), fixed in [color-js/apps#29](https://github.com/color-js/apps/pull/29)).
While the immediate breakage was fixed by adding the import map in the apps repo, any user loading components from `elements.colorjs.io` without the import map will hit the same cryptic error:
```html
```
They need to include the import map first:
```html
```
## Root cause
The base class (`src/common/color-element.js`) uses bare specifier imports:
```js
import Color from "colorjs.io";
import NudeElement from "nude-element";
import { states } from "nude-element/plugins";
```
Static imports are resolved during the ES module "link" phase — **before any module body code runs**. This means we cannot wrap them in `try…catch` or run `import.meta.resolve()` first. By the time any of our code could execute, the module has already failed.
## Workarounds (available today)
Users can avoid the issue entirely by not importing from the Netlify CDN:
- **Use esm.sh** (or another CDN that resolves specifiers server-side) — already documented in the README:
```html
```
- **Use Nudeps** — manages import maps and bare specifiers without a bundler
- **Use a bundler** (webpack, Vite, Rollup, etc.) — resolves bare specifiers at build time
These don't solve the detection problem, but they're the recommended paths for users who don't want to manage import maps manually.
## Possible solutions (detection)
### 1. Documentation only
Add a note to the README about needing the import map when loading from `elements.colorjs.io`.
- **Pro**: No code changes, no degradation
- **Con**: Easy to miss; doesn't help users who hit the error
### 2. Convert bare specifier imports to dynamic imports with detection
Replace static imports with `import.meta.resolve()` check + `await import()`:
```js
for (const specifier of ["colorjs.io", "nude-element", "nude-element/plugins"]) {
try {
import.meta.resolve(specifier);
}
catch {
throw new Error(
`color-elements: Cannot resolve "${specifier}". `
+ `Include the import map first: `
+ `<\/script>`,
);
}
}
const { default: Color } = await import("colorjs.io");
const { default: NudeElement } = await import("nude-element");
const { states } = await import("nude-element/plugins");
```
This could live directly in `color-element.js` or be isolated in a separate `deps.js` module.
- **Pro**: Users get an actionable error message at runtime
- **Pro**: `import.meta.resolve()` is synchronous — no network overhead for the check
- **Con**: Degrades the codebase — static imports become dynamic
- **Con**: Requires top-level `await` (supported in all modern browsers, but changes module semantics)
- **Con**: Worse static analysis for bundlers (though practical impact is negligible since these deps are used in full)
### 3. Separate optional check script
A standalone module that users can load before component scripts. Checks `import.meta.resolve()` and warns.
- **Pro**: Core code stays untouched
- **Con**: Users who forget the import map are unlikely to include this either
## Notes
- `import.meta.resolve()` is supported in Chrome 105+, Firefox 106+, Safari 16.4+ — aligns with the project's modern browser target
- The recommended CDN usage via `esm.sh` (in the README) resolves specifiers server-side and is unaffected
- Both `colorjs.io` and `nude-element` are bare specifiers that need handling, not just `nude-element`
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.