Electron is all the rage these days and it's enabled cool projects like Beaker to experiment with creating new kinds of browsers.
Although electron enables you to reuse Node.js code and mix it with new-ish versions of Chrome, it has some drawbacks. Namely: applications using Electron need to be distributed with what's essentially the entire Chromium and Node.js code bases and take on the high memory usage of Chrome out of the box.
webview
Wouldn't it be cool if instead of bundling a bunch of extra code in your application, you reused the web views that the OS provided? A few years ago this would have been a pretty bad idea because OS-specific browsers sucked. But now that Webkit is keeping relatively up to date with modern web features, and Windows 10 is able to use Edge instead of IE, it's startling to look like a pretty good idea.
I'm of course not the first to think of this and this idea is in use in the amazing zserge/webview library. The library is written in C
and has bindings for a bunch of languages. The idea is that you load a window with the OS webview, and then use two-way communication with it to create your user interface. One of the drawbacks of this library is that it's C API is fairly minimal so you can't do everything, and it doesn't support Edge on Windows, so you're stuck with old JS features.
Another library that was inspired by zserge/webview
is quadrupleslap/tether. This library uses Rust
instead of C
and integrates with the UWP APIs on Windows to use Edge as the webview. It still has some limitations that make it unsuitable for making a fully fledged browser, but before we get into that, let's look at what a browser would need.
A browser that wants to mess around with new protocols and JS APIs will want to have at least the following to be viable:
These features aren't super fancy, but it's still a challenge to find a way to get it work the same across multiple platforms.
webview
and tether
have examples of how to spawn windows with a webview, but they tie in the creation of a webview with the creation of a window.
This would need to be decoupled into two APIs. One for creating a window, and one for creating webviews and attaching a webview to the window.
The APIs for this will be based off of the code in tether
.
After these web views are created, we need APIs to move them around in the window. The platforms I'd want to support all provide some way of doing layout with absolute values, so those APIs could be abstracted across the platforms.
With the previous stuff in place, it could be enough to make a super basic browser. But we're looking to experiment with new protocols so we should have support for that. Most browsers have something like this, register a handler, and return a stream of data for a request. Edge seems to only support loading the main page from other protocols, so I'm not sure how well that'll work
TODO
Wouldn't it be cool if you had total control over your browser without having to do any native coding?
What if most of your browser features were created using a webpage?
I think that the easiest way to make this new browser hackable is to provide a set of high level APIs for spawning webviews and interating with them, and having a priviledged webview which is used as the the main browser logic.
From there you can configure which URL this priviledged view is loaded from, and allow it to control how the browser behaves from there.
The browser should ship with a default look and feel, but it should be easy to fork off of it and customize it how you see fit and configure it to load from your URL instead. This plays nicely with the Dat ecosystem since it's easy to fork an archive, customize it, and push out uptdates (or checkout a specific version).
Instead of having internal databses and fancy settings for the browser in native code, it can be stored in localStorage and indexedDB (or dat archives!).
This enables people to customize their browsers on a low level. For example, if you want to share your browser history between your devices, instead of relying on a centralized service, you could put your history in a Dat Archive and have that sync between your devices.
You could have your own ideas of what boomarks are and how they should be organized, or how tabs should be split on the screen.
The goal is to take browser customization outside of the native code, and to put it in the hands of the user.
<browser-webview>
elementpostMessage
and onmessage
Use Rust (yay)
Base code off of tether, a cross platform library for binding to OS browsers. This way you don't need to include any browser engine like you would with electron.
Add API for registerStreamHandler(url, stream: Write)
to Rust bindings
Linux
webkit_web_context_register_uri_schemeWindows
NavigateToLocalStreamURIApple
setURLSchemeHandlerAdd API for addJSInterface(name, script, (args: String) => void)
to Rust binding
Apple
Handle events: addScriptMessageHandler Inject APIs: WKUserScriptLinux
Handle Events: register_script_message_handler Inject APIs: add_script Windows
Handle Events: ScriptNotify Inject APIs: InvokeScriptAsyncAdd API for setPosition(top, bottom, left, right)
to reposition a webview
Windows
UpdateLayoutLinux
GtkFixed LayoutApple
setFrameSize / setFrameOriginSupport new protocols:
dat://
datrsipfs://
rust-libp2pipns://
rust-libp2pssb://
(for blobs) No existing rust implementation 😢JS APIs:
static async readFile(url: String, format?): ArrayBuffer|String
static async writeFile(content : ArrayBuffer|String) : String
static async readdir(url: String) : Array<String>
static mkdir(name: String, paths : Array<String>) : Strng
static async resolve(url: String) : String
Resolve IPNS to an IPFS URLstatic async * watch(url: String) : AsyncIterable<String>
Resolve static async publish(url: String) : String
static async self() : String
ipns://
or ipfs://
URL and you can write to folders if it's IPNS and you're the ownerBrowser UI should use overlayed web views
dat://
?)<webview>
postMessage
and onMessage
for communicationuserScripts
attribute for loading JS.<webview>
element in the HTMLwindow.open
and positioned with that in mind so that they'll be overlayed over the content webviewlocalStorage
or indexedDB
or whatever else.Use similar methods for Android and iOS? Should figure out how rust bindings would work there.