material-components / material-components/material-web

Use bare specifier import for dependent components

Open
#5,107 2 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
SCSS
Stars
11.3k
Forks
1.1k
Avg merge
20h 28m
Merged PRs (30d)
13

Description

What is affected?

Tooling

Description

As reported by a user on discord https://discord.com/channels/1012791295170859069/1076197552904491108/1165169545816846346

when components are loaded from CDNs like esm.run or esm.sh, they end up being bundled such that using multiple components can cause duplicate custom element registration errors.

CDN bundlers currently have no knowledge of all the entrypoints to the package to be able to deduplicate internal self imports. Using bare specifiers and package exports would help with this.

Reproduction

https://lit.dev/playground/#gist=73234f9745308e38a224d3eb92ca71ab

doing

import "https://esm.sh/@material/web/button/elevated-button.js";
import "https://esm.sh/@material/web/switch/switch.js";

produces error

Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "md-focus-ring" has already been used with this registry
Workaround

Workaround is to use the all.js entrypoint to register everything at once, or don't use a CDN and use a build system to actually bundle the code being used yourself.

Using bare specifier imports internally would allow better deduplication control by these bundlers.
e.g.
https://github.com/material-components/material-web/blob/33e4293eca4f7056ed106f7247f12424dbc82290/button/internal/button.ts#L7-L8

could turn into

import '@material/web/focus/md-focus-ring.js';
import '@material/web/ripple/ripple.js';

Unfortunately, I think package exports is required for self reference in Node https://nodejs.org/api/packages.html#self-referencing-a-package-using-its-name.
So following should be added to package.json

{
  "exports": {
    "./button/*.js": "./button/*.js",
    "./checkbox/*.js": "./checkbox/*.js",
    ... etc
  }
}

This can be considered breaking unless absolutely every file that was accessible before, including internal files, is listed there.

Is this a regression?

No or unsure. This never worked, or I haven't tried before.

Affected versions

1.0.1

Browser/OS/Node environment

n/a

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with internal imports such as button/internal/button.ts and inspect package.json exports. Reproduce the duplicate md-focus-ring registration using the linked Lit playground, then assess replacing internal imports with bare package specifiers and exposing the required entrypoints without unintentionally hiding previously accessible files. Confirm the CDN imports no longer register the same custom element twice.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
build-system, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.