![Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility](https://cdn.sanity.io/images/cgdhsj6q/production/97774ea8c88cc8f4bed2766c31994ebc38116948-1664x1366.png?w=400&fit=max&auto=format)
Security News
Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
@open-wc/scoped-elements
Advanced tools
@open-wc/scoped-elements is an npm package that allows developers to use scoped custom elements in their web applications. This means that you can use the same custom element tag name multiple times in different parts of your application without conflicts. It is particularly useful in large applications or when integrating third-party components that might have naming conflicts.
Scoped Custom Elements
This feature allows you to define custom elements that are scoped to a particular component, preventing naming conflicts. In the code sample, `MyButton` is scoped to `MyElement`, allowing the use of `<my-button>` without worrying about conflicts with other components that might use the same tag name.
import { ScopedElementsMixin } from '@open-wc/scoped-elements';
import { LitElement, html } from 'lit';
import { MyButton } from './my-button.js';
class MyElement extends ScopedElementsMixin(LitElement) {
static get scopedElements() {
return {
'my-button': MyButton,
};
}
render() {
return html`<my-button>Click me</my-button>`;
}
}
customElements.define('my-element', MyElement);
LitElement is a base class for creating fast, lightweight web components. While it doesn't provide scoped elements out of the box, it is often used in conjunction with @open-wc/scoped-elements to create scoped custom elements. LitElement focuses on providing a simple and efficient way to create web components with reactive properties and templating.
React is a JavaScript library for building user interfaces. It provides a component-based architecture similar to web components but does not natively support custom elements. However, React's component scoping and encapsulation can achieve similar goals to @open-wc/scoped-elements by avoiding naming conflicts through its component hierarchy.
Vue.js is a progressive JavaScript framework for building user interfaces. Like React, Vue provides a component-based architecture that helps manage component scoping and encapsulation. While it doesn't directly support custom elements, Vue's single-file components and scoped styles can help manage naming conflicts in a similar way to @open-wc/scoped-elements.
Part of Open Web Components
Open Web Components provides a set of defaults, recommendations and tools to help facilitate your web component project. Our recommendations include: developing, linting, testing, building, tooling, demoing, publishing and automating.
:::warning
This is an experimental feature, use it at your own risk and be sure to understand its limitations.
No big applications are using scoped-elements
yet - so there is no proof yet if it works in production.
This page focuses on in depth explanations as it should help foster a discussion on scoping.
:::
Complex Web Component applications are often developed by several teams across organizations. In that scenario it is common that shared component libraries are used by teams to create an homogeneous look and feel or just to avoid creating the same components multiple times, but as those libraries evolve problems between different versions of the same library may appear, as teams may not be able to evolve and update their code at the same velocity. This causes bottlenecks in software delivery that should be managed by the teams and complex build systems, to try and alleviate the problem.
Scoped Custom Element Registries is a proposal that will solve this problem, but until it is ready or a polyfill becomes available, we have to scope custom element tag names if we want to use different versions of those custom elements in our code. This package allows you to forget about how custom elements are defined, registered and scopes their tag names if it is necessary, and avoids the name collision problem.
npm i --save @open-wc/scoped-elements
Consider the following setup
Two possible solutions come to mind:
@open-wc/scoped-elements
; see the "fixed" example with-scope [code] running with nested dependencies.The simplified app has the following dependencies
which leads to the following node_modules tree
├── node_modules
│ ├── feature-a
│ ├── feature-b
│ ├── page-a
│ └── page-b
│ └── node_modules
│ └── feature-a
├── demo-app.js
└── index.html
To demonstrate, we made three demos:
before-nesting [code] In this demo, everything works fine as Page A and B both are using the same version of Feature A
no-scope [code] Feature A version 1.x and 2.x are imported via self registering entry points which leads to the following error message, because the feature-a
component tries to register multiple times:
Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': the name "feature-a" has already been used with this registry
at [...]/node_modules/page-b/node_modules/feature-a/feature-a.js:3:16
with-scope [code] This example successfully fixes the problem by using createScopedHtml
on both Page A and Page B.
createScopedHtml
defines your custom element classes and creates a unique scoped tag for each of them if you need to use multiple versions of an element. In case those classes were already defined, it will return the previously defined tag.
Then, the html
function provided by the createScopedHtml
method transforms the template literal into another one replacing the tags used by the user by the ones defined by the custom elements. Finally, the transformed template literal is going to be processed by lit-html
.
<my-button>${this.text}</my-button>
becomes:
<my-button-3>${this.text}</my-button-3>
Import createScopedHtml
from @open-wc/scoped-elements
.
import { createScopedHtml } from '@open-wc/scoped-elements';
Import the classes of the components you want to use.
import MyButton from './MyButton.js';
import MyPanel from './MyPanel.js';
Create the html
function and define the tags you want to use for your
components.
const html = createScopedHtml({
'my-button': MyButton,
'my-panel': MyPanel,
});
Use your components in your html.
render() {
return html`
<my-panel class="panel">
<my-button>${this.text}</my-button>
</my-panel}>
`;
}
import { css, LitElement } from 'lit-element';
import { createScopedHtml } from '@open-wc/scoped-elements';
import MyButton from './MyButton.js';
import MyPanel from './MyPanel.js';
const html = createScopedHtml({
'my-button': MyButton, // <-- binds the element to a tag in your html
'my-panel': MyPanel,
});
export default class MyElement extends LitElement {
static get styles() {
return css`
.panel {
padding: 10px;
background-color: grey;
}
`;
}
static get properties() {
return {
text: String,
};
}
render() {
return html`
<my-panel class="panel">
<my-button>${this.text}</my-button>
</my-panel}>
`;
}
}
Components imported via npm MUST NOT be self registering components. If a shared component (installed from npm) does not offer an export to the class alone, without the registration side effect, then this component can not be used. E.g. every component that calls customElement.define
.
export class MyEl { ... }
customElement.define('my-el', MyEl);
Or uses the customElement
typescript decorator
@customElement('my-el')
export class MyEl { ... }
Only side effects free class exports may be used
export class MyEl { ... }
Every (!!!) component that uses sub components need to use scoped-elements
. Any import to a self registering component can result in a browser exception - completely breaking the whole application.
Imported elements need to be fully side effect free (not only element registration)
Currently, only lit-html
is supported (though other rendering engines could be incorporated in the future).
You can not use tag selectors in css, but you could use an id, a class name or even a property instead.
🚫 my-panel {
width: 300px;
}
✅ .panel {
width: 300px;
}
You can not use tag names using javascript querySelectors, but you could use an id, a class name or even a property instead.
🚫 this.shadowRoot.querySelector('my-panel');
✅ this.shadowRoot.querySelector('.panel');
Using scoped-elements
may result in a performance degradation of up to 8%.
Loading of duplicate/similar source code (most breaking releases are not a total rewrite) should always be a temporary solution.
Often, temporary solutions tend to become more permanent. Be sure to focus on keeping the lifecycle of nested dependencies short.
We are using Tachometer to measure the performance penalty of using the scoped elements feature. The chosen test application is a slight variation of the Polymer Shop Application.
This is an example of the results obtained running the performance test.
⠋ Auto-sample 150 (timeout in 13m37s)
┌─────────────┬──────────────┐
│ Version │ <none> │
├─────────────┼──────────────┤
│ Browser │ chrome │
│ │ 79.0.3945.88 │
├─────────────┼──────────────┤
│ Sample size │ 200 │
└─────────────┴──────────────┘
┌─────────────────┬────────────┬─────────────────────┬─────────────────┬────────────────────┐
│ Benchmark │ Bytes │ Avg time │ vs lit-element │ vs scoped-elements │
├─────────────────┼────────────┼─────────────────────┼─────────────────┼────────────────────┤
│ lit-element │ 185.99 KiB │ 110.89ms - 117.84ms │ │ faster │
│ │ │ │ - │ 0% - 8% │
│ │ │ │ │ 0.13ms - 9.6ms │
├─────────────────┼────────────┼─────────────────────┼─────────────────┼────────────────────┤
│ scoped-elements │ 190.12 KiB │ 116.02ms - 122.44ms │ slower │ │
│ │ │ │ 0% - 8% │ - │
│ │ │ │ 0.13ms - 9.60ms │ │
└─────────────────┴────────────┴─────────────────────┴─────────────────┴────────────────────┘
This package was initially inspired by carehtml and we would like to thank @bashmish for his work on it.
FAQs
Allows to auto define custom elements scoping them
The npm package @open-wc/scoped-elements receives a total of 100,449 weekly downloads. As such, @open-wc/scoped-elements popularity was classified as popular.
We found that @open-wc/scoped-elements demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Security News
React's CRA deprecation announcement sparked community criticism over framework recommendations, leading to quick updates acknowledging build tools like Vite as valid alternatives.
Security News
Ransomware payment rates hit an all-time low in 2024 as law enforcement crackdowns, stronger defenses, and shifting policies make attacks riskier and less profitable.