I need to develop two components, in two separate namespaces, that can interact with each other. As per the product documentation it is not possible (yet) to write a component that uses a component from a different namespace.
I am therefore looking at a way of doing this that is compatible with the LWC framework.
As part of a separate discussion with a Salesforce Product Manager, it was suggested that I could consider using the new LWC Message Channel stuff. However, this is only Winter '20 developer preview at this stage and therefore not something I can use at this point.
The "not quite product" approach available until LWC Message Channels arrive as GA is the "pubsub" approach as discussed in further product documentation.
Note that the pubsub approach, as it stands in the example code, cannot be used directly since it is defined as a module and the documentation (see first link) says modules cannot be used cross-namespace. Instead the idea is to make it a static resource and load it as if it were a third-party library.
Knowing that LWC can really bite you in the posterior if you are doing anything slightly out of the ordinary I decided to create a simple PoC. The "core" package includes the "pubsub" code as a static resource, which gets imported like this in the "core" package component:
import {loadScript} from 'lightning/platformResourceLoader';
import pubsub from '@salesforce/resourceUrl/pubsub';
The code uses loadScript to resolve the imported URL (pubsub) into JavaScript available for use in the component.
The "secondary" package does this almost identically; the only difference is that this time the import looks like:
import pubsub from '@salesforce/resourceUrl/corens__pubsub';
where "corens" is the namespace for the "core" package.
This appears to deploy to the org fine. However, when executing the code it doesn't behave as expected. The code for handling the registration of listeners during the loading of the resource fails:
renderedCallback() {
if (!this._pubsubInit) {
// Mark that this loading is complete
this._pubsubInit = true;
loadScript(this, pubsub).then(() => {
// Tentatively register, in case the page reference is already resolved
this.register();
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: "Error loading pubsub",
message: error.message,
variant: "error"
})
);
});
}
}
Something I can't see makes the loadScript Promise call the catch instead of the then, but the "error" is undefined (and therefore the toast event cannot be created due to an unhandled JavaScript error attempting to access "error.message").
If I load a script from the current component's namespace, it seems to work OK.
Have I hit yet another restriction that means it is impossible to use a shared JavaScript resource to supply the common "pubsub" functionality? Have you got a solution for this? (I am thinking about effectively duplicating the pubsub code and making them share a common "var" definition to share the "pubsub" event listener state and that is my next thing to try, but if you already have a way to make this work I'd love to know how!)