Edit: Never mind! I was responding with a solution to a similar (but quite different) problem I was experiencing.
A workaround is for the content script to call repeatedly postMessage and await the result (because postMessage returns a Promise). The plugin's entrypoint script can then resolve that Promise when it wants to send a message to the content script.
Example
(Taken from the custom CodeMirror .vimrc plugin and modified)
Type definitions
// Type definitions
interface FooMessage {
kind: 'foo';
}
interface BarMessage {
kind: 'bar';
content: string;
}
interface SetReceiveMessageCallback {
kind: 'set-callback';
}
type ToContentScriptMessage = FooMessage|BarMessage;
type FromContentScriptMessage = FooMessage|SetReceiveMessageCallback;
// Content script:
type PostMessageCallback = (message: FromContentScriptMessage)=>Promise<string|ToContentScriptMessage>;
type OnMessageCallback = (message: ToContentScriptMessage)=>void;
const setupOnMessageCallback = async (
onMessage: OnMessageCallback, postMessage: PostMessageCallback
) => {
// Handle messages from index.ts in a loop:
while (true) {
const callbackResult = await postMessage({
kind: 'set-callback',
});
// Result should be a ToContentScriptMessage
if (typeof callbackResult === 'string') {
throw new Error(`Invalid callback result: ${callbackResult}`);
}
onMessage(callbackResult);
}
};
export default (context: { contentScriptId: string, postMessage: PostMessageCallback }) => {
return {
plugin: () => {
setupOnMessageCallback(message => {
console.log('Message from index.ts: ', message);
}, context.postMessage);
}
};
};
// index.ts
joplin.plugins.register({
onStart: async () => {
const contentScriptId = `some-content-script-id-here`;
let messageContentScriptCallback: MessageContentScriptCallback|null = null;
await joplin.contentScripts.onMessage(contentScriptId, (message: FromContentScriptMessage) => {
if (message.kind === 'set-callback') {
return new Promise(resolve => {
// Store resolve as a callback — we can use it to communicate with the contentScript.
messageContentScriptCallback = resolve;
});
}
// Handle other message types here.
});
await joplin.contentScripts.register(
ContentScriptType.CodeMirrorPlugin,
contentScriptId,
'path/to/content-script.js',
);
...
// Send a message to the content script
messageContentScriptCallback({
kind: 'foo'
});
}
});