curiousdannii / parchment

The Interactive Fiction web app
https://iplayif.com
MIT License
421 stars 60 forks source link

Dialog: Use IndexedDB instead of localStorage #142

Open dfabulich opened 6 months ago

dfabulich commented 6 months ago

Something I learned recently that may be of interest to you. localStorage is limited to 5MB, but IndexedDB has a much larger storage limit.

https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria

Browsers can store up to 5 MiB of local storage, and 5 MiB of session storage per origin.

The data that's stored by using other web technologies, such as IndexedDB, Cache API, or File System API (which defines the Origin Private File System), is managed by a storage management system that's specific to each browser.

In Firefox, the maximum storage space an origin can use in best-effort mode is whichever is the smaller of:

  • 10% of the total disk size where the profile of the user is stored.
  • Or 10 GiB, which is the group limit that Firefox applies to all origins that are part of the same eTLD+1 domain.

In browsers based on the Chromium open-source project, including Chrome and Edge, an origin can store up to 60% of the total disk size in both persistent and best-effort modes.

Starting with macOS 14 and iOS 17, Safari allots up to around 20% of the total disk space for each origin. If the user has saved it as a web app on the Home Screen or the Dock, this limit is increased to up to 60% of the disk size. For privacy reasons, cross-origin frames have a separate quota, amounting to roughly 1/10 of their parents.

The biggest gotcha here is that localStorage is synchronous, but IndexedDB is asynchronous.

The second biggest gotcha is that IndexedDB is a much more complicated API. You might enjoy this library https://github.com/jakearchibald/idb-keyval which provides a Promisified wrapper around IDB.

The third biggest gotcha has to do with sharing IndexedDB between multiple games, especially in the single-file HTML mode, where all file:// URLs are the same origin.

In ChoiceScript, which generates offline-enabled HTML files, I handled this by using a different database for each game. https://github.com/jakearchibald/idb-keyval/blob/main/custom-stores.md (Note that I don't recommend sharing one database and creating multiple object stores per database, because the only time you're allowed to create an object store is when creating or "upgrading" the database to a higher version number.) I used the IFID as the unique identifier for each game. Seems to be working OK.

curiousdannii commented 6 months ago

Oh, yes I am already planning to switch to IndexedDB in the future! But making the whole system async is a massive task. See #11 for a checklist. I'm getting there though, I'm going to add my rewrite of GlkApi into Parchment for testing hopefully this week.