Skip to content

fix(runtime): skip native attribute watchers until the lazy instance exists - #6946

Open
addahlbe wants to merge 1 commit into
stenciljs:mainfrom
addahlbe:fix/watch-native-attr-before-instance
Open

addahlbe wants to merge 1 commit into
stenciljs:mainfrom
addahlbe:fix/watch-native-attr-before-instance

Conversation

@addahlbe

Copy link
Copy Markdown

What is the current behavior?

With the lazy loader, a component that uses @Watch on a native (non-@Prop) attribute throws from attributeChangedCallback when that attribute changes after the element connects but before the component's module has loaded:

TypeError: Cannot read properties of undefined (reading 'ariaLabelChanged')

The propName == null branch only checks hostRef.$flags$, which already includes hasConnected at that point, while hostRef.$lazyInstance$ is still undefined.

GitHub Issue Number: #6945

What is the new behavior?

The watcher lookup is null-safe (instance?.[watchMethodName]), so a change that arrives before the instance exists is ignored. That matches @Prop changes, which don't fire watchers before the component is ready either. Changes after the instance exists still reach the watcher.

Documentation

N/A

Does this introduce a breaking change?

  • Yes
  • No

Testing

  • Added a newSpecPage test in src/runtime/test/watch.spec.tsx. It connects a component with @Watch('aria-label'), sets aria-label before the module is flushed, and expects no error. After waitForChanges() it sets the attribute again and expects the watcher to receive it.
  • Without the fix the test fails with TypeError: Cannot read properties of undefined (reading 'ariaLabelChanged'). With the fix it passes.
  • jest src/runtime: 65 suites, 684 tests pass. eslint and prettier --list-different are clean on both files.
  • Manually checked in Chrome with a minimal www build of the component from bug: changing a watched native attribute before a lazy component's instance exists throws #6945. On 4.45.2 the page logs the uncaught TypeError. Built against this branch, there is no error, and a later setAttribute logs ariaLabelChanged after load.

Other information

We hit this in production through Ionic, where ion-button watches aria-label, aria-pressed and aria-checked and an Angular [attr.aria-label] binding can update the attribute before the button's chunk loads.

🤖 Generated with Claude Code

…exists

Changing a watched non-prop attribute (e.g. `aria-label`) after a lazy
component connected but before its module loaded threw, because
`hostRef.$lazyInstance$` was still undefined. The change is now ignored,
the same as a prop change before the instance exists.

fixes: stenciljs#6945

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants