docs: function (embedder, params) {
    if (webViewManager == null) {
      webViewManager = process.electronBinding('web_view_manager')
    }
  
    const guest = webContents.create({
      isGuest: true,
      partition: params.partition,
      embedder: embedder
    })
    const guestInstanceId = guest.id
    guestInstances[guestInstanceId] = {
      guest: guest,
      embedder: embedder
    }
  
    // Clear the guest from map when it is destroyed.
    //
    // The guest WebContents is usually destroyed in 2 cases:
    // 1. The embedder frame is closed (reloaded or destroyed), and it
    //    automatically closes the guest frame.
    // 2. The guest frame is detached dynamically via JS, and it is manually
    //    destroyed when the renderer sends the GUEST_VIEW_MANAGER_DESTROY_GUEST
    //    message.
    // The second case relies on the libcc patch:
    //   https://github.com/electron/libchromiumcontent/pull/676
    // The patch was introduced to work around a bug in Chromium:
    //   https://github.com/electron/electron/issues/14211
    // We should revisit the bug to see if we can remove our libcc patch, the
    // patch was introduced in Chrome 66.
    guest.once('destroyed', () => {
      if (guestInstanceId in guestInstances) {
        detachGuest(embedder, guestInstanceId)
      }
    })
  
    // Init guest web view after attached.
    guest.once('did-attach', function (event) {
      params = this.attachParams
      delete this.attachParams
  
      const previouslyAttached = this.viewInstanceId != null
      this.viewInstanceId = params.instanceId
  
      // Only load URL and set size on first attach
      if (previouslyAttached) {
        return
      }
  
      if (params.src) {
        const opts = {}
        if (params.httpreferrer) {
          opts.httpReferrer = params.httpreferrer
        }
        if (params.useragent) {
          opts.userAgent = params.useragent
        }
        this.loadURL(params.src, opts)
      }
      guest.allowPopups = params.allowpopups
      embedder.emit('did-attach-webview', event, guest)
    })
  
    const sendToEmbedder = (channel, ...args) => {
      if (!embedder.isDestroyed()) {
        embedder._sendInternal(`${channel}-${guest.viewInstanceId}`, ...args)
      }
    }
  
    // Dispatch events to embedder.
    const fn = function (event) {
      guest.on(event, function (_, ...args) {
        sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT', event, ...args)
      })
    }
    for (const event of supportedWebViewEvents) {
      fn(event)
    }
  
    // Dispatch guest's IPC messages to embedder.
    guest.on('ipc-message-host', function (_, channel, args) {
      sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE', channel, ...args)
    })
  
    // Notify guest of embedder window visibility when it is ready
    // FIXME Remove once https://github.com/electron/electron/issues/6828 is fixed
    guest.on('dom-ready', function () {
      const guestInstance = guestInstances[guestInstanceId]
      if (guestInstance != null && guestInstance.visibilityState != null) {
        guest._sendInternal('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', guestInstance.visibilityState)
      }
    })
  
    // Forward internal web contents event to embedder to handle
    // native window.open setup
    guest.on('-add-new-contents', (...args) => {
      if (guest.getLastWebPreferences().nativeWindowOpen === true) {
        const embedder = getEmbedder(guestInstanceId)
        if (embedder != null) {
          embedder.emit('-add-new-contents', ...args)
        }
      }
    })
  
    return guestInstanceId
  }