Writing native Linux desktop apps with JavaScript Philip Chimento •   ptomato •  @therealptomato Linux Application Summit, May 13, 2021 Image by Сергей Корчанов from Pixabay
Introduction I maintain GJS (GNOME JavaScript) This talk is a bit of an experiment for me Can web JS programmers ramp up quickly on writing a desktop app?
What this talk is For JavaScript developers and enthusiasts who are curious about writing a desktop app A walk through creating and publishing a desktop app in JS Technologies: GJS, GTK, Flatpak, Flathub A slide deck that you can read later https://ptomato.name/talks/las2021/
What this talk is not A step-by-step tutorial on how to write an app There's already a good one on gjs.guide Presented by an experienced web developer
Let's get started! Image CC0 licensed
App: "Bloatpad" the unnecessary note-taking app
Have something to start with Can also use gtk-js-app
a Meson build system a placeholder icon resource bundles a .desktop file a settings schema an AppStream meta info file infrastructure for i18n skeleton code a Flatpak manifest
Build systems Meson is probably a good one to stick with You will need it if your app ever includes any C code Coming from JS development you still might want something more familiar $ yarn init "scripts": { "prebuild": "test -d _build || meson _build", "build": "ninja -C _build", "start": "meson compile -C _build devel", "test": "meson test -C _build" }
Yarn $ yarn build $ yarn start
Linter May as well install prettier and never again worry about code style eslint for usage $ yarn add --dev prettier eslint eslint-config-prettier "lint": "eslint . --fix && prettier --write ."
TypeScript You can write in TypeScript, it mostly works Or write JS with type annotations in comments and use TypeScript to typecheck Thanks to the hard work of Evan Welsh
Other build tools Bundlers are probably not needed Tree shaking can be useful use e.g. find-unused-exports Minifiers are probably not needed Babel probably works
Assembling the UI Photo by Anna Shvets from Pexels
XML UI files or no? XML-CSS-JS is like the trinity of HTML-CSS-JS Alternative is to build your UI in code
XML UI files or no? <object class="GtkListView" id="notesList"> <property name="show-separators">True</property> <signal name="activate" handler="_onNotesListActivate"/> </object> vs. this._notesList = new Gtk.ListView({ showSeparators: true }); this._notesList.connect("activate", this._onNotesListActivate.bind(this));
XML UI files Tedious to write by hand Glade UI Designer GTK 3 only GTK 4 alternative underway
Result
CSS .large-icon { color: #888a85; -gtk-icon-shadow: #d3d7cf 1px 1px; padding-right: 8px; }
CSS
Time to write code Image CC0 licensed
API Documentation gjs-docs.gnome.org
About the API Every UI element is based on Gtk.Widget Roughly equivalent to a HTML DOM element Methods Properties Signals (events) CSS element name and classes Things that are not UI elements are based on GObject.Object
ES modules import Gdk from "gi://Gtk"; import Gio from "gi://Gio"; import GObject from "gi://GObject"; import Gtk from "gi://Gtk"; import { NotesListItem } from "./item.js";
Async operations GNOME platform has asynchronous, cancellable I/O Experimental opt-in support for JS await Gio._promisify(Gio.OutputStream.prototype, 'write_bytes_async', 'write_bytes_finish'); // ... let bytesWritten = 0; while (bytesWritten < bytes.length) { bytesWritten = await stream.write_bytes_async(bytes, priority, cancellable); bytes = bytes.slice(bytesWritten); }
Popular runtime libraries These may or may not work Check if you actually need the dependency Use ES module directly if it doesn't have other deps Some modules ship a browser bundle, this might work Else, build a UMD bundle with Browserify and vendor it
Build a UMD bundle with browserify yarn add my-library mkdir -p src/vendor npx browserify -r my-library -s myLibrary -o src/vendor/my-library.js import './vendor/my-library.js'; // myLibrary is now a global object
Top 5 most used NPM libraries 1. lodash 2. chalk 3. request 4. commander 5. react
Lodash In some cases not necessary Use lodash-es if you need lodash import _ from './vendor/lodash-es/lodash.js'; _.defaults({ 'a': 1 }, { 'a': 3, 'b': 2 });
Chalk No bundle, so make a Browserified one Color support detection code is Node-only Edit bundle, change stdout: false and stderr: false to true import './vendor/chalk.js'; print(chalk.blue('Hello') + ' World' + chalk.red('!'));
Request Deprecated Use Soup instead const request = require('request'); request('https://ptomato.name', function (error, response, body) { console.error('error:', error); console.log('statusCode:', response && response.statusCode); console.log('body:', body); }); import Soup from 'gi://Soup'; const session = new Soup.Session(); const msg = new Soup.Message({ method: 'GET', uri: new Soup.URI('https://ptomato.name') }); session.queue_message(msg, (_, {statusCode, responseBody}) => { log(`statusCode: ${statusCode}`); log(`body: ${responseBody.data}`); });
Commander No bundle, so make a Browserified one import System from 'system'; import './vendor/commander.js'; const { Command } = commander; const options = new Command() .option('-p, --pizza-type <type>', 'flavour of pizza') .parse(System.programArgs, { from: 'user' }) .opts(); // ^^^^^^^^^^^^ if (options.pizzaType) print(`pizza flavour: ${options.pizzaType}`);
React Not applicable P.S. Although it would be cool if React Native worked with GTK
Fast-forward to the written code (Live demo, but in case that doesn't work out, screenshots follow) Image CC0 licensed
Distributing your app to users Image by acebrand from Pixabay
How? Flathub Requirements Luckily, the generated project skeleton meets all of these Only need to fill in a few things
AppStream meta info This file is used to provide the description that users see on Flathub And in their software updater appplication Description of file format
AppStream meta info Generator to get you started Asks you a few questions Asks for URLs of screenshots Flathub guidelines OARS rating OARS Generator
Desktop file Tells how to display your app in the desktop Description of file format List of categories [Desktop Entry] Name=Bloatpad Comment=Unnecessary note-taking application Exec=name.ptomato.Bloatpad Icon=name.ptomato.Bloatpad Terminal=false Type=Application Categories=Utility;GTK; StartupNotify=true
Application icon Tobias Bernard on Designing an Icon for your App
Submit it to Flathub Instructions here
Translate your UI Gettext is built-in to the platform Venerable framework for UI translations Use a website like Transifex Recruit volunteer translators Or translate the UI yourself in whatever languages you speak
Conclusion Some things might seem familiar to JS developers, others might not We should reduce the friction for these developers But not everything from the web or Node.js applies well to the desktop
Questions Image by IRCat from Pixabay
Thanks Andy Holmes, Evan Welsh, Sri Ramkrishna for discussions and their work on improving the GJS developer experience License Presentation licensed under Creative Commons BY-NC-ND 4.0 Bloatpad code, permissive MIT license

Writing native Linux desktop apps with JavaScript

  • 1.
    Writing native Linuxdesktop apps with JavaScript Philip Chimento •   ptomato •  @therealptomato Linux Application Summit, May 13, 2021 Image by Сергей Корчанов from Pixabay
  • 2.
    Introduction I maintain GJS(GNOME JavaScript) This talk is a bit of an experiment for me Can web JS programmers ramp up quickly on writing a desktop app?
  • 3.
    What this talkis For JavaScript developers and enthusiasts who are curious about writing a desktop app A walk through creating and publishing a desktop app in JS Technologies: GJS, GTK, Flatpak, Flathub A slide deck that you can read later https://ptomato.name/talks/las2021/
  • 4.
    What this talkis not A step-by-step tutorial on how to write an app There's already a good one on gjs.guide Presented by an experienced web developer
  • 5.
  • 6.
  • 7.
    Have something tostart with Can also use gtk-js-app
  • 8.
    a Meson buildsystem a placeholder icon resource bundles a .desktop file a settings schema an AppStream meta info file infrastructure for i18n skeleton code a Flatpak manifest
  • 9.
    Build systems Meson isprobably a good one to stick with You will need it if your app ever includes any C code Coming from JS development you still might want something more familiar $ yarn init "scripts": { "prebuild": "test -d _build || meson _build", "build": "ninja -C _build", "start": "meson compile -C _build devel", "test": "meson test -C _build" }
  • 10.
  • 11.
    Linter May as wellinstall prettier and never again worry about code style eslint for usage $ yarn add --dev prettier eslint eslint-config-prettier "lint": "eslint . --fix && prettier --write ."
  • 12.
    TypeScript You can writein TypeScript, it mostly works Or write JS with type annotations in comments and use TypeScript to typecheck Thanks to the hard work of Evan Welsh
  • 13.
    Other build tools Bundlersare probably not needed Tree shaking can be useful use e.g. find-unused-exports Minifiers are probably not needed Babel probably works
  • 14.
    Assembling the UI Photoby Anna Shvets from Pexels
  • 15.
    XML UI filesor no? XML-CSS-JS is like the trinity of HTML-CSS-JS Alternative is to build your UI in code
  • 16.
    XML UI filesor no? <object class="GtkListView" id="notesList"> <property name="show-separators">True</property> <signal name="activate" handler="_onNotesListActivate"/> </object> vs. this._notesList = new Gtk.ListView({ showSeparators: true }); this._notesList.connect("activate", this._onNotesListActivate.bind(this));
  • 17.
    XML UI files Tediousto write by hand Glade UI Designer GTK 3 only GTK 4 alternative underway
  • 18.
  • 19.
    CSS .large-icon { color: #888a85; -gtk-icon-shadow:#d3d7cf 1px 1px; padding-right: 8px; }
  • 20.
  • 21.
    Time to writecode Image CC0 licensed
  • 22.
  • 23.
    About the API EveryUI element is based on Gtk.Widget Roughly equivalent to a HTML DOM element Methods Properties Signals (events) CSS element name and classes Things that are not UI elements are based on GObject.Object
  • 24.
    ES modules import Gdkfrom "gi://Gtk"; import Gio from "gi://Gio"; import GObject from "gi://GObject"; import Gtk from "gi://Gtk"; import { NotesListItem } from "./item.js";
  • 25.
    Async operations GNOME platformhas asynchronous, cancellable I/O Experimental opt-in support for JS await Gio._promisify(Gio.OutputStream.prototype, 'write_bytes_async', 'write_bytes_finish'); // ... let bytesWritten = 0; while (bytesWritten < bytes.length) { bytesWritten = await stream.write_bytes_async(bytes, priority, cancellable); bytes = bytes.slice(bytesWritten); }
  • 26.
    Popular runtime libraries Thesemay or may not work Check if you actually need the dependency Use ES module directly if it doesn't have other deps Some modules ship a browser bundle, this might work Else, build a UMD bundle with Browserify and vendor it
  • 27.
    Build a UMDbundle with browserify yarn add my-library mkdir -p src/vendor npx browserify -r my-library -s myLibrary -o src/vendor/my-library.js import './vendor/my-library.js'; // myLibrary is now a global object
  • 28.
    Top 5 mostused NPM libraries 1. lodash 2. chalk 3. request 4. commander 5. react
  • 29.
    Lodash In some casesnot necessary Use lodash-es if you need lodash import _ from './vendor/lodash-es/lodash.js'; _.defaults({ 'a': 1 }, { 'a': 3, 'b': 2 });
  • 30.
    Chalk No bundle, somake a Browserified one Color support detection code is Node-only Edit bundle, change stdout: false and stderr: false to true import './vendor/chalk.js'; print(chalk.blue('Hello') + ' World' + chalk.red('!'));
  • 31.
    Request Deprecated Use Soup instead constrequest = require('request'); request('https://ptomato.name', function (error, response, body) { console.error('error:', error); console.log('statusCode:', response && response.statusCode); console.log('body:', body); }); import Soup from 'gi://Soup'; const session = new Soup.Session(); const msg = new Soup.Message({ method: 'GET', uri: new Soup.URI('https://ptomato.name') }); session.queue_message(msg, (_, {statusCode, responseBody}) => { log(`statusCode: ${statusCode}`); log(`body: ${responseBody.data}`); });
  • 32.
    Commander No bundle, somake a Browserified one import System from 'system'; import './vendor/commander.js'; const { Command } = commander; const options = new Command() .option('-p, --pizza-type <type>', 'flavour of pizza') .parse(System.programArgs, { from: 'user' }) .opts(); // ^^^^^^^^^^^^ if (options.pizzaType) print(`pizza flavour: ${options.pizzaType}`);
  • 33.
    React Not applicable P.S. Althoughit would be cool if React Native worked with GTK
  • 34.
    Fast-forward to thewritten code (Live demo, but in case that doesn't work out, screenshots follow) Image CC0 licensed
  • 38.
    Distributing your appto users Image by acebrand from Pixabay
  • 39.
    How? Flathub Requirements Luckily, the generatedproject skeleton meets all of these Only need to fill in a few things
  • 40.
    AppStream meta info Thisfile is used to provide the description that users see on Flathub And in their software updater appplication Description of file format
  • 41.
    AppStream meta info Generatorto get you started Asks you a few questions Asks for URLs of screenshots Flathub guidelines OARS rating OARS Generator
  • 42.
    Desktop file Tells howto display your app in the desktop Description of file format List of categories [Desktop Entry] Name=Bloatpad Comment=Unnecessary note-taking application Exec=name.ptomato.Bloatpad Icon=name.ptomato.Bloatpad Terminal=false Type=Application Categories=Utility;GTK; StartupNotify=true
  • 43.
    Application icon Tobias Bernardon Designing an Icon for your App
  • 44.
    Submit it toFlathub Instructions here
  • 45.
    Translate your UI Gettextis built-in to the platform Venerable framework for UI translations Use a website like Transifex Recruit volunteer translators Or translate the UI yourself in whatever languages you speak
  • 46.
    Conclusion Some things mightseem familiar to JS developers, others might not We should reduce the friction for these developers But not everything from the web or Node.js applies well to the desktop
  • 47.
  • 48.
    Thanks Andy Holmes, EvanWelsh, Sri Ramkrishna for discussions and their work on improving the GJS developer experience License Presentation licensed under Creative Commons BY-NC-ND 4.0 Bloatpad code, permissive MIT license