You are browsing as a guest. Sign up (or log in) to start making projects!

Open comments for this post

18m 44s logged

the one big devlog

so updato exists now. figured i should write down what actually happened before i forget why i made half these decisions.

what even is this

updato is a decentralized update system for browser apps. the whole idea is: you push code, your app knows there’s a new version, and it updates itself. no app store, no server infrastructure you have to maintain. just github and a cloudflare worker.

it’s three pieces:

  • a github action that takes your build output and pushes it to a cdn branch on your repo. every version gets its own folder, plus there’s always a latest/ copy. it writes a manifest.json with metadata about what’s current.
  • a cloudflare worker that acts as the middleman. your app asks it “hey is there an update?” and it goes and reads your manifest off github, compares versions, and tells the client yes or no. stateless, basically free to run.
  • a js client library that you drop into your app. it talks to the worker, downloads new files if there’s an update, caches them in localStorage, and reloads when you’re ready.

two modes because i couldn’t pick one

there’s commit mode and version mode. commit mode means every push is a new version and the “version” is just the commit sha. version mode uses semver from your package.json. commit mode is nice for apps where you just want continuous deployment. version mode is for when you want to be more intentional about it.

honestly i went back and forth on whether to support both. decided it was easy enough to keep and the action just reads a flag.

the action

lives in Action/. typescript, compiled with ncc. it clones your cdn branch into a temp directory (or inits a fresh one if the branch doesn’t exist yet), copies your dist folder into latest/ and versions/{version}/, writes the manifest, commits, and pushes. the commit messages are kinda nice actually, they show what version replaced what: deploy: abc123 (was def456).

one thing i’m quietly proud of is that it handles the “branch doesn’t exist yet” case gracefully. first run just works.

the worker

lives in Worker/. pretty small. two endpoints: /check and /manifest. /check takes a repo and your current version, fetches the manifest from github, does the comparison, and returns whether there’s an update. wrote my own semver parser because i didn’t want to pull in a dependency for what’s basically three number comparisons. it’s probably fine. it validates the repo format with a regex so you can’t pass in weird stuff.

set up wrangler.toml with a production and staging env.

the client

lives in Build/. this is the part that actually runs in people’s apps. it’s a class called Updato (creative naming, i know). you init it with your repo, mode, and current version. then you can check for updates, download them, and apply them. downloads get cached in localStorage with version tags so stale cache gets cleaned up automatically.

built with vite, outputs both esm and umd so you can import it or just drop a script tag.

tooling i added after

wrote a bump-version.js script that bumps the version across all four package.jsons (root + the three workspace packages), commits, tags, and pushes. one command to do a release, basically. also a little print-cdn-commit.js that tells you what the latest cdn branch commit is, which is useful for debugging.

there’s a TODO.md with a bunch of stuff i want to do eventually. hot-swap support, rate limiting in the worker, tests, linting, npm publishing. the usual “i’ll get to it” list.

current status

it works. the action runs, the worker deploys, the client checks and downloads. trying to publish the action to the github marketplace but the name “Updato” is apparently reserved by a ghost account that doesn’t exist. so that’s cool. working on that.

0
2

Comments 0

No comments yet. Be the first!