'Can I use ES Modules library from CDN?

I want to use this library via CDN.
https://www.jsdelivr.com/package/npm/lit-element

My js code is here.

import { LitElement, html } from "https://cdn.jsdelivr.net/npm/[email protected]/lit-element.js";

class MyElement extends LitElement {
    render(){
        return html`ABCD`
    }
}

customElements.define("my-element", MyElement)

I get following error.

Uncaught TypeError: Failed to resolve module specifier "lit-html". Relative references must start with either "/", "./", or "../".

Do I have to build using npm ?


Update

Following code works.

import { LitElement, html } from "https://unpkg.com/lit-element/lit-element.js?module"

class MyElement extends LitElement {
    render(){
        return html`ABCD`
    }
}

customElements.define("my-element", MyElement)


Solution 1:[1]

Inside LitHtml and LitElement modules use bare module specifiers internally to import dependencies, and these aren't supported by JS modules yet. LitElement has import { TemplateResult } from 'lit-html', but JS needs that 'lit-html' replaced with whatever path to the actual file (not the abstract name of the package).

If you use the npm packages (which cdn.jsdelivr.net is serving up here) you have to use a build step (WebPack, Rollup, etc) to resolve all those import statements to either the file paths JS supports or inline all the files together.

The former is what unpkg.com ... ?module does, it replaces the bare reference to lit-html with the absolute https://unpkg.com/lit-html@^1.1.1/lit-html.js?module.

Solution 2:[2]

The accepted answer is great; the core issue is your CDN file(s) use a "module specifier" that is the "bare" specifier (i.e. not using "/" or "./" or "../") . I fixed my issue with an importmap, mapping my "bare" module specifier, to a full URL/baseURL specifier, i.e.

<script type="importmap">
   { "imports": { 'bare-specificer': 'https://full-url-specifier' } } 
</script>

DETAIL ON CURRENT APPROACH: importmap

I was using jsm three.js modules like ColladaLoader, but I got this error:

Uncaught TypeError: Failed to resolve module specifier "three". Relative references must start with either "/", "./", or "../"

This happens because I import this ColladLoader.js file, which imports many things from 'three' (a "bare module specifier"):

import {
    AmbientLight,
    // ...etc....
    sRGBEncoding
} from 'three';
//--------^ this is the "bare" module specifier problem

For the fix I referenced the collada loader example from three.js, which adds an importmap to its html. I think importmap is still a draft feature but it works well to map a "bare module specifier" to a full URL /baseURL-- just what we need! (more here and here):

<script type="importmap">
    {
        "imports": {
            "three": "../build/three.module.js"
        }
    }
</script>
<script type="module">
        //...
</script>

In my case I am using the three.js file located here: https://cdnjs.cloudflare.com/ajax/libs/three.js/r123/three.module.js

Therefore my importmap looks like this:

<script type="importmap">
    {
        "imports": {
            "three": "https://cdnjs.cloudflare.com/ajax/libs/three.js/r123/three.module.js"
        }
    }
</script>
<script type="module">
        //...
</script>

I expect an importmap can work for you even if you have a "bare" module specifier from somewhere other than three.js; but the importmap approach may only work in certain browsers (i.e. caniuse suggests Edge 89+, Chrome 89+, and Opera 76+ support type="importmap" as of 5/4/2022)

DETAIL ON ALTERNATIVE APPROACH: skypack

THE BELOW ANSWER DEPENDS ON skypack hosting up-to-date modules; i.e. the latest ColladaLoader should use BufferGeometry instead of Geometry which was deprecated with the change in r125, but the latest ColladaLoader was not available on skypack AFAIK

I'm providing this answer to suggest skypack as an alternative to your CDN, which works especially in the context of three.js, (apparently even unpkg might not work; read on)

The solution is discussed in this github issue, which references this migration guide

NPM: ES6 modules in examples/jsm now import using the bare specifier three. This change breaks working with modules in cdns such as https://www.jsdelivr.com/ and https://unpkg.com/. Please use https://www.skypack.dev/ instead.

So in my case I replaced this line:

import { ColladaLoader } from 'https://cdn.jsdelivr.net/gh/mrdoob/three.js/examples/jsm/loaders/ColladaLoader.js';

with this line:

import ColladaLoader from 'https://cdn.skypack.dev/three-collada-loader';

This fixed the error re "Failed to resolve module specifier". But I did face a different issue, but that's three.js specific; i.e. using the deprecated Geometry constructor, because I guess the skypack.dev/three-collada-loader is not the latest code...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Keith
Solution 2