The TinyJS Page

A bit of a run down of the experience I have had with using TinyJS

General:

The backend of TinyJS is based on txiki.js using the system webview for the frontend allowing apps to be developed with HTML/JS/CSS on the frontend and use JS on the backend. The final size of bundled apps can be very small as the runtime/backend components of TinyJS are very small (c. 7M) and use of the system webview avoids the need to ship Chromium or CEF.
Apps are bundled using TinyJS using stock binaries and the app files are located in the Resources/app folder. There is no compilation into a single executable binary and the app files are not encoded.


The biggest hassle with all these app builders is the need to bridge backend to frontend contexts but this is not a big showstopper with TinyJS. As with Deno Desktop a FS API does need to be coded in the frontend as the FS API exists in the backend using txiki.js however the mechanism to do it is reasonably simple given the backend offers methods to extend the API into the frontend.

All in all I am extremely impressed with TinyJS and still trying to find any major downsides - small binaries, easy building, good backend feature set via txiki.js

Did I say I am impressed with TinyJS? - yes indeed I am - as an example the biggest hassle I found was the hard-coded credits message in the About menu box.
Solution: edit the launcher-macos.cc file in the original source and rebuild new binaries via ./setup.sh - removing the hard-coded credit text allowed the About menu to make use of the Credits.html file in the Resources folder which of course is default MacOS behaviour. UPDATE: a contributor did a PR for this and is now fixed - I love this distro.

The brain dump (if you can call it that) .... (with the fullness of time this should grow)

:: Top Tips ::

Dev/Production detection -

I wanted to detect if the app was running in Dev or Prod - an easy way on macOS is to check for the icon.icns file in the Resource folder of the macOS app package.
During Prod the AppIcons.icns file will be in the bundle Resources folder but the folder will not exist when running DEV build

eg:

try {
    //PROD
    var fileExists = await Deno.readFile(... + 'Resources/AppIcon.icns');
} catch(e) {
    // DEV
    ...
}


Retina Screen sizing on Macs -

Window settings for X, Y, width and height will be doubled when shown on screen eg: width of 200 will be 400 actual pixels on retina screen.
A window created with no width/height settings will default to 800 x 600 and show onscreen as 1600 x 1200


:: Install ::

% cd TinyDev

% curl -fsSL https://tinyjs.app/install | sh
==> downloading tinyjs v0.42.0 (arm64)
==> verifying checksum
==> installing to /Users/USER/.tinyjs
==> installed: tinyjs v0.42.0 (txiki.js 26.6.0)
    linked /Users/USER/.local/bin/tinyjs -> /Users/USER/.tinyjs/tinyjs

/Users/USER/.local/bin is not on your PATH. Add it to /Users/USER/.zshrc? [Y/n] Y

Added /Users/USER/.local/bin to your PATH in /Users/USER/.zshrc.
Open a NEW terminal (or run the line below) before using tinyjs:

export PATH="/Users/USER/.local/bin:$PATH"

get started (in a new terminal): tinyjs new myapp && cd myapp && tinyjs dev
%



:: Create project ::

Open new Terminal (Home folder)

% cd TinyDev

% tinyjs new simpleapp
created simpleapp/
cd simpleapp
tinyjs dev # run it
tinyjs build # package it
%


simpleapp folder -

    icon.png
    jsconfig.json (manual update after tinyjs update)
    tinyjs.json (manual update after tinyjs update)
    src -
        main.js
        frontend -
            app.js
            index.html
            style.css
    types -
        tiny.d.ts (needs update after tinyjs update)
        tjs.d.ts (needs update after tinyjs update)
    dist -    (Appears after build done)



:: Dev ::

% tinyjs dev (opens sensible demo window)
tinyjs: v0.42.1 is available (you have v0.42.0) — run `tinyjs update`


:: Update tinyjs ::

% tinyjs update
==> updating v0.42.0 → v0.42.2
==> downloading tinyjs v0.42.2 (arm64)
==> verifying checksum
==> installing to /Users/USER/.tinyjs
==> installed: tinyjs v0.42.2 (txiki.js 26.6.0)
    linked /Users/USER/.local/bin/tinyjs -> /Users/USER/.tinyjs/tinyjs
    (/Users/USER/.local/bin is already on your PATH — a good home for it)

If this terminal says `tinyjs: command not found`, run `hash -r`
(or just open a new terminal) so your shell sees the new command.

get started:    tinyjs new myapp && cd myapp && tinyjs dev


Note: The update only updates the hidden tinyjs repository so version related files that are included in app projects already existing will need to be updated.
The easiest way of doing this would appear to be to create a new app project with the updated tinyjs and move all the app related files into the new structure.
Files affected -
    jsconfig.json
    tinyjs.json
    types folder


:: Build ::

will use the stock tinyjs repo located in the .tinyjs folder of the home dir.

% tinyjs build
==> compiling backend
Compiled /Users/USER/TinyDev/simpleapp/dist/simpleapp (build 0dfa1ea3218240979726c72581b869ea)
==> assembling simpleapp.app
==> generating icon from icon.png
==> codesigning (ad-hoc)
==> runs on: Apple Silicon (arm64)
note: won't open on Intel Macs — tjs has no x86_64 slice.
     Build an Intel copy with --arch x86_64, or one app for both with --universal.
==> done -rwxr-xr-x 1 USER staff 3.0M 28 Sep 19:35 dist/launcher
-rwxr-xr-x 1 USER staff 5.7M 28 Sep 19:35 dist/simpleapp
run it: ./dist/simpleapp (or open "dist/simpleapp.app")
%



Build creates dist folder in project root.

dist -

    launcher
    simpleapp
    simpleapp.app
        Contents -
            Info.plist
            _CodeSignature
                CodeResources
            MacOS
                simpleapp
                tjs
            Resources
                AppIcon.icns
                app -
                    app.json
                    bridge.js
                    entry.js
                    update.js    (updater)
                    frontend -    (app files)
                        app.js
                        index.html
                        style.css
                    src -
                        main.js    (backend - runs on txiki.js)
    frontend -
        app.js
        index.html
        style.css


:: Build from source ::    (generates TJS binary)

generates tjs binary in bin folder and launcher-macos binary in native folder of the source repo.

% ./setup.sh
==> downloading txiki.js v26.6.0 (arm64)
==> compiling launcher
==> compiling without on-device AI (no FoundationModels in this SDK)
xcode-select: note: No developer tools were found, requesting install.
If developer tools are located at a non-default location on disk, use `sudo xcode-select --switch path/to/Xcode.app` to specify the Xcode that you wish to use for command line developer tools, and cancel the installation dialog.
See `man xcode-select` for more details.

After Command Line Tools installed -

% ./setup.sh
==> compiling launcher
==> compiling with on-device AI (FoundationModels found in the SDK)
==> done
v26.6.0
try: ./tinyjs new hello && cd hello && ../tinyjs dev



:: Shelf ::

Useful app that contains a curated list of apps that can be installed (within shelf app structure) and used to demo tinyjs functionality.


:: General ::

main.js based in backend and used for linking frontend.

tjs.whatever - used in backend but accessible from frontend via api.


api is an exported constant containing functions that are available from frontend pages.

eg:    (FE)

var result = await tiny.api.call('readFileHead', { path: `${DESKTOP}/samplefile.txt`})
console.log('returnedDataFromBE', result);



init(app) is an exported function which allows events to be pushed to the page.

eg:    (BE)

app.setTitle("NewWindowTitle");



:: File I/O ::

Done via tjs on backend so need to setup linking functions in main.js using the api constant for frontend use.

eg:    (BE)

async readTextFile({ path }) {
const bytes = await tjs.readFile(path);
const text = new TextDecoder().decode(bytes);
return text;
},


(FE)

var result = await tiny.api.call('readTextFile', { path: `${DESKTOP}/samplefile.txt`})
console.log('returnedDataFromBE', result); // content of text


:: Config Parameters :: (tinyjs.json)

































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