Moving from Electron to Muon
February 20, 2018 · View on GitHub
Muon is a fork of Electron with improved security and support for Chrome extensions.
While both provide similar features, it's important to note that Muon has mostly diverged from Electron changes since around Electron v1.4.13 (Dec 20, 2016) due to architectural differences [1].
This document details API differences which affect switching to Muon.
As Muon is actively maintained for use in Brave Browser, it can also be useful to study the code found in brave/browser-laptop.
Prebuilt binaries
Prebuilt binaries for Muon are provided by the brave/electron-prebuilt repo. It can be used in package.json along with related variables configured in .npmrc. Running npm install && npm rebuild after adding the following changes should switch your project to use Muon.
package.json
{
"devDependencies": {
"electron": "brave/electron-prebuilt"
}
}
.npmrc
runtime = electron
target_arch = x64
brave_electron_version = 4.7.2
chromedriver_version = 2.33
target = v4.7.2
disturl=https://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist/
build_from_source = true
See .npmrc in brave/browser-laptop for up-to-date versions.
Building from source
Refer to the browser-laptop-bootstrap repo for instructions on building Muon from source.
Process sandbox
Muon removes NodeJS integration from the renderer process to improve security by enabling Chromium's Sandbox features.
A limited subset of Electron APIs are still available when files are loaded using the chrome://brave/* protocol. The wildcard path accepts an absolute file path and works similar to the file:///* protocol.
APIs are available under the chrome.* global object. Among those included are ipcRenderer, remote, and webFrame.
Webpack configuration
Using webpack's externals config can provide an easier transition instead of replacing all 'electron' imports.
externals: {
'electron': 'chrome'
}
asar archives
Electron's asar archives are deprecated in Muon and will be removed sometime in the future. They're planned to be replaced with pak files.
Currently Brave uses them to archive extensions which are to be unpacked on first startup.
Removed asar:// protocol
Accessing contents of an asar archive is no longer possible using the asar:// protocol. In its place is the chrome://brave/ protocol which supports loading files from within .asar archives.
In the renderer context, the __dirname global is unavailable due to removed NodeJS integration. To link to files within the asar archive, use paths relative to your app's entry html file—similar to a typical web application.
Given an application structure of
app/
assets/icon.svg
index.html
Using icon.svg can be linked using a relative path.
<img src="./assets/icon.svg" />
The resolved url would resemble chrome://brave//Users/Foobar/MyApp/app/assets/icon.svg. Keep in mind, the window frame's location must be using the chrome://brave/ protocol for this to work.
<webview> element
- Not available in renderers without
chrome://brave/*prefix. - Attributes which are no longer supported:
preload,allowtransparency,httpreferer getURL,send, and other remote methods can only be called from the main process. Example in #396
preload scripts
Preload scripts have been removed in favor of Chrome extension content scripts.
The ipcRenderer API is still available under the chrome.* object in content scripts.
Mimicking a preload script from a Chrome extension
If mutating any window.* global object is important for your project, it can be closely mimicked by injecting a JavaScript file from your content script.
const script = document.createElement('script');
script.src = chrome.runtime.getURL('preload.js');
document.documentElement.appendChild(script);
Set the extension manifest's run_at property to use the value of 'document_start' in combination with the above script to closely match the scope and timing of Electron's preload scripts.
protocol API
protocol.registerFileProtocolis removedprotocol.registerStreamProtocolis not yet supported (brave/browser-laptop#10629)
WidevineCDM
Muon supports downloading and using WidevineCDM binaries with the componentUpdater API.
Add the following code to the main process for WidevineCDM support.
const widevineComponentId = 'oimompecagnajdejgnnjijobebaeigek'
const widevineComponentPublicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmhe+02cLPPAViaevk/fzODKUnb/ysaAeD8lpE9pwirV6GYOm+naTo7xPOCh8ujcR6Ryi1nPTq2GTG0CyqdDyOsZ1aRLuMZ5QqX3dJ9jXklS0LqGfosoIpGexfwggbiLvQOo9Q+IWTrAO620KAzYU0U6MV272TJLSmZPUEFY6IGQIDAQAB'
componentUpdater.on('component-registered', (event, componentId) => {
componentUpdater.checkNow(componentId)
})
componentUpdater.registerComponent(widevineComponentId, widevineComponentPublicKey)
Links
- browser-laptop - Brave Browser built using Muon
- muon-quick - Sample code to get started with Muon; analagous to electron-quick-start.
References
[1] "I think we mainly split on a philosophical difference. Electron pulled in a minimal amount of chromium code and built custom apis on top of it. We have been moving in the other direction pulling in more chromium code and exposing js apis for it" - @bridiver