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 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.
Refer to the browser-laptop-bootstrap repo for instructions on building Muon from source.
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
.
Using webpack's externals
config can provide an easier transition instead of replacing all 'electron'
imports.
externals: {
'electron': 'chrome'
}
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.
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.
- 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 have been removed in favor of Chrome extension content scripts.
The ipcRenderer
API is still available under the chrome.*
object in content scripts.
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.registerFileProtocol
is removedprotocol.registerStreamProtocol
is not yet supported (brave/browser-laptop#10629)
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)
- browser-laptop - Brave Browser built using Muon
- muon-quick - Sample code to get started with Muon; analagous to electron-quick-start.
[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