bug: setTagTransformer transforms every tag rendered by h(), including native HTML tags

オープン
#7,016 コメント 0 件 リアクション 1 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
45/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
javascript, typescript, web-dev
領域
frontend, web-dev

調査の方向性

Start in the runtime's h() function, where transformTag is applied to every string node name, and compare it with how cmpMeta.$tagName$ identifies component tags. Also read setTagTransformer and its JSDoc example. Done means either the transformer no longer receives native HTML tags such as div, span and slot, or the docs state clearly that it receives every rendered tag. The maintainers still need to choose between these options, so confirm that before writing code.

索引モデルが issue の本文から書いたものです。

説明

Stencil Version

4.45.2

Current Behavior

When a transformer is registered via setTagTransformer(fn), the runtime applies fn to every string tag rendered through h() — not only component tags. Native HTML tags used inside a component's shadow DOM (div, span, label, slot, input, …) are renamed as well.

With a natural consumer callback like (tag) => \${tag}-sample`, the entire internal structure of every component becomes unknown elements (, ): slotted content no longer projects, ` stops being an input, and components render broken with no error or warning.

The mechanism sits in the runtime's h():

var h = (nodeName, vnodeData, ...children) => {
  if (typeof nodeName === "string") {
    nodeName = transformTag(nodeName);   // every string tag
  }
  ...
}

The docs/JSDoc example only accidentally protects users:

setTagTransformer((tag) => {
  if (tag.startsWith('my-')) return `new-${tag}`;
  return tag;
});

It never states that the callback receives every rendered tag, including native HTML.

Minimal reproduction

Self-contained page (importmap + a built dist-custom-elements component), verified against 4.45.2:

<script type="importmap">
  {"imports": {"@stencil/core/internal/client": "./vendor/stencil-core/internal/client/index.js"}}
</script>
<script type="module">
  import { setTagTransformer, transformTag } from '@stencil/core/internal/client';
  import { defineCustomElement } from './components/kol-button.js';

  setTagTransformer((tag) => `${tag}-sample`);
  defineCustomElement();

  const host = document.createElement(transformTag('kol-button'));
  host.setAttribute('_label', 'Label');
  document.body.append(host);
</script>

Observed shadow DOM (host correctly upgrades as kol-button-sample, internals do not):

<div-sample class="kol-button kol-button--standalone kol-button--normal">
  <button-sample class="kol-button__interactive-element" type="button">
    <span-sample class="kol-span kol-button__text">
      <span-sample class="kol-span__label">Label</span-sample>
      <slot-sample name="expert" slot="expert"></slot-sample>
Expected Behavior

The runtime already knows which tags are component tags (cmpMeta.$tagName$). The transformer should receive only tags it can meaningfully rename — ideally component tags by default — or the docs/JSDoc must state explicitly that the callback receives every rendered tag including native HTML, and that the callback therefore has to be selective. Currently a one-line consumer callback silently destroys every component's internal structure.

System Info

macOS 15 (arm64) and Linux (CI, Firefox), Stencil 4.45.2, Node 24. Reproduced with dist-custom-elements output and with the lazy loader.

Additional context

We hit this while migrating a component library's tag-rename feature from a tag-constant mutation approach to the native API. Our visual regression suite (which renders the whole sample app with the transformer enabled) caught it; a naive one-line callback destroyed the internal structure of every component while unit tests stayed green, because the components themselves hydrate fine — only the shadow structure is renamed.

主要言語
TypeScript
スター
13.2k
フォーク
865
平均マージ
2日 16時間
マージ済み PR(30日)
29

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

stenciljs/core のほかの issue

stenciljs/core の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。