Lädt...


🔧 Deprecating Your Web Component APIs


Nachrichtenbereich: 🔧 Programmierung
🔗 Quelle: dev.to

Deprecating your web component APIs is a great way to communicate to your users that a feature will be removed in the next major release of your package. If you are using a Custom Elements Manifest for documenting your component APIs, this may be trickier than it seems. Web components typically have more public APIs than framework components:

  • CSS variables
  • CSS parts
  • slots
  • events
  • methods
  • attributes
  • properties.

In this article, I will demonstrate how to document your API deprecations and add replacement features without introducing breaking changes.

Documentation

One of the trickiest parts of the deprecation process is the documentation. For properties, methods, and even your component, this can be as simple as adding a @deprecated tag to your JSDoc comment in the component's class.

/**
  * @deprecated This component is going away. Use ... instead.
  */
class MyElement extends HTMLElement {
  /** @deprecated This property is being removed. Use ... instead. */
  myProp;

  /** @deprecated This method is going away. Use ... instead. */
  myMethod() {
  }
}

The CSS variables, CSS parts, slots, events, and attributes are typically documented in the class's JSDoc.

Here's an example of what you can document in a custom elements JSDoc:

/**
 * @attr {boolean} disabled - disables the element
 * @attribute {string} foo - description for foo
 *
 * @csspart bar - Styles the bar element in the shadow DOM
 *
 * @slot - This is a default/unnamed slot
 * @slot container - You can put some elements here
 *
 * @cssprop --text-color - Controls the color of foo
 * @cssproperty [--background-color=red] - Controls the background color of bar
 *
 * @prop {boolean} prop1 - some description
 * @property {number} prop2 - some description
 *
 * @fires custom-event - some description for custom-event
 * @fires {MyType} typed-event - some description for typed-event
 * @event {MyType} typed-custom-event - some description for typed-custom-event
 *
 * @summary This is MyElement
 *
 * @tag my-element
 * @tagname my-element
 */
class MyElement extends HTMLElement {}

The Problem

The challenge is that you can't double up on JSDoc tags and use the @deprecated tag to indicate that these items are deprecated. Otherwise, it will be interpreted as the entire class is deprecated.

/**
 * @cssprop --text-color - @deprecated I dub thee "deprecated" ❌
 */
class MyElement extends HTMLElement {}

A Solution

To get around this, I created a tool (custom-elements-manifest-deprecator) that allows you to tag items in your JSDoc so they are appropriately updated in the Custom Elements Manifest.

Using this tool you can use alternative tags to identify deprecated APIs. By default, it uses a parenthesis-wrapped @deprecated tag as the identifier (which is what we'll use today), but it can be customized to whatever you would like.

/**
 * @cssprop --text-color - (@deprecated) I dub thee "deprecated" 👍
 */
class MyElement extends HTMLElement {}

Updating Your APIs

An important thing for our team is that when we will be removing or changing an API, we try to introduce the new feature before the next major release so teams can migrate to it early. That way, if they are staying up-to-date, they can minimize the impact of upgrading to a new version.

In this next section, we will go through how to introduce new features without breaking your old APIs and how they can co-exist without competing with each other. We will be updating some APIs for a simple button component.

In this example I will be using Lit, but these features and principles can be applied to any environment.

CSS Variables

To provide better autocomplete and descriptions in our editors like VS Code and JetBrains, we need to provide component-specific CSS variable names.

/* old variables */
--bg-color: #ccc;
--fg-color: black;

/* new variables */
--button-bg-color: #ccc;
--button-fg-color: black;

The tricky part is that teams are already using the old variables, so we need them both to work. We can do this by mapping the deprecated variables to new ones and updating our button code to only use the variables. That way, if the users are styling with the deprecated variables, they will be applied to the new variables, or users can apply values to the new variables directly.

--bg-color: #ccc;
--fg-color: black;
--button-bg-color: var(--bg-color);
--button-fg-color: var(--fg-color);

button {
  background-color: var(--button-bg-color);
  border: solid 1px var(--button-fg-color);
  color: var(--button-fg-color);
}

Now we can update our JSDoc information with the new CSS variables and add (@deprecated) to the old ones with updated descriptions.

/**
 * An example button element.
 *
 * @tag my-button
 * 
 * @cssprop [--bg-color=#ccc] - (@deprecated) (use `--button-bg-color` instead) controls the background color of the button
 * @cssprop [--fg-color=black] - (@deprecated) (use `--button-fg-color` instead) controls the foreground/text color of the button
 * @cssprop [--button-bg-color=#ccc] - controls the background color of the button
 * @cssprop [--button-fg-color=black] - controls the foreground/text color of the button
 *
 */

CSS Parts

Like our CSS variables, we want to provide namespaced names for our parts for better tooling support, so we will be replacing control with button-control. CSS parts are pretty easy since we can apply multiple parts to an element like CSS classes, so let's apply the new part name to the element alongside the other.

<button part="control button-control">
  <slot></slot>
</button>

Now we can update our JSDoc with the new part, deprecate the old part with (@deprecated), and update the description.

/**
 * An example button element.
 *
 * @tag my-button
 *
 * @csspart control - (@deprecated) (use `button-control` instead) provides a hook to style internal button element
 * @csspart button-control - provides a hook to style internal button element
 */

Slots

With the new initiatives for our components to support internationalization (i18n), we are updating some of our APIs to be more meaningful in RTL (right-to-left) languages. One thing we want to do is update our slot that is intended to display an icon before the button text from left to start without breaking the experience for projects that are already using the left slot.

We can do this by nesting the deprecated slot within the new slot. If the new slot is not being used, it will "fall back" to the old slot.

<button part="control">
  <slot name="start">
    <slot name="left"></slot>
  </slot>
  <slot></slot>
</button>

Now we can update our JSDoc with the new slot, deprecate the old slot with (@deprecated), and update the description.

/**
 * An example button element.
 *
 * @tag my-button
 * 
 * @slot the default slot adds main content to the button
 * @slot left - (@deprecated) (use the `start` slot instead) adds content before the main button content
 * @slot start - adds content before the main button content
 */

Events

For our example, we are emitting a custom focus event, but it's getting confusing for teams, so we want to add a namespaced event (my-focus). events are pretty straightforward since you can emit both events and developers can move to the new one when they get a chance.

private handleFocus() {
  this.dispatchEvent(new CustomEvent("focus", { bubbles: true }));
  this.dispatchEvent(new CustomEvent("my-focus", { bubbles: true }));
}

Now we can update our JSDoc with the new event, deprecate the old event with (@deprecated), and update the description.

/**
 * An example button element.
 *
 * @tag my-button
 * 
 * @event focus - (@deprecated) emitted when control is focused
 * @event my-focus - emitted when control is focused
 */

NOTE: Most tools accept @event and @fires for documenting events. There isn't really a difference between them.

Methods

Methods are pretty easy to add in parallel to each other and you can use the standard @deprecated tag in the method description to communicate that it's deprecated.

/** @deprecated use `newMethod` instead */
public oldMethod() {
 ...
}

/** description about this method */
public newMethod() {
  ...
}

Properties and Attributes

Properties and attributes can be documented in the class's JSDoc using the @attr/@attribute and @prop/@property tags. If you are using them, you can use the (@deprecated) tag to deprecate them in the Custom Elements Manifest, however, it's usually better to document the property directly using its own JSDoc comment. This will enable things like types and other tooling to properly identify deprecated APIs.

The nice thing is that most analyzers are pretty good about associating attributes with properties that are being defined in the component class with decorators or other configurations, so if you deprecate the property, the associated attribute will also be deprecated.

In our demo component, we have a disable attribute that we want to update to disabled to be more in line with native HTML elements.

The first thing we want to do is deprecate the old property and add our new one.

/** @deprecated Disables the button. */
@property({ type: Boolean })
disable = false;

/** Disables the button. */
@property({ type: Boolean })
disabled = false;

Now, we want to avoid having to check both properties every time we need to determine if the component is disabled. To simplify this, we can convert the deprecated property to a getter/setter and use the new property to be the source of truth.

/** @deprecated Disables the button. */
@property({ type: Boolean })
get disable(): boolean {
  return this.disabled;
}

set disable(value: boolean) {
  this.disabled = value;
}

/** Disables the button. */
@property({ type: Boolean })
disabled = false;

Now, whenever the old value is updated, it will automatically update the new value, so we only need to check the new property to determine if the component is disabled.

<button ?disabled=${this.disabled}>...</button>

Check out the completed example!

Open in StackBlitz

Conclusion

Changing APIs can introduce complications, but it doesn't mean you need to stop producing new features because it may involve breaking changes. Introducing new features early and deprecating old ones can be a way to provide a good developer experience (DX). This provides a path of progressive enhancement rather than forcing teams to wait and make massive changes all at once to take advantage of new features.

...

🔧 Deprecating Your Web Component APIs


📈 45.16 Punkte
🔧 Programmierung

🔧 Are Web APIs the same as REST APIs? How Web APIs Improve the Web.


📈 36.27 Punkte
🔧 Programmierung

🔧 What are Web APIs? [1 of 18] | Beginner's Series to: Web APIs | Beginner's Series to: Web APIs


📈 36.27 Punkte
🔧 Programmierung

🔧 Deprecating Node JS REST APIs in 6 Frameworks


📈 30.18 Punkte
🔧 Programmierung

🔧 Deprecating REST APIs: A Developer's Guide


📈 30.18 Punkte
🔧 Programmierung

🔧 Deprecating and removing Web SQL


📈 24.68 Punkte
🔧 Programmierung

🔧 Deprecating Angular App Inbox towards web-inbox


📈 24.68 Punkte
🔧 Programmierung

🔧 Deprecating Angular App Inbox towards web-inbox


📈 24.68 Punkte
🔧 Programmierung

🐧 What I think OpenSSH 8.2+'s work toward deprecating 'ssh-rsa' means


📈 21.39 Punkte
🐧 Linux Tipps

🪟 Microsoft should’ve integrated Paint 3D to Paint instead of deprecating it


📈 21.39 Punkte
🪟 Windows Tipps

🐧 Deprecating support for the Linux kernel


📈 21.39 Punkte
🐧 Linux Tipps

🕵️ Apple deprecating macOS kernel extensions (KEXTs) is a great win for security


📈 21.39 Punkte
🕵️ Hacking

📰 Google Won't Be Deprecating Third-Party Cookies In Chrome After All


📈 21.39 Punkte
📰 IT Security Nachrichten

📰 Deprecating TLS 1.0 and 1.1 support in Power BI


📈 21.39 Punkte
📰 IT Nachrichten

🐧 [$] The path to deprecating SPARSEMEM


📈 21.39 Punkte
🐧 Linux Tipps

📰 Deprecating Basic Authentication for Outlook Integration in Business Central


📈 21.39 Punkte
📰 IT Nachrichten

🪟 Microsoft is Suddenly Deprecating a Lot of Windows Features


📈 21.39 Punkte
🪟 Windows Tipps

📰 Chrome UI for Deprecating Legacy TLS Versions


📈 21.39 Punkte
📰 IT Security Nachrichten

🪟 Microsoft deprecating three useful features in Windows 11 this month. What are those?


📈 21.39 Punkte
🪟 Windows Tipps

🔧 Chrome UI for Deprecating Legacy TLS Versions


📈 21.39 Punkte
🔧 Programmierung

🐧 Deprecating and removing SLOB ... FYI


📈 21.39 Punkte
🐧 Linux Tipps

🐧 Deprecating a.out Binaries


📈 21.39 Punkte
🐧 Linux Tipps

🐧 Fedora not deprecating legacy BIOS - yet


📈 21.39 Punkte
🐧 Linux Tipps

📰 Microsoft partners with DigiCert to begin deprecating Symantec TLS certificates


📈 21.39 Punkte
📰 IT Security Nachrichten

🐧 Fedora not deprecating legacy BIOS - yet


📈 21.39 Punkte
🐧 Linux Tipps

🐧 [$] Fedora considers deprecating legacy BIOS


📈 21.39 Punkte
🐧 Linux Tipps

🐧 [/r/apple] Apple users justify and celebrate deprecating OpenGL for Metal API


📈 21.39 Punkte
🐧 Linux Tipps

🐧 What are the implications of deprecating the k10temp?


📈 21.39 Punkte
🐧 Linux Tipps

🕵️ Deprecating TLS 1.0 and TLS 1.1 … kill them now!


📈 21.39 Punkte
🕵️ Hacking

🐧 Deprecating scp


📈 21.39 Punkte
🐧 Linux Tipps

📰 Social Security Administration Adopts What NIST is Deprecating


📈 21.39 Punkte
📰 IT Security Nachrichten

🐧 [$] Deprecating scp


📈 21.39 Punkte
🐧 Linux Tipps

📰 Microsoft Deprecating 'Obsolete' SmartScreen Spam Filters In Outlook and Exchange


📈 21.39 Punkte
📰 IT Security

📰 Google Sets Timeline For Deprecating 'Classic' Google Sites


📈 21.39 Punkte
📰 IT Security Nachrichten

matomo