Is there a way to make install button work in VSCode extension Webview?

不问归期 提交于 2021-01-29 21:28:03

问题


We are making a VSCode extension on gatsby.js, and we have a tree view that shows a webview when clicked. In the webview, we have an 'install button' that we want to have it run 'npm install pluginName' by sending the command to the terminal.

We have a method in a class called 'installPlugin', which parses through npm API to get the plugin data such as the npm install plugin command.

For the webview content, we are using panel.webview.html to add the html string. On the button tag, we have an onclick attribute that whose value is the invocation of the installPlugin function. However, the button does not do anything when it is clicked. Instead, the npm install command runs when the plugin in the tree view is clicked(when webview opens simultaneously).

The code for installPlugin method in some class is as follows:

/* ---------- Logic handling the installation of Plugins and Themes --------- */

  async installPlugin(plugin?: any): Promise<void> {
    const activeTerminal = Utilities.getActiveTerminal();
    const gatsbyIsInitiated:
      | boolean
      | null = await Utilities.checkIfGatsbySiteInitiated();

    if (!gatsbyIsInitiated) {
      const input = await window.showErrorMessage(
        'Open up a new workspace containing only the site you are working on.',
        'Change Workspace',
        'Cancel'
      );
      if (input && input === 'Change Workspace') {
        commands.executeCommand('vscode.openFolder');
      }
      return;
    }
    // const rootPath = await Utilities.getRootPath();
    const { name, links } = plugin.command.arguments[0];
    if (plugin) {
      const installCmnd =
        (await PluginData.getNpmInstall(links.repository, links.homepage)) ||
        `npm install ${name}`;

      // if (rootPath) {
      //   activeTerminal.sendText(`cd && cd ${rootPath}`);
      //   activeTerminal.sendText(installCmnd);
      //   activeTerminal.show(true);
      // } else {
      // }
      activeTerminal.sendText(installCmnd);
      activeTerminal.show(true);
      // check for if "plugin" is a theme or actual plugin
      if (name.startsWith('gatsby-theme')) {
        window.showInformationMessage(
          'Refer to this theme\'s documentation regarding implementation. Simply click on the theme in the "Themes" section.',
          'OK'
        );
      } else {
        window.showInformationMessage(
          'Refer to this plugin\'s documentation regarding further configuration. Simply click on the plugin in the "Plugins" section.',
          'OK'
        );
      }
    }
  }

The code for webview panel is here:

export default class WebViews {
  static async openWebView(npmPackage: any) {
    // const { links, name, version, description } = npmPackage;
    const readMe = await PluginData.mdToHtml(links.repository, links.homepage);

    // turn npm package name from snake-case to standard capitalized title
    const title = name
      .replace(/-/g, ' ')
      .replace(/^\w?|\s\w?/g, (match: string) => match.toUpperCase());

    // createWebviewPanel takes in the type of the webview panel & Title of the panel & showOptions
    const panel = window.createWebviewPanel(
      'plugin',
      `Gatsby Plugin: ${title}`,
      ViewColumn.One
    );

    // create a header for each npm package and display README underneath header
    // currently #install-btn does not work
    panel.webview.html = `
    <style>
      .plugin-header {
        position: fixed;
        top: 0;
        background-color: var(--vscode-editor-background);
        width: 100vw;
      }

      #title-btn {
        display: flex;
        flex-direction: row;
        align-items: center;
        align-text: center;
      }

      #install-btn {
        height: 1.5rem;
        margin: 1rem;
      }

      body {
        position: absolute;
        top: 9rem;
      }
    </style>
    <div class="plugin-header">
      <div id="title-btn">
        <h1 id="title">${title}</h1>
        <button id="install-btn" onclick="${installPlugin(npmPackage)}">Install</button>
      </div>
      <p>Version: ${version}</p>
      <p>${description}</p>
      <hr class="solid">
    </div>
    ${readMe}
    `;

    // close the webview when not looking at it
    panel.onDidChangeViewState((e) => {
      if (!e.webviewPanel.active) {
        panel.dispose();
      }
    });
  }

In summary, we would like to know if there is a way to have the onclick attribute in the webview.panel.html to have reference to a method in a class, which is the installPlugin method. It seems like the html in webview does not have any reference to the installPlugin method.


回答1:


The most important thing you should be aware of is that you cannot call code in the webview from the extension or vice versa! Once you internalized that things should become more obvious to you.

What you do instead is to send messages, just like you do for example with web workers. Your button can only trigger a function in your webview code. And this function should send a message to vscode. This in turn ends up in your extension webview. For more details see the webview documentation, particularly the message passing paragraph.



来源:https://stackoverflow.com/questions/64395277/is-there-a-way-to-make-install-button-work-in-vscode-extension-webview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!