The Neutralino.js Page

Basically this page encapsulates some of the experience I have had with using Neutralino.js

General:

Interesting project this, the aim of the project being to produce a cross-platform desktop application environment based on HTML/JS/CSS without the heavy footprint of a bundled browser.

Unlike NW.js and Electron which both bundle a modified Chromium browser Neutralino uses the native browser on the particular platform (eg: MacOS - Safari-Webkit) so the shipped application is massively lighter in terms of size. The downside at the moment is that Neutralino (as at 2021) is quite young in development terms so there is a lot of capability missing compared to the more mature NW.js/Electron projects however the dev team seem to be pushing out updates fairly quickly at the moment.
Note: I have mentioned Electron here but I prefer NW.js (even though the world is being drawn into the Electron Black Hole) so any comparisons of Neutralino will tend to be with NW.js.

I have tried Neutralino on the Mac and for me it works quite well if I encapsulate non-complex websites as the app resource. PHP is not supported in the native window since the internal server is a static one however a PHP server can be started as a child process. The Node ecosystem is not directly supported by Neutralino but packaged node apps can be run via child process or the new Extension API offers an opportunity to integrate node.

Neutralino vs NW.js:

Neutralino

Pros

  • Small bundle size of apps
  • Easy to build binary for platform
  • GitHub Discussions
  • Slack chat
  • Extension API
  • Fairly active dev

Cons

  • Dev team appears small
  • Community limited
  • Docs minimal
  • Examples minimal
  • Possible inconsistent browser rendering across platforms (shouldn't be big problem now with standardized browsers)
  • Transparency not supported for widget style apps (on roadmap)
  • Prebuilt binaries only for later OS versions (eg: MacOS 11)
  • HTML media tag support (MP4/WebM/Wav) broken in pre-Catalina Mac build
  • Heavy reliance on upstream libraries - support is under-resourced and may lose traction to other repos (eg: Tauri, WAILS)

NW.js

Pros

  • Node ecosytem support
  • Updated prebuilt binaries for all platforms
  • Docs relatively good
  • Google Groups forum
  • Gitter forum
  • Discord chat
  • Consistent browser rendering across platforms
  • Transparency supported for widget style apps
  • Easy to build starter app (start file is either html/js)

Cons

  • Dev team very small (largely 1 person with occasional support from 2/3 others)
  • Community limited
  • Large bundle size of apps
  • Loses a lot of interest to Electron as the latter is 'popular'

In regard to the above comparison the Community support for both projects is quite limited.

For NW.js there are a number of supporting projects (packagers/updaters/etc) that exist but are struggling in the stampede to Electron.

For Neutralino there is a dearth of supporting projects.

There are probably a lot more pros/cons but I have only tried a few scenarios.
eg:
standalone PHP web server app - NW.js OK, Neutralino OK

transparent widget app - NW.js OK, Neutralino NO
  note: showstoppers here with transparency not implemented and draggability broken on Safari

express server app - NW.js OK, Neutralino OK

static web encapsulation - Both OK

apps using node modules - NW.js OK, Neutralino Partial
  note: may be possible via extension API

Regarding the size thing the difference in app size is dramatic. eg: a very simple app in Neutralino was 2.7MB whereas the same app in NW.js weighed in at 134.4MB.

For me I can generally live with the larger NW.js builds for complex apps but once multiple apps are running or small widget style apps are used then the size becomes an issue.

At this stage the Neutralino project seems to be just getting out of the proof of concept stage so the API is a little thin especially with no access to node modules.

Special Note: Node modules are not supported directly by Neutralino (unable to require from JS) however Neutralino does support a child process type API.

Neutralino.os.execCommand() allows the use of CLI terminal commands so the use of packaged Node apps as executables is possible (eg: Express server, etc)
The new extension API may offer a tighter integration. As of v4.6.0 a spawnProcess API has been included which will allow streaming control of child processes - this should aid integration.

Unfortunately the Mac platform support is weak as there are a few vital features that do not work and appear to be down to the webview library which at the moment is basically a dump for Mac related issues with no effort to address. Since Catalina Safari 15 has fixed some stuff but there seems to be features that work in Safari but not via webview eg: Dark Mode detection and mediaDevices stuff.
eg:
   Media files don't work (except for MP3) - OK in Safari 15
   cut/paste not working
   native menus not available - needs a DCR action
   draggable elements broken - OK in Safari 15
   portable file dialog library issues not being addressed


Useful Neutralino.js Links



Neutralino.js site HERE the main site with docs, etc


GitHub repos HERE GitHub repos


Project article HERE Architectural article by Lead Developer


StackOverflow HERE 




Neutralino.js Concepts/Packaging



CSS/HTML coding:

Should be quite straight forward normally but there will be variations between the browsers on each platform - for me if I port an app from NW.js to Neutralino then that is moving from Chromium to Safari/Webkit so some differences will be encountered. Likewise if the app is of a type that allows remote access from other browsers then the layout coding may have to reflect that.
Neutralino also has Browser and Cloud modes in addition to the Window mode but these I think are still being developed - I have only worked with the Window mode (Desktop).

Typical look of the sample app for Neutralino (with tray menu popup) -

The Neutralino Sample App

Neutralino is a Client-Server type app -

  Neutralino Server: essentially a web server that handles requests from the Client Library (via Websockets)

  Neutralino Client:

In terms of a MacOS app package the Neutralino Server is the equivalent of the main executable runtime binary that normally sits in the MacOS folder. The Neutralino Client Library is the neutralino.js file that communicates with the server binary. The client library needs to be referenced from every HTML page in the app that needs to use the Neutralino server functions (eg: Native API).

Typical MacOS Project to produce a desktop App:



New Project :: - call it Box

:: Typical MacOS app structure ::

Hippo.app      (App package name)

Contents      (Folder - Top Level)

   MacOS  (Folder - app package executable binary)
   Info.plist  (File - Property list information for package)
   Resources  (Folder - App files/resources)


   MacOS folder      (Folder - 2nd Level)

      booter  (File - executable script used to start app binary and define app resources path)
      box  (File - executable server binary - this is the binary produced by Neutralino)


   Info.plist      (File - 2nd Level)  Property list file for App

   Resources      (Folder - 2nd Level) -

      neutralino.config.json  (File - config file for app binary)
      neutralino.log  (File - log file may be produced if enabled)
      app.icns  (File - App icon file referenced from Info.plist)
      app resources  (Files - can be bundled as a resources.neu file rather than discrete files.

      js      (Folder - 3rd Level)
          neutralino.js  (File - Client Library)
          other js files


Neutralino will produce the server binary and the client library file which then need to be packaged (in the case of a Mac app) into an application bundle.

Packaging the App ::

Neutralino-CLI is used to bundle the app file/resources into a resources.neu file which can then be used with the Neutralino server binary. The Client Library file that is required to work with the server binary and the neutralino.confif.json file are included in the resources.neu bundle.
Again neutralino-CLI is not required if app resource bundling is not required.
Further processing into installer bundles/etc need to be done using third party code. eg: Win installers/ Mac app packages/ DMG images /etc

Mac:

   Platypus is the closest app that I have seen that can produce a standard Mac .app package. I just build mine manually.
   I may try and make a bundler that will use appdmg node modules to produce a distributable.

Special Note: if .app is added to the mac binary produced by Neutralino it will sort of act like a Mac app but a normal Mac app bundle is actually a folder bundle (as shown above) with the executable in the MacOS folder rather than an executable with a .app suffix.

 Sample Mac App packages -

Download Box project app bundle (ZIP) HERE(basically a minimal skeleton app)

Download Hippo project app bundle (ZIP) HERE(basically an API demo app)


=> Unzip and place where-ever
=> Note: the executables in the MacOS folder are built for 10.13 (High Sierra or later) and are renamed from neutralino-mac_x64 as it was named when produced by Neutralino


Windows:

   Possibly Inno/NSIS/EVB will work here

Linux:

   Linux64 only - https://www.npmjs.com/package/neutralino-appimage-bundler



Using Audio/Video (MP3/MP4)



HTML media tag use is problematic with the Mac build.

Status:
v2.8.0 - Safari MP4/MP3/WAV OK , WEBM needs Safari 14+, OGV Fail - Firefox/Chromium/Opera OK

v3.0.0 - Safari MP3 OK , WEBM needs Safari 14+, MP4/OGV/WAV Fail - Firefox/Chromium/Opera OK

v4.0.0 - Safari MP3 OK , WEBM needs Safari 14+, MP4/OGV/WAV Fail - Firefox/Chromium/Opera OK

v4.3.0 - Safari MP4/WebM/MP3/WAV OK with Safari 15 otherwise as per v4.0.0, OGV not supported - Firefox/Chromium/Opera OK

As it stands the Mac build for MacOS pre-Catalina is incapable of hosting local video within the native window and only supports MP3 audio (Needs Safari 15).


Using Flash



As of Dec 2020 Flash support has been withdrawn by Adobe so no current browsers are likely to support it.

Flash is Dead - Long live Flash


Handy config (neutralino.config.json) settings





General



At this stage of my experience with Neutralino I would have to say that the feature set has improved well enough but there is an issue with the ongoing maintenance of upstream libraries. Initial implementation of the libraries for Neutralino involve a bit of customisation and if further issues arise later down the track the maintenance of the libraries appears under-resourced. eg: quite simple issues that have been resolved upstream may not be integrated with the Neutralino libraries. This is typical of the webview and portable-file-dialog libs for example.
Neutralino is largely based in the javascript arena but the core server which relies on the upstream libraries(C++/Go/etc) is based on C++ so any JS focussed dev is going to struggle with trying to troubleshoot the core and the libraries themselves.
This would be the area where Tauri might win out since although it is Rust based the developer resource of the project is far deeper. WAILS which is GO based may also be an option to get round the library support issues.



Node Packaging



Well - technically Neutralino does not support the Node ecosystem however by using the os.execCommand() or spawnProcess() API (child process) it is possible to run packaged executables.
eg: Express

There are a number of packaging systems out there led by Pkg and Nexe. Pkg support appears to be on the wane. I tried both Pkg and Nexe but had issues with them. The method I have used very succesfully is called Caxa and is my Node packager of choice.

CAXA:
The repository is very informative and appears active plus it just works.

Very easy to use - Select Node version to use, create a folder and install caxa via NPM, prepare the target App folder then run caxa and a packaged executable will be built in seconds.
The executable can then be included in the Neutralino app for use with the os.execCommand() API. The executable is essentially a compressed self-executing bundle.

Taking the example of running an Express server package once the child-process has started it then Neutralino loses control so if Neu exits then the express process can be left running as an orphan.

There are currently two ways of handling this scenario -
   Using execCommand() to run the server will return a PID for the Express process which can be stored and used to close the server with kill -9 PID method.
   Using spawnProcess() to run the server will return both the Express PID and a spawnProcessID - the latter can be used to close the spawnedProcess using the updateSpawnedProcess method.

This method of packaging seems most suitable for a web app that has a server and uses browsers to access the content.

UPDATE: v4.0.0 provides an extension API that may assist in the usage of node modules - usage still to be figured out by myself however


GitHub Repositories



neutralinojs: The server code.

   This repository is the one to use for building the server binary (largely C++ based src files). In the case of MacOS the release binaries are usually built with MacOS 11 so for earlier releases the binary will have to be generated with this repository.
   eg: Using Terminal - bash build_macos.sh

Note: As of post 4.4.0 the build process is changing with buildzri script using python3 instead of bash script.
In the case of MacOS this is a bit more complicated. MacOS generally includes Python 2.7 so Python 3 will have to be installed. As from Monterey 12.3 Python is not bundled at all so a Python 3 install is required.

neutralino.js: The client library.

   This repository is used to build the JS Client library. This needs to match the server binary.

neutralinojs-CLI: This can be used to generate a basic package bundle called resources.neu

   This repository can be used to do basic packaging of the app. The default binaries are usually compiled for the later OS versions so for earlier versions the platform binary may need to be rebuilt using the neutralinojs repository. The CLI produces a dist folder within the app folder that contains the resources.neu bundle (created with Rollup.js) along with the platform binaries.
   The beginning of the resources.neu file will contain the config for the binary (neutralino.config.json).
   Essentially the app will work with the binary and the resources.neu file. The resources.neu file can be replaced with the open source app files but the config file must also be included.
   For the avoidance of doubt it is important to note that CLI does not build the server binary it only uses a copy of an existing server build and basically just bundles the app resources into the resources.neu package. Unless the dev specifically wants the app resources packaged as a resources.neu file the CLI does not have to be used.

neutralinojs-minimal: Simple template for a Neutralino app.


Architecture/Contexts



Essentially based on a client/server approach - neutralinojs provides the server code and neutralino.js is the client library.

Four modes are available - window, browser, cloud and chrome.

Window mode: (normal desktop mode)

The neutralino server binary is co-located with a config file (neutralino.config.json) which will specify the main window parameters. Additional windows can be opened using the Native JS API however the window functionality at present is incomplete. Version 3.0.0 addresses a few of the window issues.

Use of the Native JS API requires the Client Library JS to be called from HTML files in the windows.

Local Storage:

Rather than use the native browser localstorage neutralino uses a hidden folder (.storage) in the app root folder. This storage will be available using the API to any window that is opened despite the fact that they are created as essentially separate apps. This storage can also be used as a conduit between windows.


Window management:

The window control buttons -

Close button: Controlled by a boolean option (exitProcessOnClose).

eg: true will invoke app.exit() directly (used for windows with fixed content that cannot call the Client Library API)
   false will allow Client Library API to be used (used for windows with HTML content and allow for do stuff before exit scenarios)

Min/Max/Resize buttons: Work implicitly as expected

In a multiple window scenario each window is effectively a separate app and so subwindows are not directly controlled by the main window. In this case communication between the windows can be done via the storage API which is held in a hidden folder in the app root directory.
A typical scenario here would be if the main app window closes then the subwindows are normally closed as well rather than leaving orphan windows that need to be individually closed.

eg: sample technique - each new win will store the unique PID on open and remove the PID on close. This provides an array of PID's (open subwindows) that can be checked by the main window before closing and the subwindow processes can be killed from the main window and the array cleared. If the storage array is cleared when the app starts then the only time the array should exist is if a subwindow is open.


Version Status:

2.8.0 - reasonably stable using HTTP for server calls but lacking in featureset.

3.0.0 - best avoided as architecture undergoing a lot of breaking changes.

eg:   Native API re-alignment
      Dialog library replaced
      Draggability code changed (broken on Mac)
      WebSocket implemented
      Process management library replaced (post 3.0.0 release)

Major Mac issue: window.create API is broken (it works OK with 2.8.0).
Another issue to be aware of is with the change to WebSocket the server now has a spinup delay (c. 30ms) so the ready event needs to be used with the API commands or else server offline issues will occur.
Media playback on the Mac build is badly broken since change to WebSocket.

4.0.0 - OK but still a bit of feature work going on.

      In v4.0.0 the ready event no longer has to be used to mitigate the server start delay issue as any immediate Native API call on start will be queued until the server(WebSocket) has fully started.
      An important change has been implemented for the execCommand API - should this be used to start a remote server or suchlike then the {background: true } option should be used otherwise the await function will freeze the API as long as the remote process is running and provides no resolve data.

4.3.0 - Stable release
      Media playback on the Mac build is OK on machines running Safari 15 (Catalina and later) - although OGV has never been supported.
      Draggable elements are also supported OK with Safari 15.

4.4.0 - Stable release

      Window and Filesystem API enhancements


Special Note: As it stands (as at 4.4.0) for MacOS apps the versions later than 2.8.0 are a bit of a disaster because the websocket implementation is not a drop in replacement for the http (this affects media and child process usage) - as a result Safari 15 (Catalina or later) is required and support for earlier releases of MacOS is patchy.

4.6.0 - Stable release

4.7.0 - Stable release

4.8.0 - Stable release


Application Start Modes



Four modes exist - window, browser, cloud, chrome.
:: window ::

   Typically used for desktop apps.

   The server binary on double-click will look for the resources.neu file which contains the config and app files and go from there. In the absence of a resources.neu file the binary will look for a co-located config file (neutralino.config.json) which will define the url of the app files and client library.
In the case of Lin/Win these files are likely to be co-located within the app folder but Mac is a bit different.

   MacOS:
Mac uses an app bundle rather than a monolithic executable so the binary produced by Neu should be in the MacOS folder of the package and the app files in the co-resident Resources folder.
In this case the server binary needs to be told where to find the config and app files - this can be done using a boot script in MacOS.
When the Mac app is double-clicked the Info.plist file is checked for the executable of the package. Normally this would be the binary directly but because we need the script to set the resources path the executable script will be specified. The boot script starts the server binary and uses the --path argument to define the location of the config/app files (otherwise the binary would just look in the MacOS folder for the resources.neu or config file).

Note: If .app is appended to the Neu produced binary it will act like a Mac app (no terminal window) but is not really the right structure (should be a folder bundle). Without the .app the binary will run via a terminal window.

Typical compile times for the server binary will vary by machine. The time taken for the CLI repo to produce a package is quite quick because the binaries are just copied not compiled.

iMac i7 40G RAM 10.13 - c. 40 seconds

MacBookPro Core 2 Duo 8G RAM 10.14 - c. 120 seconds

:: browser ::


:: cloud ::

:: chrome ::

May be of use but not a replacement for native window since the Native API doesn't really work (based on Lorca project code).
Using this mode will add c. 30M to the application bundle size since it creates a hidden .tmp/chromedata folder within the resources folder. Ideally this tmp folder should be located outside the app bundle to avoid runtime changes to the app package.



Project Building



MacOS:

   Neutralino will produce executable binary along with a resources.neu file. The resources.neu file is essentially the app files all bundled with Rollup.js which also gives a measure of code protection if so desired.

   In the absence of a builder/packaging utility a Mac app package can be built manually.

   If bundling of the app resources is not required (ie: no resources.neu file needed) then along with the app files/resources the only files needed from Neu are server binary, client library and config file.
   In this case neutralinojs-CLI is not really required since the server binary is either prebuilt or built from the main repository and the client library is either prebuilt or built from the client repository. The config file is just an editable json file.



Important Changes



Server/Client version:

2.1.0 - http server code replaced - licence --> MIT

2.2.0 - Unified platform codebase

2.3.0 - New window properties

2.4.0/1.0.0 - Tray menu implemented

2.5.0/1.1.0 - Window enhancements (isFullscreen, setFullscreen)

2.6.0/1.3.0 - Draggable region support, 32bit builds on all platforms

2.7.0/1.4.0 - app.exit(), windowClose revision

2.8.0/1.5.0 - NL_PID global added, Multiple windows creation, 32bit ARM port

3.0.0/2.0.0 - (breaking changes) JS API recoded, dialog code changed, API via WebSocket, draggability code changed

4.0.0/3.0.0 - (big release) Extension API support added, WebSocket ready event changes, Linux ARM64 support, NL_APPVERSION added

4.1.0/3.0.0 - Chrome mode added

4.2.0/3.1.0 - Clipboard text API added, custom HTTP headers support, NL_RESMODE added

4.3.0/3.10 - TOKEN security enhanced, enhanced window API, NL_EXTENABLED added

4.4.0/3.3.0 - window.getPosition added, filesystem API enhancements

4.5.0/3.4.0 - window.Focus and window.Blur added, BuildZri used for binary builds, writeBinaryFile fix

4.6.0/3.5.0 - Process spawning API added, getStats create/modify date enhancements, URL query parameter support

4.7.0/3.6.0 - infoware library enhancements for .computer API, defaultPath added to file dialogs

4.8.0/3.7.0 - os.getEnvs, storage.getKeys, computer.getMousePosition added, readFile/readBinaryFile partial content support

4.9.0/3.8.0 - API Custom methods (BE), File Streams

4.10.0/3.8.2 - ESM/NPM support

4.11.0/3.9.0 - File watcher API, binary file append fixed

4.12.0/3.10.0 - window.center API added, window centering config, Unicode support for Windows

4.13.0/3.11.0 - Persistent main window state, NL_WSAVSTLOADED global variable added

4.14.0/3.12.0 - filesystem.getWatchers added, binary file reading updates, cwd parameter added



Application Package Renaming



The app binary name can be changed and will be reflected within the process view as long as references to the binary are updated (eg: Info.plist file).
Assume app is called Hippo - (showing main window and subwindow)

Processes ::

  Hippo    PID 1899    (App name as specified in Info.plist)    Main Window
  Hippo    PID 1915    (App name as specified in Info.plist)    Subwindow
  hippo Networking    PID 1905    (hippo being the binary name within the Mac App bundle)
  hippo Networking    PID 1917    (hippo being the binary name within the Mac App bundle)
  http://localhost:52796    PID 1904    (port set to 0 in config)
  http://localhost:52813    PID 1916    (port set to 0 in config)





Binary Compiling



The supplied server binaries are built for MacOS 11 or later but the binary can be built for earlier OS's (eg: Catalina/Mojave/High Sierra). Possibly the devs don't have access to a Mac earlier than 11 to do the builds.

:: Server binary ::   (Repo is https://github.com/neutralinojs/neutralinojs)

v4.5.0 or later -

Need python3 installed on Mac then -   (Build uses python based BuildZri)

git clone https://github.com/neutralinojs/neutralinojs.git
--> Cloning into 'neutralinojs'...
cd neutralinojs
./scripts/bz.py
--> ascii splash
--> Compiling Neutralinojs...
--> OK: Neutralinojs compiled into ./bin/neutralino-mac_x64

If rebuilding a server binary from a standard release then the release client library (neutralino.js) should be OK to use otherwise both the server and client binaries need to be built. Building the client library is documented in the client repo under Developer FAQ - also uses git clone method.

Build on iMac i7 takes c. 40 seconds.

v4.4.0 or earlier -

git clone https://github.com/neutralinojs/neutralinojs.git or just download zipped source
--> Cloning into 'neutralinojs'...
cd neutralinojs
bash build_macos.sh
--> ascii splash
--> Compiling Neutralinojs...
--> OK: Neutralinojs compiled into ./bin/neutralino-mac_x64

Note: Adding .app to the server binary will not produce a normal app package but will sort of work. The server binary is the executable file that would normally be found in the MacOS folder of a normal Mac App bundle which would then contain Info.plist, etc.


:: Client Library ::   (Repo is https://github.com/neutralinojs/neutralino.js)

git clone https://github.com/neutralinojs/neutralino.js.git
--> Cloning into 'neutralino.js'...
cd neutralino.js
npm install
npm run build



Widevine Support






Window/Process Management




Window Management:

Normally this is mainly done implicitly by the OS/runtime however with Neutralino it is a bit different.

With Neutralino windows the Minimize button and Fullscreen button are implicit but the Close button is not. The Close button is controlled via the modes.window.exitProcessOnClose setting in the config file.
Set to true the app process will exit as normal but set to false the framework just issues a windowClose event which is then handled in user code. This allows some interim handling (cleanup) code to be run before app.exit() is called.
Also in the case of subwindows being opened the windows are more or less separate instances from the app so if the main app should exit then orphaned windows will occur unless handled in app code (the window.create() command uses the execCommand() API to open the window).

The lack of implicit functionality between windows in a multi-window app means some careful coding has to be implemented by the user.

At the moment two approaches seem possible - using the storage API or the extension API.

Extension API - this allows communication between the app and extension using WebSocket, I have managed to get it going and create an sqlite database but still a WIP for a practical app. No real world examples with Neutralino have surfaced yet.

Storage API - this is relatively straightforward and allows me to solve the orphaned window problem.

    :: Method ::

Every HTML page must have access to the Neutralino Client Library (neutralino.js) and an associated main.js file will handle any implicit type of code (eg: window control/tray/etc).
I keep these files in a folder called neuclientlib in the root of the Resources folder.

    <script src="neuclientlib/neutralino.js"></script>
    <script src="neuclientlib/main.js"></script>

Main native app window (usually index.html) - use exitProcessOnClose set to false in neutralino.config.json file, the app will use the windowClose event in the main.js file.
When the app closes checks for existing subwindows are done and closed if necessary - the main app will then close.
    The sub-window check is done by looking up the subWins array in storage which should have the PID that was stored (using the storage API) when the subwindow was opened.
In current versions of Neutralino the PID is returned by the createWindow API (v2.8.0 - the PID would have to be supplied by the window HTML) so this should be OK for windows that may not have HTML/JS content (eg: .pdf).
If a subwindow is closed it will remove the PID from the stored array.
Process Management:

This is a result of using the execCommand API to start remote processes. Can get a bit tricky but generally the execCommand will return a PID which in most cases could be stored and used for closing windows/processes.


Extensions


WIP


execCommand API



execCommand is Neutralino's method of using child processes which allows command line executables to be run. As of v4.6.0 a streaming type of return is handled using the spawnProcess API.
eg: continuous ping

If a server is started then the background option should be set TRUE - this avoids blocking the Native API of the app and the child process will continue as a standalone process.



eg: Possible server examples using execCommand include -

    Node Express server - use a packaged executable containing Node and the Express modules (I find CAXA works very well but will add c. 30M of code to the app build) (MIT).

    RAN server - standalone executable with CLI args (MIT) (https://github.com/m3ng9i/ran)

    PHP server - uses installed PHP (note: later MacOS releases no longer bundle PHP)

    SUXM server - standalone executable with CLI args (Apache 2.0) (https://github.com/isurfer21/Suxm)

    Static-Web-Server server - standalone executable with CLI args (Apache 2.0) (https://github.com/joseluisq/static-web-server)

    SFK server - standalone executable with CLI args (Personal Use) (http://stahlworks.com/dev/swiss-file-knife.html)

    Http-server server - use a packaged executable containing Node and the http-server modules (MIT) (https://github.com/http-party/http-server)


Packaging tools for executables include -

    Caxa - allows packaging of Node into executable along with node modules. (MIT) (https://github.com/leafac/caxa)
    The inclusion of node adds about 30M of payload but is OK if it allows for a function that Neutralino will not do - node module bloat shouldn't be too much of a problem unless there are a large number required for the app.


Databases


Client side SQLite database can be used easily with sql.js (using WASM files).

WIP - currently issues with size of database allowed
    Pros:
    Does not require server environment (eg: node).
    Two files to be referenced (sql-wasm.js and sql-wasm.wasm).

    Cons:
    Needs to load entire database into memory - does not work directly with sqlite file.
    Need to export on changes to file for persistence.
    Limited subset of normal SQLite API commands.



UI Design - Widgets



At this stage widget style apps are not feasible if they require transparency which is currently not implemented in the native windows (it is in the 2022 roadmap but don't hold your breath as it apparently quite tricky to implement - it works with Chromium in NW.js but it ain't easy!).

Draggable elements are possible so really just waiting for transparency.


UI Design - Desktop Style




The app content of the window generally should not be subject to swiping actions as per the web world so overflow: hidden; against the body tag can be used to make the window content solid.

Pollution of the app UI by dragged files/objects, as outlined above, is avoided using the same method as for widgets.




expander -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- expander