From 680d34b490d6fb2673e49fd5b00c53bc4d431876 Mon Sep 17 00:00:00 2001 From: Tanner Reits Date: Tue, 25 Jun 2024 12:39:22 -0400 Subject: [PATCH 1/2] fix(runtime): allow watchers to fire w/ no Stencil members Fixes #5854 STENCIL-1338 --- src/compiler/app-core/app-data.ts | 2 +- src/runtime/proxy-component.ts | 6 ++--- .../cmp-no-members.test.tsx | 24 +++++++++++++++++++ .../cmp-no-members.tsx | 23 ++++++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 test/wdio/watch-native-attributes/cmp-no-members.test.tsx create mode 100644 test/wdio/watch-native-attributes/cmp-no-members.tsx diff --git a/src/compiler/app-core/app-data.ts b/src/compiler/app-core/app-data.ts index ff7a7dd4059..0c378aee9d4 100644 --- a/src/compiler/app-core/app-data.ts +++ b/src/compiler/app-core/app-data.ts @@ -50,7 +50,7 @@ export const getBuildFeatures = (cmps: ComponentCompilerMeta[]): BuildFeatures = member: cmps.some((c) => c.hasMember), method: cmps.some((c) => c.hasMethod), mode: cmps.some((c) => c.hasMode), - observeAttribute: cmps.some((c) => c.hasAttribute), + observeAttribute: cmps.some((c) => c.hasWatchCallback), prop: cmps.some((c) => c.hasProp), propBoolean: cmps.some((c) => c.hasPropBoolean), propNumber: cmps.some((c) => c.hasPropNumber), diff --git a/src/runtime/proxy-component.ts b/src/runtime/proxy-component.ts index a9a50b849f3..ffed91c090b 100644 --- a/src/runtime/proxy-component.ts +++ b/src/runtime/proxy-component.ts @@ -49,12 +49,12 @@ export const proxyComponent = ( ); } - if (BUILD.member && cmpMeta.$members$) { - if (BUILD.watchCallback && Cstr.watchers) { + if ((BUILD.member && cmpMeta.$members$) || (BUILD.watchCallback && (cmpMeta.$watchers$ || Cstr.watchers))) { + if (BUILD.watchCallback && Cstr.watchers && !cmpMeta.$watchers$) { cmpMeta.$watchers$ = Cstr.watchers; } // It's better to have a const than two Object.entries() - const members = Object.entries(cmpMeta.$members$); + const members = Object.entries(cmpMeta.$members$ ?? {}); members.map(([memberName, [memberFlags]]) => { if ( (BUILD.prop || BUILD.state) && diff --git a/test/wdio/watch-native-attributes/cmp-no-members.test.tsx b/test/wdio/watch-native-attributes/cmp-no-members.test.tsx new file mode 100644 index 00000000000..6bcaa8d040e --- /dev/null +++ b/test/wdio/watch-native-attributes/cmp-no-members.test.tsx @@ -0,0 +1,24 @@ +import { h } from '@stencil/core'; +import { render } from '@wdio/browser-runner/stencil'; + +describe('watch native attributes w/ no Stencil members', () => { + beforeEach(() => { + render({ + template: () => ( + + ), + }); + }); + + it('triggers the callback for the watched attribute', async () => { + const $cmp = $('watch-native-attributes-no-members'); + await $cmp.waitForExist(); + + await expect($cmp).toHaveText('Label: myStartingLabel\nCallback triggered: false'); + + const cmp = document.querySelector('watch-native-attributes-no-members'); + cmp.setAttribute('aria-label', 'myNewLabel'); + + await expect($cmp).toHaveText('Label: myNewLabel\nCallback triggered: true'); + }); +}); diff --git a/test/wdio/watch-native-attributes/cmp-no-members.tsx b/test/wdio/watch-native-attributes/cmp-no-members.tsx new file mode 100644 index 00000000000..95cd3b7aac3 --- /dev/null +++ b/test/wdio/watch-native-attributes/cmp-no-members.tsx @@ -0,0 +1,23 @@ +import { Component, Element, forceUpdate, h, Watch } from '@stencil/core'; + +@Component({ + tag: 'watch-native-attributes-no-members', +}) +export class WatchNativeAttributesNoMembers { + @Element() el!: HTMLElement; + + private callbackTriggered = false; + + @Watch('aria-label') + onAriaLabelChange() { + this.callbackTriggered = true; + forceUpdate(this); + } + + render() { + return [ +

Label: {this.el.getAttribute('aria-label')}

, +

Callback triggered: {`${this.callbackTriggered}`}

, + ]; + } +} From 48dc71c9d0566bdca163151430a2d82ae2ba682f Mon Sep 17 00:00:00 2001 From: Tanner Reits Date: Tue, 25 Jun 2024 13:38:44 -0400 Subject: [PATCH 2/2] resolve test failures --- src/compiler/app-core/app-data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/app-core/app-data.ts b/src/compiler/app-core/app-data.ts index 0c378aee9d4..04890373ca6 100644 --- a/src/compiler/app-core/app-data.ts +++ b/src/compiler/app-core/app-data.ts @@ -50,7 +50,7 @@ export const getBuildFeatures = (cmps: ComponentCompilerMeta[]): BuildFeatures = member: cmps.some((c) => c.hasMember), method: cmps.some((c) => c.hasMethod), mode: cmps.some((c) => c.hasMode), - observeAttribute: cmps.some((c) => c.hasWatchCallback), + observeAttribute: cmps.some((c) => c.hasAttribute || c.hasWatchCallback), prop: cmps.some((c) => c.hasProp), propBoolean: cmps.some((c) => c.hasPropBoolean), propNumber: cmps.some((c) => c.hasPropNumber),