<webview>からBrowserViewへの移行


これは Gotanda.js #12 in ZEALS で発表した内容からTIPSを抜き出した記事です。

元Slide: https://speakerdeck.com/nekobato/migration-to-browserwindow-in-electron

package.json
{
  "dependencies": {
    "electron": "5.0.4",
  },
}

Electron公式ではBrowserView<webview>の代わりに使うことを推奨しています。

BrowserViewは可能な操作が<webview>に比べてまだ少なく、またmain process上で管理するため、<webview>とは些か勝手が違ってきます。
ここでは、BrowserView<webview>を操作してきた手法を置換するためのTIPSを紹介します。

基本的な操作

Before

webview.js
const webview = document.querySelector('webview');

// 表示するWeb Pageを変更する
webview.src = 'https://yahoo.co.jp';

// 戻れるなら戻る
if (webview.canGoBack()) {
  webview.goBack();
}

// いけたらいく
if (webview.canGoForward()) {
  webview.goForward();
}

// 更新
webview.reload();

After

BrowserView-renderer.js
const { ipcRenderer } = require('electron');

ipcRenderer.send('SET_URL', { url: 'https://yahoo.co.jp' });
ipcRenderer.send('BACK');
ipcRenderer.send('FORWARD');
ipcRenderer.send('RELOAD');
BrowserView-main.js
ipcMain.on('SET_URL', (_, payload) => {
  webView.webContents.loadURL(payload.url);
});

ipcMain.on('BACK', () => {
  if (webView.webContents.canGoBack()) {
    webView.webContents.goBack();
  }
});

ipcMain.on('FORWARD', () => {
  if (webView.webContents.canGoForward()) {
    webView.webContents.goForward();
  }
});

ipcMain.on('RELOAD', () => {
  webView.webContents.reload();
});

基本的にRendererとコミュニケーションしたい場合はイベントを送るという手法を採用しています。

URLの変更をRendererで検知する

function setUrl(url: string): void {
  mainWindow.webContents.send(types.SET_URL, {
    url,
    // ついでにcanGoBackとcanGoForwardを報告する
    canGoBack: webView.webContents.canGoBack(),
    canGoForward: webView.webContents.goForward(),
  });
}

webView.webContents.on('did-navigate', (_, url) => {
  setUrl(url);
});

webView.webContents.on('did-navigate-in-page', (_, url) => {
  setUrl(url);
});

サイズを可変にする

ウィンドウサイズに合わせて可変にする

BrowserView-main.js
mainWindow.on('will-resize', (_, { width, height }) => {
  webView.setBounds({
    x: 0,
    y: 0,
    width,
    height,
  });
});

レイアウトに合わせて可変にする

BrowserView-renderer.js
const webviewArea = document.querySelector('.webview-area');
ipcRendeerer.send('SET_BOUNDS', {
  x: webviewArea.offsetLeft,
  y: webviewArea.offsetTop,
  width: webviewArea.innerWidth,
  height: webviewArea.innerHeight
});
BrowserView-main.js
ipcMain.on('SET_BOUNDS', (_, { x, y, width, height }) => {
  webView.setBounds({
    x,
    y,
    width,
    height
  });
});

DevToolsを開く時に邪魔なので隠す

BrowserViewはWebおよびDevToolsよりも上に重なって表示されるため、BrowserWindowに表示されているWebのデバッグ中は邪魔です。DevToolsを表示中は隠す処理を書いておくと便利です。

BrowserView-main.js
mainWindow.webContents.on('devtools-opened', () => {
  webView.setBounds({
    x,
    y,
    // hide() みたいな便利な関数は無いので、見えないようにサイズ変更する
    0,
    0
  });
});

mainWindow.webContents.on('devtools-closed', () => {
  webView.setBounds({
    x,
    y,
    defaultWidth,
    defaultHeight
  });
});

BrowserViewの見た目をCSSで変えたい

無理だよ