lwc
lwc copied to clipboard
Expose all @wire configurations on the element instance in non-prod modes
Is your feature request related to a problem? Please describe.
@wire
'd properties are concise but don't provide insight into if and when a value is provisioned.
A customer recently shared this perspective:
I love how "wiring" Apex methods to properties reduces lines of code. But it makes debugging impossible. I have this js and see in the Apex logs that the method indeed is called but nothing ever reaches the Javascript property.
Consider this example LWC component:
import { LightningElement, wire} from 'lwc';
import myApexMethod from '@salesforce/apex/MyController.myApexMethod';
export default class MyComponent extends LightningElement {
@wire(myApexMethod, { args })
wiredProperty;
}
<template>
<template if:true={this.wiredPropery.data}>
{this.wiredPropery.data}
</template>
</template>
If this.wiredProperty.data
isn't rendered, what was the cause?
- Is the config args incorrect?
- Was the provisioned value the empty string?
- Did the wire service have an error?
Describe the solution you'd like
When in non-production mode, provide a developer with insight into:
- When a component's @wires provision a value (data or error)
- The resolved configuration that is responsible for a provisioned value
- When changes to resolved configuration are observed
This can be done by exposing the values on the element instance keyed from a known symbol. Continuing the example above, imagine running this code in the dev console after selecting the c-my-component
element:
> $0[Symbol.for('@wire')]
{
wiredProperty: {
data: { ... }, // provisioned data, if any
error: { ... }, // provisioned error, if any
config: { ... } // resolved config values
}
}
With wire reform getting the resolved configuration values is simple.
Describe alternatives you've considered
#1. Lifecycle Hook
Comparable to connectedCallback()
, if you implement a (static?) function it is invoked when wires update: config, provision of value/error.
export default class MyComponent extends LightningElement {
**wiredCallback**({wireName, config, value}) {
}
}
This approach was rejected because a single codebase is used for dev and prod mode, which means this debugging logic contaminates the codebase.
#2 Metaconfig for a wire
Add an additional parameter to @wire which is a meta-config object.
export default class MyComponent extends LightningElement {
@wire(getRecord, { ... }, **{ verbose: true }**)
wiredProperty;
}
This approach was rejected because it restricts future evolution of @wire
. It also suffers from placing the toggle for debug mode into the code whereas it is configured external to the component source code (eg on Lightning Platform it's via the Setup menu, in OSS it's a compiler/bundler flag).
#3 Callback on @wire
Add a third parameter arrow function to the @wire
declaration that is invoked only in dev mode.
export default class MyComponent extends LightningElement {
@wire(getRecord, {...config }, **(_debugOpts) => {...}**)
wiredProperty;
}
This approach was rejected because it restricts future evolution of @wire
. It also suffers from placing the toggle for debug mode into the code whereas it is configured external to the component source code (eg on Lightning Platform it's via the Setup menu, in OSS it's a compiler/bundler flag).
Thanks for raising this issue @kevinv11n.
The main concern that I have with a symbol attached to the host element is that it leaks internal details of the component on the host element. The wired properties have nothing to do with the custom element but with the component (those are 2 distinct objects in LWC). As a side effect, the parent component might also be able to observe in dev mode the child component wired properties, but this is less of an issue.
// From c-my-parent
this.querySelector('c-my-component')[Symbol.for('@wire')]
That being said, I think we should start exposing more information via the devtool to help developers debug LWC components and wired properties/methods. A preferable approach IMHO would be to define new APIs that a dedicated browser extension to hook into to observe and report the component state.
Good stuff! I'm very sympathetic with this. As for @pmdartus' concerns, I think we can mitigate that by not using Symbol.for
, and instead, install one symbol per wired field, e.g.:
As you can see, by creating a new symbol every time, per instance, per wire, it reads very nice, and it is very hard for anyone to attempt to use this information before they realized it is a dev-mode only thing.
Btw, I believe this is an old issue for this somewhere. This was @philcalvin's first complain about LWC a long time ago... let's get this solved.
The proposed facility is arguably a central component to the LWC development experience. @wire
s
are an area where any number of things can go wrong, and with varying consistency. Having access to more detailed error feedback early in the development cycle should both improve the quality of delivered components, and shorten the time to market for LWC developers.
Fixed in #3090. Thanks, @jodarove ! 🎉