Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/app-mobile/components/plugins/PluginRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,18 @@ export default class PluginRunner extends BasePluginRunner {
return false;
});

// On native mobile, pass a file path so the WebView can load the
// script directly from the filesystem (avoids transferring the full
// script text across the React Native bridge). On web, file:// URLs
// are blocked by CSP so we pass the script text directly.
Comment on lines +51 to +52
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are blocked by CSP

Note: Rather than due to the CSP, this doesn't work on web because it uses a virtual file system to store plugins (because of browser sandboxing). Most files need to be read through fs-driver on web, rather than through native APIs.

const scriptFilePath = plugin.scriptText ? '' : `${plugin.baseDir}/index.js`;
this.webviewRef.current.injectJS(`
pluginBackgroundPage.runPlugin(
${JSON.stringify(shim.injectedJs('pluginBackgroundPage'))},
${JSON.stringify(plugin.scriptText)},
${JSON.stringify(scriptFilePath)},
${JSON.stringify(messageChannelId)},
${JSON.stringify(plugin.id)},
${JSON.stringify(plugin.scriptText)},
Comment thread
laurent22 marked this conversation as resolved.
);
`);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ const PluginRunnerWebViewComponent: React.FC<Props> = props => {
html={html}
injectedJavaScript={injectedJs}
hasPluginScripts={true}
allowFileAccessFromJs={true}
onMessage={pluginRunner.onWebviewMessage}
onLoadEnd={onLoadEnd}
onLoadStart={onLoadStart}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,29 @@ export const stopPlugin = async (pluginId: string) => {
delete loadedPlugins[pluginId];
};

export const runPlugin = (
pluginBackgroundScript: string, pluginScript: string, messageChannelId: string, pluginId: string,
export const runPlugin = async (
pluginBackgroundScript: string, scriptFilePath: string, messageChannelId: string, pluginId: string, scriptText = '',
) => {
if (loadedPlugins[pluginId]) {
console.warn(`Plugin already running ${pluginId}`);
return;
}

// When scriptText is provided (web), use it directly. Otherwise load
// the plugin script from the filesystem (native mobile). We use
// XMLHttpRequest because fetch() doesn't support file:// URLs on
// Android WebView.
let pluginScript = scriptText;
if (!pluginScript) {
pluginScript = await new Promise<string>((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', `file://${scriptFilePath}`, true);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(new Error(`Failed to load plugin script: ${scriptFilePath}`));
xhr.send();
});
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const bodyHtml = '';
const initialJavaScript = `
"use strict";
Expand Down
10 changes: 9 additions & 1 deletion packages/lib/services/plugins/PluginService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,8 +350,16 @@ export default class PluginService extends BaseService {

logger.info(`Loading plugin from ${path}`);

const scriptText = await fsDriver.readFile(`${distPath}/index.js`);
const manifestText = await fsDriver.readFile(`${distPath}/manifest.json`);
// On mobile, plugin scripts are loaded directly by the WebView
// from the filesystem, so we don't need to read them here.
const indexPath = `${distPath}/index.js`;
if (shim.mobilePlatform()) {
if (!(await fsDriver.exists(indexPath))) {
throw new Error(`Plugin bundle not found at: ${indexPath}`);
}
}
const scriptText = shim.mobilePlatform() ? '' : await fsDriver.readFile(indexPath);
const pluginId = makePluginId(filename(path));

return this.loadPlugin(distPath, manifestText, scriptText, pluginId);
Expand Down
Loading