
Croissant is Coming for You
Croissant is Coming for You ź“ė Ø
Last week I documented Croissant development in a lengthy tome that should have been a series. Iām also writing a series of dev notes. I suppose the main blog is a series now because this is part two. My gift of a Googly eyes CodePen (dbushell) was a success. I have no gift this week.
Hereās a boring screenshot.

Tauri MacOS App
Croissant is a progressive web app[1] and will be hosted as a website eventually. I have not abandoned those principles!
iOS and macOS allow PWAs to be āinstalledā albeit with questionable enthusiasm from Apple. Iāve been side-questing around Tauri 2.0 this week in pursuit of a better PWA experience. Tauri packages a native app out of a website with minimal fuss.
Tauri required 16.1 MB of node_modules to generate 16.9 MB of Croissant.app. The web assets are only 250 KBs. Thatās like 98.5% overhead.
Out of curiosity I followed the Electron tutorial to create the most basic Electron app. Electron required 347.2 MB of node_modules to produce a 264.4 MB macOS app. The major difference between Tauri and Electron is that Electron ships embedded Chromium and Node.js whereas Tauri uses the native web view provided by the OS.
Tauriās homepage claims:
From Tauri's hompage (tauri.app)
By using the OSās native web renderer, the size of a Tauri app can be little as 600KB.
Naturally they refuse to elaborate on that 600 KB claim.
I checked the App Size docs and copy-pasted config. The freshly compiled Croissant.app shrunk to 6.6 MB. I should read more of this documentation. A 6.6 MB native macOS app that wraps my PWA is smaller than a website like nextjs.org (to select a random example). And my app works unlike nextjs.org.
Persistant Data
Croissant uses IndexedDB to store RSS feed data. Iām using Dexie for now to help.
Safari is known for the odd IndexedDB bug but I believe it is stable now. Safari has (or had?) a 7-day policy on purging storage. How this affects PWAs is confusing:
Web applications added to the home screen are not part of Safari and thus have their own counter of days of use. Their days of use will match actual use of the web application which resets the timer. We do not expect the first-party in such a web application to have its website data deleted.
Iām struggling to find a concrete answer so please @ me if you know the current state of Safari storage.
Anyway, I was concerned about how Tauri apps stored IndexedDB data, and if it persisted across updates. On macOS I found data in the following directory.
/Users/dbushell/Library/WebKit/com.dbushell.croissant
Inside that location there is an empty WebsiteData/IndexedDB directory. Curious. Spelunking deeper into randomly named directories I found what I was looking for.
Size Date Modified Name
164M 18 Jul 07:19 IndexedDB.sqlite3
33k 18 Jul 07:12 IndexedDB.sqlite3-shm
29k 18 Jul 07:19 IndexedDB.sqlite3-wal
It was SQLite all along! This is not surprising, Apple love a good SQLite database. Itās sad Apple get all the fun and weāre stuck with IndexedDB. Web SQL needs a comeback. I did consider SQL Wasm; itās not worth the cost.
This database persists across app updates. It probably hangs around after the app is deleted. That said, some Tauri devs have had issues:
From (tauri-apps/tauri)
General recommendation is to store your app data separately and not rely on IndexedDB as it may change again in a future major version of tauri.
Iām very reluctant to use Tauriās store plugin. Itās effectively proprietary for my purposes. I already have a cross-platform database. Iāll stick to using IndexedDB for now. I have import/export functionality. I could always write a migration script.
Tauri Plugins
Speaking of Tauri plugins, one does not simply open an external hyperlink from a Tauri app.

meme of Boromir from Lord of the Rings quoted as saying 'One does not simply open a hyperlink'
Hyperlinks are kind of a big deal in RSS feeds. Some feeds are nothing but links. Whilst Tauri is a web view it is not a web browser. There is a special Opener plugin for that. I have to detect external clicks. I do this conditionally because Tauri is not my only target.
if ("__TAURI__" in globalThis) {
globalThis.addEventListener('click', (ev) => {
const link = ev.target?.closest('a[href][target="_blank"]');
if (link) {
globalThis.__TAURI__.opener.openUrl(link.href);
}
});
}
The Croissant website itself is āno buildā (a deliberate choice) which means I have to use the awkward __TAURI__ global. Were I to acquiesce to a build toolchain I could import.
import { openUrl } from '@tauri-apps/plugin-opener';
Why they canāt expose a fake module like the global object I donāt know.
The Tauri HTTP Client plugin solved my proxy server dependency to bypass CORS issues. Previously an early experiment led to a 88.8 MB app including a Deno sidebar binary. Reducing that to 6.6 MB has made me very happy.
Annoyingly, the opener plugin will not open the blob: URLs I generate to export data and prompt a download. For that I had to combine the save dialog and file system write plugins. This added another conditional branch.
const path = await globalThis.__TAURI__.dialog.save({
defaultPath: "croissant.json",
filters: [{
name: "croissant.json",
extensions: ["json"],
},
],
});
if (path) {
await globalThis.__TAURI__.fs.writeTextFile(
path,
JSON.stringify(data)
);
}
Itās not much code but it adds complexity. Iām in danger of turning my web app into a Tauri app. Iāve set myself the restriction of not implementing anything in Tauri that I cannot do on a website. And itās pretty much feature complete now.
Release Date?
If you would like to use the Croissant macOS app, or a hosted web version, please get in touch. It might be September before itās ready because my August is busy.
Theoretically I could cross compile for Windows and Linux but I have no desire to do that right now. @ me if youāre interested.
Once the app design and functionality is stable Iāll consider how I plan to distribute it, host it, open source it, sell it? I will do another blog post expanding on my design principles for Croissant. Itās super minimal. If you like āfeaturesā prepare to be disappointed!
Sources on 'Progressive Web App'(1)
see: Website. ā©ļø