The project I want to build is a web-based local file storage.
Why? Nowadays, there are so many web-based tools that work with files, such as:
- Squoosh image compressor
- Photopea photo editor
- gifcap screen recorder
- Diagrams.net diagram and flowchart maker
- vox.spacet.me voice recorder (I made this one)
- json.spacet.me JSON viewer (I made this one too)
- instant.io streaming file transfer over WebTorrent
- ShareDrop file transfer over WebRTC
- StackEdit and Dillinger Markdown editor
- Carbon code image generator
- other specialized tools that I create for specific situations
Now comes my pain point: When I want to use multiple apps together, I have to go through a lot of Download-then-Upload experience, and thus my Downloads folder fills up with many temporary files.
Many apps are inconsistent in how they handle input/output. To get data into a web app, you can use the usual File open dialog (via <input type="file">
), the Drag and Drop API, the Clipboard API, and the Share Target API. To get data out, there's <a>
's download attribute, DownloadURL DataTransfer type for dragging files out of the browser, the Clipboard API, the Web Share API, and the classic "Save Link As", "Save Image As" and "Copy Image" menu items.
Most apps support only a subset of these APIs. Some apps also have integrations with cloud storage services like Google Drive, but many don't. Paul Kinlan (2017). “Web sites as unintended silos: The problem with getting data in and out of the web client.” is an interesting read.
Now the web has the postMessage
API that lets web applications throw data around among different websites. So, I'm pondering about the idea of having a web-based portal, a hub of sort, that takes care of importing/exporting files using all the available Web APIs...
...and integrates with all the different apps.
It should be extensible. Of course I'm lazy and I won't be integrating all the different apps myself. Instead, integrations will be provided through an extensions system. (In the above picture, the text in blue are to be implemented as an extension rather than as a core feature.)
If all goes according to the plan, extensions will be HTML pages and communicate with this app through the postMessage
API. This way new extensions can be written using any tool, and added to the app without having to touch the main app. This is a nice opportunity to learn about "micro-frontends."
Deployment structure: The main app will be deployed as a Static Site application, while extensions may be deployed as separate apps, and some of them might require a database. This is also an opportunity to try out App Platform services such as DigitalOcean Managed Databases.
Project name: This is one of the hardest thing in computer science. I intended it to be a place where I temporarily put files in. For the lack of better name, I just called it "tmp".
Project setup: I applied for a DigitalOcean credit, created a Next.js static app, set up Tailwind, TypeScript and next-pwa. I deployed the app to DigitalOcean App Platform and it just works (except the part where I waited for the spinner to finish. By the way everyone, please don't add a spinner if you will not also automatically refresh it.)
Implementating the core features: I then implemented the basic import/export functionalities using various Browser APIs and npm packages:
- Clipboard API
- Web Share Target API
- DownloadURL for Drag and Drop
- window.open()
- downloadjs
- Browser-NativeFS
File data and all other data will be stored inside IndexedDB, through the help of PouchDB. Querying data from the local database in the React app is done using React Query.
After a few days of coding, most of the core features are implemented. Now, for example, I can share photos from Google Photos directly to tmp. Within tmp, I can view the image (using the browser's built-in image viewer) and share it to other apps.
Right now the UI is very unpolished, and the rename functionality has not yet been implemented. But there are more important stuff to do first. The elephant in the room -- postMessage
-based integrations.
Open source contributions: Along the way I sent some quick PRs:
- PaulKinlan/paul.kinlan.me#28 fixes a few little typos
- shadowwalker/next-pwa#132 improves error messages
Next up: I will probably be implementing a first iteration of a postMessage
-based integration system. It will integrate with an external tool I have already created. Meanwhile, the source code is on GitHub at dtinth/tmp.