WebPlus adds super powers to web applications and strives to be easy to setup, easy to use, produce small distributions, and require no compilation.
β:zap: Hot reloading for instant visual feedback during development.
β:zap: Setting window icon and title.
β:zap: Window resizing and repositioning.
β:zap: Window minification to system tray.
β:zap: Fullscreen and frameless window toggling.
β:zap: True window resize event pumping.
β:zap: Dialogs to select files and folders.
β:zap: Loading and saving text files.
β:zap: Saving PNG images.
β:zap: Renaming, moving, and deleting files.
β:zap: Creating, renaming, moving, and deleting directories.
β:zap: Persistent state.
β:zap: Base distribution size of 790KB.
v1.0.0 (7 Nov 2023)
β:bulb: Initial release.
I really enjoy creating web applications using HTML, CSS, and JavaScript.
Sadly "web apps" have no access to the local file system, because of security. This issue can be solved by using currently available frameworks, so I tried a bunch of them, ElectronJS, NWjs, CEFSharp, Tauri, and Neutralino.
Some of them created gigantic distributions (90Mb+) and others had unresolvable issues, so I just decided to write my own.. WebPlus.
WebPlus was created for my own personal use and is publicly availabe in case anyone finds it interesting or of use. It does not strive to compete with other framework that provide similar functionality, and comparing WebPlus to other frameworks is like comparing an abacus with an electronic calculator.
WebPlus is also only works with Windows because I don't have any Apple or Linux stuff, sorry.
If you create something using WebPlus, please let me know, I'd love to see what you do with it. Maybe you would also consider buying me a coffee β
All you really need is a text editor but if you want to build your own binary you will need Visual Studio.
Lets make an app called MyCoolApp.
β:one: Copy the "dist" folder somewhere handy and rename it as "MyCoolApp".
β:two: Rename the WebPlus.exe file to "MyCoolApp.exe".
β:three: Run the "MyCoolApp.exe" file and an empty grey window will magically appear.
β:four: Edit "app.html", "style.css", and "app.js" inside the "app" folder. Saving them will update the app view.
β:five: Rinse and repeat :four: until your app is done.
β:six: Set HotReload to false in the "app\app.json" file to disable hot reloading.
β:seven: Delete the "MyCoolApp.WebView" folder. This is a temprorary cache folder that isn't required for distribution.
β:eight: Perform extra tasks such as minifying or obfuscating your code, etc.
β:nine: Replace the "icon.ico" with your own icon, and then you're ready to commence distribution.
That's it, you're done.. time for a beverage β π΅ πΆ πΌ πΊ π» πΈ πΉ π·
For all intents and purposes WebPlus is a just a WebView2 control that fills the client area of a Windows Form, with a host object coclass glued on to provide some extra functionality. Hot reloading is provided using a FileSystemWatcher.
When a WebPlus application launches, it..
- Creates a windows containing a WebView2 control.
- Loads persistent options from "app/app.json".
- Modifies the windows form according to the options.
- Loads "app/app.html" into the WebView2 control.
When "app/app.html" has fully loaded the window.onload event in "app/app.js" is fired, which starts the app running.
The default icon provided inside the "app" folder contains with sizes of 16x16, 24x24, 32x32, 48x48, and 256x256, which are considered the bare minimum any icon should contain.
π I was delighted at how easy it was to actually get a WebView2 set up and working inside Visual Studio.. finally Microsoft made something that didn't have me cursing loudly and tearing at what little hair I have left π
WebPlus stores its persistent state in a the "app/app.json" file which has the following structure..
{ HotReload: {Boolean}, SaveOnExit {Boolean}, // Set to disable persistent state. Title: {String} // Window title. X: {Number}, // Window position Y: {Number}, Width: {Number}, // Window dimensions. Height: {Number}, FullScreen: {Boolean}, // The remaining properties are not yet implemented. Frameless: {Boolean}, Minimized: {Boolean}, MinimizeToTray: {Boolean}, } π Remember to set HotReload to false before distributing your app.
WebPlus provides a number of global variables that you might find useful...
The WebPlus object that encapsulates all methods that can be called on the host.
The cached host (window.chrome.webview.hostObjects.sync.hostedObject).
The applications home directory.
True if the application window is currently in full-screen mode.
True if the application window has no frame.
True when app window will minimize to the system tray.
True if the application is currently in hot-reload mode.
A pre generated filetype filter for TEXT files.
A pre generated filetype filter for JSON files.
A pre generated filetype filter for PNG files.
Some WebPlus methods return objects, and others may require you to supply an object. These objects are...
{ name: {String}, // Name of file, including extension. extension: {String}, // Forced to lowercase. type: {String}, // "FILE", "DIRECTORY", or "UNKNOWN". size: {Number}, // Size in bytes. path: {String}, // Directory where file is stored. fullPath: {String}, // Fully qualified file path. } type of "UNKNOWN" will be present when saveFileDialog was called and the user entered the name of a file that doesn't exist "yet".
{ filter: {String}, // A File Dialog Filter. multiSelect: {Boolean}, // Set to true to enable multiple file selection. title: {String} // Dialog title. } π WebPlus includes some handy file dialog filters for common filetypes.. WP_TEXTFILE_FILTER for for TEXT files, WP_JSONFILE_FILTER for JSON files, and WP_PNGFILE_FILTER for PNG files.
You can subscribe to the "windowresize" event in your app to receive notifications when your apps window resizes.
window.addEventListener('windowresize', (e) => { console.log(`windowresize: ${e.detail}`); }); The events `detail`` property will contain a string describing what type of resize event just occurred, and it will be one of the following:
β:small_orange_diamond: "windowEnteredFullScreen"
β:small_orange_diamond: windowLeftFullScreen"
β:small_orange_diamond: windowRestored"
β:small_orange_diamond: windowMinimized"
β:small_orange_diamond: windowMaximized"
π¨ Code for asynchronous messaging between the app and host is included in the various source code files (and this readme) but has been commented out because making use of this code means editing the C# source and recompiling the binaries. This is not how I intend for WebPlus to work and not something I personally require. Hoswever I have left the code in situ incase anyone else wants that functionality and can be bothered messing about with it.
All callable host methods are encapsulated inside the wp object and you call them the same way you would a class, so if you wanted to set the windows title to "WebPlus Rocks" you would use the following code:
wp.setWindowTitle("WebPlus Rocks"); Exit the application.
Enable or disable hot reloading according to the given state.
πΉ parameter {Boolean} state
Get the applications folder.
πΈ returns {String}
Get the last error encountered by the host. Useful for determining why some method or another failed.
πΈ returns {String}
Set the host window location to the given coordinates.
πΉ parameter {Number} x
πΉ parameter {Number} y
Set the host window size to the given dimensions.
πΉ parameter {Number} width
πΉ parameter {Number} height
Set the host window title to the given title.
πΉ parameter {String} title
Set the host window icon to the given path pointing to a .PNG or .ICO file.
πΉ parameter {String} path
Set the host window to minify to the system tray instead of the task bar according to the given state.
πΉ parameter {Boolean} state
Enter or leave fullscreen mode according to the given state.
πΉ parameter {Boolean} state
Remove or add window frame according to the given state.
πΉ parameter {Boolean} state
Get the FileDetails for the file or directory at the given path.
πΉ parameter {String} path
πΈ returns {FileDetails}
Delete the file with the given path.
πΉ parameter {String} path
Rename the file with the given path to the given name.
πΉ parameter {String} path
Get an array of FileDetails for all files and directories in the given path.
πΉ parameter {String} path
πΈ returns ([FileDetails])
Create a directory with the given path.
πΉ parameter {String} path
Recursively delete the directory with the given path.
πΉ parameter {String} path
Rename the directory with the given path to the given name.
πΉ parameter {String} path
Using the given options, display an open file dialog where a file can be selected, and return its FileDetails if it wasn't cancelled.
πΉ parameter {DialogOptions} options
πΈ returns {FileDetails}
Using the given options, display a save file dialog where a file can be selected, and return its FileDetails if it wasn't cancelled.
πΉ parameter {DialogOptions} options
πΈ returns {FileDetails}
Display a dialog where a folder can be selected, and return its FileDetails if it wasn't cancelled.
πΈ returns {FileDetails}
Load the text file with the given path.
πΉ parameter {String} path
πΈ returns {String}
Browse for a text file using a OpenFileDialog, and if not cancelled, load the selected text file.
πΉ parameter {DialogOptions} options
πΈ returns {String}
Save the given text to the file at the given path.
πΉ parameter {String} text
πΉ parameter {String} path
Browse for a text file using a SaveFileDialog, and if not cancelled, save the given text to the selected file.
πΉ parameter {String} text
πΉ parameter {DialogOptions} options
Save the given canvas as a PNG image at the given path.
πΉ parameter (HTMLCanvasElement) canvas
πΉ parameter {String} path