0

I have built a complex single page web app using React (create-react-app PWA). (app, code)

Now I want to reuse/share most of that app to make a VSCode web extension (CustomTextEditorProvider) and potentially a JupyterLab extension).

What would be the best way to share and organize the code? Are there any similar examples of reuse and multi-targeting?

I'm quite new to frontend development (I know nothing about webpack etc). I understand taht in theory it's possible and maybe even simple. However in practice it might not be as trivial. If I understand correctly, create-react-app hides a lot of complexity (hence eject existence). But VSCode has its own templates and webpack/tool configuration (especially for Web extensions). Probably, JupyterLab has its own extension templates and configurations.

How should I re-organize the repo without minimal disturbance to my SPA so that all three targets live in a single repository (or is it a bad idea?) with shared component code.

Ark-kun
  • 6,358
  • 2
  • 34
  • 70

1 Answers1

0

After producing the production build in your CRA based app you will have a bundle that can be loaded into any (recent) webbrowser. There's an index.html file that you would open to bootstrap your webapp.

The same works in vscode and any other host which can load webcontent. For vscode you would open a webview and add an iframe as webcontent. That iframe can then load your index.html or connect to a server etc. Here's how do it for my vscode extension:

    protected createPanel(url: URL, caption: string, placement?: string): Promise<boolean> {
        return new Promise((resolve) => {
            const viewColumn = (!placement || placement === "Active") ? ViewColumn.Active : ViewColumn.Beside;
            if (placement === "Beside Bottom") {
                void commands.executeCommand("workbench.action.editorLayoutTwoRows");
            }

            this.panel = window.createWebviewPanel(
                "my-webview", caption, viewColumn, {
                    enableScripts: true,
                    retainContextWhenHidden: true,
                },
            );

            this.panel.onDidDispose(() => { this.handleDispose(); });

            this.panel.webview.html = `
    <!doctype html><html lang="en">
    <head>
    <meta http-equiv="Content-Security-Policy" content="default-src *; img-src http: https:;
        script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'unsafe-inline' http: https: data: *;">
    </head>
    <body style="margin:0px;padding:0px;overflow:hidden;">
    <iframe id="frame:${caption}"
        src="${url.toString()}"
        frameborder="0" style="overflow: hidden; overflow-x: hidden; overflow-y: hidden; height:100%;
        width:100%; position: absolute; top: 0px; left: 0px; right: 0px; bottom: 0px" height="100%"
        width="100%">
    </iframe>
    </body></html>
    `;

        });
    }

Mike Lischke
  • 48,925
  • 16
  • 119
  • 181