top | item 22422989

NeutralinoJS: Lightweight Electron alternative using native browser controls

347 points| api | 6 years ago |neutralino.js.org | reply

190 comments

order
[+] derefr|6 years ago|reply
I feel like nobody cares too much if they’re running one Electron app; people do have the headroom for an extra 1-2GB of RAM usage. The problem comes when they run several Electron apps at once, and each comes with its own “base” overhead (i.e. the runtime memory consumption of the browser-runtime as a whole, independent of how many render contexts are open.)

Chromium is built to share a lot of things between tabs efficiently, but this economy-of-scale doesn’t translate over into having multiple instances of Chromium running. Each instance gets its own GPU renderer process + font-glyph tile cache, its own network-request cache (i.e. its own in-memory key-value store with its own LRU limit), etc. Running multiple Chromium instances at once is a bit like running multiple copies of an RDBMS on the same machine and expecting them to not fight over memory.

Does anyone know what exactly this “base” overhead in Chromium consists of; and, more importantly, how often it changes relative to Chromium releases? Because I’m wondering whether it’d be possible to factor most of it out into a separate layer from the highly-iterated-on “browser engine” DLL stuff (the renderer + DOM + JS layer) into its own sort of “Chromium Core Services” DLL, which could be relatively-more ABI-stable.

If you had that factoring-out, you could achieve a pretty good memory + CPU savings just by having Chromium + application frameworks like Electron all share one copy of the Chromium Core Services between them, while keeping their own higher-level “renderer+VM” DLL on top (which would hopefully be pretty stateless in terms of shared state, only adding the ~50MB mmap(2) overhead of the DLL-image itself, and then whatever memory the individual render-contexts consume.)

Alternately, of course, you could build Electron as a pseudo-browser where Electron “apps” are just separate windows running in its memory space, and the native Node processes are all just distinct V8 Execution Contexts in the same process. But 1. this would lose you the ability to develop for a particular version of the renderer, which is what Electron gains you over projects like Neutralino in the first place; and 2. this wouldn’t give you the benefit of Electron sharing service-memory with Chrome itself.

[+] woodrowbarlow|6 years ago|reply
i believe (but may be mistaken) that this was a goal of mozilla's positron project -- an electron-compatible runtime that uses firefox instead of chromium, but shares most resources across all of the positron apps running on your system so that it's more like having multiple tabs open rather than having multiple distinct instances open.
[+] efdee|6 years ago|reply
Where is this 1-2GB number coming from? I'm running a fairly large Electron app and the combined memory usage of its processes is about 250-300MB.
[+] zelly|6 years ago|reply
Given that everyone brings this up every time Electron is mentioned, and Electron apps keep proliferating, I expect a future version of Windows and macOS to have Chromium bundled with the OS. There will be some platform independent open standard that Electron will use under the covers.

Native desktop apps are never coming back. It will either be Electron or mobile apps emulated on desktops.

[+] dmitrygr|6 years ago|reply
> I’m wondering whether it’d be possible to factor most of it out into a separate layer

We've done this. The layer is called a web browser. You deliver runnable code to it using something called HTTP.

[+] ljm|6 years ago|reply
It has side effects, too. For example, I wanted to record a new screencast with OBS Studio (fantastic free software), but couldn’t capture any chromium-based application without disabling GPU-acceleration.

Only happens with electron apps.

[+] jcelerier|6 years ago|reply
> Chromium is built to share a lot of things between tabs efficiently

yey, currently using 6.6 gigabytes on my machine (RSS)... efficient...

firefox is no better, sitting at 4.8 gigabytes...

[+] gigel82|6 years ago|reply
I see projects like this pop up every once in a while and get abandoned.

A simpler approach may be to just publish a basic web server as your app (express on top of node would do) that runs on the local machine on some random port and have users just go to that URL with their regular installed browser. Bonus points for no leakage of security / CORS / etc. issues from the UI side of things, every unsafe thing needs to be node-side where it can be better controlled. Also enforces asynchronous and efficient communication between the UI and the "local backend".

[+] throwlaplace|6 years ago|reply
Does the browser really have access to all the same apis as electron? Doesn't electron have broader access to the file system (e.g. all the stuff that vscode does).
[+] troxwalt|6 years ago|reply
Love the idea of shipping something smaller. In your proposed idea, would a user still need to make sure node and express were installed? Or can you have a user download a project folder and initiate the same way they would a typical executable?
[+] martin-adams|6 years ago|reply
i see this approach with DB admin tools which makes it great to run in docker along side the db itself.
[+] hamaluik|6 years ago|reply
Looks kind of like WebView [1] which I earnestly tried but eventually abandoned. Using the system-provided web engine is great for space savings, but terrible for cross-compatibility and feature availability owing to having to use IE on Windows.

[1] https://github.com/zserge/webview

[+] valdiorn|6 years ago|reply
Isn't the "system provided web engine" now Edge on Windows 10, and has been fore a while?
[+] dingdingdang|6 years ago|reply
The good thing about webview is that it does not use localhost:8080 for internal comms!
[+] Sephr|6 years ago|reply
> There are some drawbacks such as Windows edition is based on IE etc.

This alone is a major reason to use Carlo[1] instead, which is arguably more secure (by virtue of not using IE) and produces even more lightweight bundles than NeutralinoJS.

1. https://github.com/GoogleChromeLabs/carlo

[+] xienze|6 years ago|reply
> There are some drawbacks such as Windows edition is based on IE etc.

Well that's kind of a non-starter. Part of the appeal with shipping an entire browser in an Electron app is to give yourself a fixed target.

It always seems that these "Electron killers" all have some fatal flaw, be it "just use whatever the system browser is" or "just as good as Electron, if you don't care about file drag-and-drop, system clipboard integration, full CSS support, minor things like that"[1].

1: https://github.com/ultralight-ux/Ultralight/issues/178

[+] paulirish|6 years ago|reply
Carlo is essentially what top commenter derefr is asking for.

That said, it is unmaintained and I don't expect that to change.

[+] jamesgeck0|6 years ago|reply
Is Carlo maintained? The last commit in master was eight months ago.
[+] rcarmo|6 years ago|reply
Doesn't work on Mojave for me, since it's apparently linked with 10.15 libraries:

    ./neutralino-mac  
    dyld: lazy symbol binding failed: Symbol not found: __ZNSt3__14__fs10filesystem14__current_pathEPNS_10error_codeE
      Referenced from: /Users/rcarmo/Downloads/New Items/neutralinojs-v1.3.0/./neutralino-mac (which was built for Mac OS X 10.15)
      Expected in: /usr/lib/libc++.1.dylib

    dyld: Symbol not found:  __ZNSt3__14__fs10filesystem14__current_pathEPNS_10error_codeE
      Referenced from: /Users/rcarmo/Downloads/New Items/neutralinojs-v1.3.0/./neutralino-mac (which was built for Mac OS X 10.15)
      Expected in: /usr/lib/libc++.1.dylib

    zsh: abort      ./neutralino-mac
[+] pjmlp|6 years ago|reply
This is the correct way of doing it when a PWA doesn't cut it.

No need to push a full browser engine when the OS already has enough of them available.

[+] robbick|6 years ago|reply
It definitely is the 'correct' way of doing it, but it will mean you use IE when in windows, which is often/normally not the correct way
[+] spenvo|6 years ago|reply
What are the top reasons an PWA wouldn't cut it?
[+] Mikho|6 years ago|reply
If you want anything from the web to work on Windows as native why not just use PWA utilizing Microsoft's (1) own PWA Builder (2) including the availability of proper debugging tools and acceptance in the store? It doesn't matter what tech it uses. The more important thing is it will be supported and updated. There won't be any surprises.

(1) https://developer.microsoft.com/en-us/windows/pwa/ (2) https://www.pwabuilder.com/

[+] nablaoperator|6 years ago|reply
Why is it called `Neutralino`? As a supersymmetric partner it's much heavier than the Standard Model particles.
[+] iamleppert|6 years ago|reply
A hello world Electron app uses about 50 MB of memory.

The problem with Electron apps is not so much Electron or Chromium but how they are designed & developed. Most developers view memory optimization as an after-thought. This is especially true for multiple document interface applications. The tooling is all there to monitor and optimize memory, but few make real memory budgets part of their build & integration testing process.

Developers have 16-32 GB of memory (or more) workstations and typically work on individual features that don’t exercise the edge cases of large datasets. They don’t bother to implement proper LRU mechanisms, paging, and often do performance optimizations that sacrifice memory for speed.

It gets worse if they aren’t forced to dog food their own creations or aren’t users of their app themselves.

[+] anonsivalley652|6 years ago|reply
Stupid question: instead of embedding an entire browser in each-and-every app and trying to keep that secure, why not package the native desktop framework as a shared, versioned component and the app as a tiny thing that depends on it?
[+] simias|6 years ago|reply
I'm generally pretty old school when it comes to development practices but I can totally understand how appealing it is to effectively ship your entire environment as part of your application instead of relying on shared dependencies. Dealing with dependency incompatibility is a huge maintenance burden in my experience, and it's super tricky to debug if you don't have access to the problematic environment (which is most of the time if you deal with public projects).

That's why I really try to get into docker for instance, sure good old unix sysadmin and configure scripts might arguably be more elegant and efficient but it's a huge pain to maintain and can (and eventually will) break out the blue after a system update because of a regression in some obscure library. Meanwhile docker images should work mostly everywhere without any effort and you only update your dependencies when you want to update them.

So now that storage is cheap and RAM is plentiful I think shipping the dependencies as part of the executable is a reasonable approach most of the time. The problem with electron is that the dependencies involve a full web browser and half a trillion libraries. That's the insane part. I have full python virtual envs for non-trivial apps that are a fraction of the footprint of an electron hello world. It's the core technology that's broken, not the packaging.

[+] bityard|6 years ago|reply
Not a stupid question. This is exactly how operating systems and application SDKs were always developed and deployed until fairly recently.
[+] efdee|6 years ago|reply
The appealing thing about Electron was that it shipped a particular version of a particular browser brand, combined with a particular version of a Javascript engine.

Knowing exactly what browser version you're developing for gives you a lot of freedom that you'd lack when having to support different ones.

[+] mrits|6 years ago|reply
Single binary is becoming more common even for runtime apps (JVM,.NET).

The reason I wouldn't want Electron to be shared across apps is I don't want a system wide install and certainly don't want to deal runtime version type issues. Electron would start having to be backward compatible for years.

[+] api|6 years ago|reply
That's sane. Sanity is prohibited in the realm of UI programming. There's apparently a law somewhere that states that all GUI libraries and APIs must be one of: platform-specific, bloated/slow, or incomplete/ugly.
[+] antoineMoPa|6 years ago|reply
So if I understand right, what makes this lighter than electron is the fact that only webkit2 is used instead of embedding the whole chromium app.
[+] pcr910303|6 years ago|reply
Looks like it's using system controls on macOS, Windows and dynamically linking to webkit on Linux for rendering the served HTML/CSS/JS (from node).

I see mentions of WKWebView(the system webkit) in the code[0], and while I don't know any Windows programming, they are #including <mshtml.h>[1] - looks like a system included web view (presumably the one that edge was based on). The linux build requires libwebkit2gtk-4.0-dev to be installed[2] - they're dynamically linked to webkit2gtk.

[0] https://github.com/neutralinojs/neutralinojs/blob/b10e065c97...

[1] https://github.com/neutralinojs/neutralinojs/blob/07fdc3c1c7...

[2] https://github.com/neutralinojs/neutralinojs/blob/master/REA...

[+] jonmaim|6 years ago|reply
Indeed I think they don't ship the whole browser package.

What they might actually do is to locally launch a HTTP server which renders the app if you call it on any browser (localhost:8080 in the examples). The chrome of the app is actually a thin layer that use the default OS web browser. That is why the memory footprint is much less higher that alternatives like electron.

[+] jacobush|6 years ago|reply
I don't understand, it seems like it runs in any browser? Are they using webkit2 as a replacement for node and the system browser for the GUI?
[+] ASalazarMX|6 years ago|reply
I guess it needs only 400 Mb of RAM instead of 500 then.
[+] rubyn00bie|6 years ago|reply
What is the difference between this and https://github.com/zserge/webview which it's based on? Or what do I get from this that I don't from webview (which I've been considering in Rust)?
[+] ronyfadel|6 years ago|reply
I'm currently working on an app built with Electron app. One thing I love is not to have to worry about whether the APIs I'm using are supported by the browser, since the browser is packaged inside the app. (if it works on my machine, it has a decent chance or working well on my users' machines).

The perf overhead (memory, bundle size) is big, but it's not stopping anyone from shipping Electron apps (Visual Studio Code, Slack, WhatsApp, etc..).

A nice to have compromise would be to have currently running Chromium Electron instances to host newly launched Electron apps, it doesn't solve the bundle size issue, but at least solves memory bloat and the number of Chrome main processes running.

[+] yayr|6 years ago|reply
I don't think using a local web port for the UI of a desktop app is a good idea, at least for security reasons. I guess much of the resources of the alternative solutions are used to mitigate just that (in addition to having a powerful backend framework). So if you don't want either, than maybe it is an option, but it severly limits the scope of the architecture.
[+] rafaelvasco|6 years ago|reply
It's an awkward transition period toward a universal virtual machine, universal bytecode format JIT based runtime that runs in browser and out of it. Ultimate cross platformness. The Holy Grail. Lot's of people trying several things that tackle some of it but not all. All of them will perish as all things do but they'll pave the way for the future. Let the revolution begin;