Skip to content
This repository has been archived by the owner on Dec 27, 2022. It is now read-only.

Update to Electron 4 #1296

Merged
merged 20 commits into from Feb 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Expand Up @@ -59,11 +59,12 @@ Backers support this project by contributing $2 to $99 a month. [Become a backer

Requires node 6 or higher. On Windows, you may need to use npm version 4, due to a bug in npm 5.

In Linux (and in some cases macOS) you need libtool, m4, and automake:
In Linux (and in some cases macOS) you need libtool, m4, autoconf, and automake:

```bash
sudo apt-get install libtool m4 make g++ # debian/ubuntu
sudo apt-get install libtool m4 make g++ autoconf # debian/ubuntu
sudo dnf install libtool m4 make gcc-c++ libXScrnSaver # fedora
brew install libtool autoconf automake # macos
```

In Windows, you'll need to install [Python 2.7](https://www.python.org/downloads/release/python-2711/), Visual Studio 2015 or 2017, and [Git](https://git-scm.com/download/win). (You might try [windows-build-tools](https://www.npmjs.com/package/windows-build-tools).) Then run:
Expand Down
17 changes: 17 additions & 0 deletions app/background-process/browser.js
Expand Up @@ -102,6 +102,14 @@ export function setup () {
}
})

// quick sync getters
ipcMain.on('get-markdown-renderer-script', e => {
e.returnValue = fs.readFileSync(path.join(app.getAppPath(), 'markdown-renderer.build.js'), 'utf8')
})
ipcMain.on('get-json-renderer-script', e => {
e.returnValue = fs.readFileSync(path.join(app.getAppPath(), 'json-renderer.build.js'), 'utf8')
})

// HACK
// Electron doesn't give us a convenient way to check the content-types of responses
// so we track the last 100 responses' headers to accomplish this
Expand Down Expand Up @@ -570,6 +578,14 @@ function onUpdateError (e) {

function onWebContentsCreated (e, webContents) {
webContents.on('will-prevent-unload', onWillPreventUnload)
webContents.on('remote-require', e => {
// do not allow
e.preventDefault()
})
webContents.on('remote-get-global', e => {
// do not allow
e.preventDefault()
})
}

function onWillPreventUnload (e) {
Expand All @@ -591,6 +607,7 @@ function onCompleted (details) {
function set (v) {
resourceContentTypes.set(details.url, Array.isArray(v) ? v[0] : v)
}
if (!details.responseHeaders) return
if ('Content-Type' in details.responseHeaders) {
set(details.responseHeaders['Content-Type'])
} else if ('content-type' in details.responseHeaders) {
Expand Down
8 changes: 7 additions & 1 deletion app/background-process/hidden-windows.js
Expand Up @@ -10,7 +10,13 @@ var hiddenWindows = {}

export async function spawn (id, modulePath) {
var fullModulePath = require.resolve(modulePath)
var win = new BrowserWindow({show: false})
var win = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: false
}
})
// win.webContents.toggleDevTools()
console.log('[', id, '] Starting...')
win.loadURL(`beaker-hidden-window://loader/?module=${encodeURIComponent(fullModulePath)}&userDataPath=${encodeURIComponent(app.getPath('userData'))}`)
Expand Down
6 changes: 5 additions & 1 deletion app/background-process/ui/windows.js
Expand Up @@ -135,9 +135,13 @@ export function createShellWindow (windowState) {
backgroundColor: '#ddd',
defaultEncoding: 'UTF-8',
webPreferences: {
sandbox: true,
preload: PRELOAD_PATH,
nodeIntegration: false,
contextIsolation: false,
webviewTag: true,
sandbox: true,
webSecurity: false, // disable same-origin-policy in the shell window, webviews have it restored
// enableRemoteModule: false, TODO would prefer this were true, but shell window needs this to get the webviews' webContents IDs -prf
allowRunningInsecureContent: false,
nativeWindowOpen: true
},
Expand Down
5 changes: 1 addition & 4 deletions app/package.json
Expand Up @@ -8,7 +8,7 @@
"copyright": "© 2018, Blue Link Labs",
"main": "background-process.build.js",
"dependencies": {
"@beaker/core": "3.0.2",
"@beaker/core": "beakerbrowser/beaker-core#master",
"@beaker/dat-archive-file-diff": "^1.0.0",
"@beaker/electron-localshortcut": "^1.0.0",
"anymatch": "^1.3.2",
Expand Down Expand Up @@ -91,8 +91,5 @@
"utp-native": "^2.0.0",
"yo-yo": "^1.4.0",
"zerr": "^1.0.4"
},
"devDependencies": {
"devtron": "^1.4.0"
}
}
43 changes: 22 additions & 21 deletions app/shell-window/pages.js
Expand Up @@ -3,7 +3,6 @@
import { ipcRenderer, remote } from 'electron'
import EventEmitter from 'events'
import path from 'path'
import fs from 'fs'
import throttle from 'lodash.throttle'
import parseDatURL from 'parse-dat-url'
import errorPage from '@beaker/core/lib/error-page'
Expand Down Expand Up @@ -135,6 +134,8 @@ export function create (opts) {
isReceivingAssets: false, // has the webview started receiving assets, in the current load-cycle?
isActive: false, // is the active page?
isInpageFinding: false, // showing the inpage find ctrl?
isCurrentlyAudible: false, // is the page currently playing music?
isAudioMuted: false, // is the page muted?
inpageFindInfo: null, // any info available on the inpage find {activeMatchOrdinal, matches}
liveReloadEvents: false, // live-reload event stream
zoom: 0, // what's the current zoom level?
Expand Down Expand Up @@ -173,9 +174,6 @@ export function create (opts) {
executeJavascriptCalls: {},
executeJavascriptCallCounter: 0,

// hackfix reload failsafe
reloadHackfixCounter: 0,

// get the current URL
getURL () {
return this.url
Expand Down Expand Up @@ -393,6 +391,8 @@ export function create (opts) {
page.webviewEl.addEventListener('found-in-page', onFoundInPage)
page.webviewEl.addEventListener('enter-html-full-screen', onEnterHtmlFullScreen)
page.webviewEl.addEventListener('leave-html-full-screen', onLeaveHtmlFullScreen)
page.webviewEl.addEventListener('media-started-playing', onMediaChange)
page.webviewEl.addEventListener('media-paused', onMediaChange)
page.webviewEl.addEventListener('close', onClose)
page.webviewEl.addEventListener('crashed', onCrashed)
page.webviewEl.addEventListener('gpu-crashed', onCrashed)
Expand Down Expand Up @@ -614,6 +614,14 @@ function onDomReady (e) {
}
if (!navbar.isLocationFocused(page) && page.isActive) {
page.webviewEl.shadowRoot.querySelector('iframe').focus()

// HACKFIX
// make sure the page retains focus and the cursor doesnt go invisibl
// PR: https://github.com/beakerbrowser/beaker/pull/1285
// See: https://github.com/electron/electron/issues/14474
// -prf
page.webviewEl.blur()
page.webviewEl.focus()
}
}
}
Expand Down Expand Up @@ -782,21 +790,6 @@ function onDidStopLoading (e) {
statusBar.setIsLoading(false)
}

// HACK
// there is a race condition with Electron where the CSPs will sometimes prevent the preload from executing
// this can be detected by attempting to call executeJavaScript; if it takes longer than a second, that's too long
// reloading the page usually gets it to execute correctly
// -prf
let webviewCheckTO = setTimeout(() => {
if (page.reloadHackfixCounter > 5) return // stop, we're endlessly redirecting
page.reloadAsync()
page.reloadHackfixCounter++
}, 1000)
page.executeJavaScript('true').then(res => {
page.reloadHackfixCounter = 0
clearTimeout(webviewCheckTO)
})

// determine content type
let contentType = beaker.browser.getResourceContentType(page.getURL()) || ''
let isMD = contentType.startsWith('text/markdown') || contentType.startsWith('text/x-markdown')
Expand Down Expand Up @@ -843,7 +836,7 @@ function onDidStopLoading (e) {
.markdown pre > code { display: block; }
`)
if (!cachedMarkdownRendererScript) {
cachedMarkdownRendererScript = fs.readFileSync(path.join(APP_PATH, 'markdown-renderer.build.js'), 'utf8')
cachedMarkdownRendererScript = ipcRenderer.sendSync('get-markdown-renderer-script')
}

// NOTE uses webviewEl.executeJavaScript because we dont want to run the markdown renderer in an isolated world
Expand Down Expand Up @@ -881,7 +874,7 @@ function onDidStopLoading (e) {
`)

if (!cachedJSONRendererScript) {
cachedJSONRendererScript = fs.readFileSync(path.join(APP_PATH, 'json-renderer.build.js'), 'utf8')
cachedJSONRendererScript = ipcRenderer.sendSync('get-json-renderer-script')
}

page.executeJavaScript(cachedJSONRendererScript)
Expand Down Expand Up @@ -1012,6 +1005,13 @@ function onLeaveHtmlFullScreen (e) {
document.body.classList.remove('page-fullscreen')
}

async function onMediaChange (e) {
var page = getByWebview(e.target)
await new Promise(r => setTimeout(r, 1e3)) // the event consistently precedes the audible check by at most 1s
page.isCurrentlyAudible = await page.isCurrentlyAudibleAsync()
events.emit('media-change', page)
}

function onClose (e) {
var page = getByWebview(e.target)
if (page) {
Expand Down Expand Up @@ -1098,6 +1098,7 @@ export function createWebviewEl (id, url) {
var el = document.createElement('webview')
el.dataset.id = id
el.setAttribute('preload', 'file://' + path.join(APP_PATH, 'webview-preload.build.js'))
el.setAttribute('enableremotemodule', 'false')
el.setAttribute('webpreferences', 'allowDisplayingInsecureContent,defaultEncoding=utf-8,scrollBounce,nativeWindowOpen=yes')
// TODO re-enable nativeWindowOpen when https://github.com/electron/electron/issues/9558 lands
el.setAttribute('src', url || DEFAULT_URL)
Expand Down
22 changes: 13 additions & 9 deletions app/shell-window/ui/tabs.js
Expand Up @@ -48,6 +48,7 @@ export function setup () {
pages.on('did-stop-loading', onUpdateTab)
pages.on('page-title-updated', onUpdateTab)
pages.on('page-favicon-updated', onUpdateTab)
pages.on('media-change', onUpdateTab)
window.addEventListener('resize', debounce(onWindowResize, 500))
}

Expand All @@ -57,6 +58,8 @@ export function setup () {
function drawTab (page) {
const isActive = page.isActive
const isTabDragging = page.isTabDragging && (page.tabDragOffset !== 0)
const isAudioMuted = page.isAudioMuted
const isCurrentlyAudible = page.isCurrentlyAudible

// pick a favicon
var favicon
Expand Down Expand Up @@ -102,7 +105,11 @@ function drawTab (page) {
}

// normal rendering:

const audioIcon = isAudioMuted
? yo`<span class="fas fa-volume-mute"></span>`
: isCurrentlyAudible
? yo`<span class="fas fa-volume-up"></span>`
: ''
return yo`
<div class=${'chrome-tab' + cls}
data-id=${page.id}
Expand All @@ -113,7 +120,7 @@ function drawTab (page) {
title=${getNiceTitle(page)}>
<div class="chrome-tab-bg"></div>
<div class="chrome-tab-favicon">${favicon}</div>
<div class="chrome-tab-title">${getNiceTitle(page) || 'New Tab'}</div>
<div class="chrome-tab-title">${audioIcon}${getNiceTitle(page) || 'New Tab'}</div>
<div class="chrome-tab-close" title="Close tab" onclick=${onClickTabClose(page)}></div>
</div>`
}
Expand Down Expand Up @@ -219,8 +226,9 @@ function onToggleMuted (page) {
return () => {
if (page.webviewEl) {
const wc = page.webviewEl.getWebContents()
const isMuted = wc.isAudioMuted()
wc.setAudioMuted(!isMuted)
page.isAudioMuted = !wc.isAudioMuted()
wc.setAudioMuted(page.isAudioMuted)
onUpdateTab(page)
}
}
}
Expand Down Expand Up @@ -272,16 +280,12 @@ function onClickReopenClosedTab () {
function onContextMenuTab (page) {
return e => {
const { Menu } = remote
var isMuted = false
if (page.webviewEl) {
isMuted = page.webviewEl.getWebContents().isAudioMuted()
}
var menu = Menu.buildFromTemplate([
{ label: 'New Tab', click: onClickNew },
{ type: 'separator' },
{ label: 'Duplicate', click: onClickDuplicate(page) },
{ label: (page.isPinned) ? 'Unpin Tab' : 'Pin Tab', click: onClickPin(page) },
{ label: (isMuted) ? 'Unmute Tab' : 'Mute Tab', click: onToggleMuted(page) },
{ label: (page.isAudioMuted) ? 'Unmute Tab' : 'Mute Tab', click: onToggleMuted(page) },
{ type: 'separator' },
{ label: 'Close Tab', click: onClickTabClose(page) },
{ label: 'Close Other Tabs', click: onClickCloseOtherTabs(page) },
Expand Down
1 change: 1 addition & 0 deletions app/shell-window/webview-async.js
Expand Up @@ -38,6 +38,7 @@ const methods = [
'inspectElement',
'setAudioMuted',
'isAudioMuted',
'isCurrentlyAudible',
'undo',
'redo',
'cut',
Expand Down
5 changes: 5 additions & 0 deletions app/stylesheets/shell-window/chrome-tabs.less
Expand Up @@ -88,6 +88,11 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

.fa-volume-up,
.fa-volume-mute {
margin-right: 4px;
}
}

&.chrome-tab-nofavicon .chrome-tab-title {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -3,7 +3,7 @@
"name": "beakerbrowser",
"devDependencies": {
"browserify": "^13.0.1",
"electron": "3.0.9",
"electron": "4.0.3",
"electron-builder": "~20.8.0",
"eslint": "^4.5.0",
"eslint-plugin-import": "^2.7.0",
Expand Down
12 changes: 10 additions & 2 deletions tasks/rebuild.js
Expand Up @@ -2,14 +2,22 @@ var gulp = require('gulp')
var path = require('path')
var run = require('./util-run')

//(cd app && npm rebuild --runtime=electron --target=3.0.9 --disturl=https://atom.io/download/atom-shell --build-from-source); gulp build
//(cd app && npm rebuild --runtime=electron --target=4.0.3 --disturl=https://atom.io/download/atom-shell --build-from-source); gulp build

gulp.task('rebuild', gulp.series(function () {
// TODO read electron version
var cwd = path.join(process.cwd(), 'app')
console.log(cwd)
return new Promise(resolve => {
run(`npm rebuild --runtime=electron --target=3.0.9 --disturl=https://atom.io/download/atom-shell --build-from-source`, {cwd, shell: true}, function () {
var env = {}
if (process.platform === 'darwin') {
env = {
// required to make spellchecker compile
CXXFLAGS: '-mmacosx-version-min=10.10',
LDFLAGS: '-mmacosx-version-min=10.10'
}
}
run(`npm rebuild --runtime=electron --target=4.0.3 --disturl=https://atom.io/download/atom-shell --build-from-source`, {cwd, env, shell: true}, function () {
run(`npm run build`, {shell: true}, function () {
resolve()
})
Expand Down
2 changes: 1 addition & 1 deletion tasks/util-run.js
Expand Up @@ -5,7 +5,7 @@ module.exports = function (cmd, opts, cb) {
console.log(cmd)
cmd = cmd.split(' ')
opts.stdio = 'inherit'
opts.env = process.env
opts.env = Object.assign({}, process.env, opts.env || {})
childProcess.spawn(cmd[0], cmd.slice(1), opts)
.on('error', console.log)
.on('close', cb)
Expand Down