Skip to content

feat: favseed/vite - #11

Merged
cevdetch merged 6 commits into
mainfrom
feat/vite
Oct 5, 2026
Merged

cevdetch merged 6 commits into
mainfrom
feat/vite

Conversation

@cevdetch

@cevdetch cevdetch commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Step 3 of the single-engine design: favseed/vite, a Vite 8 plugin.

What it does. In dev the set is built on the first request for an icon, in fast mode, and served from memory at Vite's base with its content type; editing the mark or favseed.config.* rebuilds it, invalidates virtual:favseed and reloads the page. vite build emits the release set at the output root and links it in index.html, unless the page already declares an icon (rel="icon" or rel="shortcut icon"). virtual:favseed exports { links, files } for frameworks without an index.html. Options are the config keys minus out, over favseed.config.* in the Vite root.

What I measured first, in scratch projects on Vite 8.3.1 and Astro 7.3.5:

  • Emitting only in a real build's client environment lands the files once, in dist/ for a plain or static Astro build and in dist/client/ for @astrojs/node, where the node server serves them. Emitting everywhere leaves dead copies in dist/server/, and Astro also runs a dev-mode server inside astro build, so settings are kept per mode: dev's fast mode never decides the release bytes.
  • Vite and Astro both let an emitted file replace a public/ file of the same name without a word, in build and in dev. favseed checks it itself: a different file fails the build in buildStart, before dist/ is emptied (in generateBundle the failure left a gutted dist/); dev serves your file and warns.
  • The dev middleware has to be registered in configureServer itself; as a post hook, public/ and Astro's router answer first.
  • vite-plugin-pwa 2.0.0 has no public API for another plugin to set its manifest icons, and vite.config cannot import a virtual module. So favseed leaves the manifest to it (no site.webmanifest, no second link), warns about its pwaAssets generator, and exports a synchronous favseedIcons() for its manifest.icons. I ran the README recipe against the real vite-plugin-pwa: its manifest.webmanifest lists favseed's 192 and 512 icons as any maskable, and the page carries one manifest link.

Shared pieces. buildFiles() is the in-memory half of build(). The content-addressed cache moves from the Astro integration to vite/cache.mjs, which both use; its key now canonicalises vars given as a Map, which the merged options are (Object.entries of a Map is empty, and the key would have dropped every --var). manifestIcons() in lib/core.mjs feeds both manifestJson (same bytes, pinned by a test) and favseedIcons().

Package. vite/ ships, exports["./vite"] has a types condition, vite ^8.0.0 is an optional peer, and vite 8.3.1 is the test dependency.

Verified locally: pnpm test, 190 pass, 0 fail, 0 skipped, including a real Vite build and dev server per case and a TypeScript check of a vite.config.

CI: every job green, same-bytes included, and the 66 Linux hashes are identical to the ones step 1 recorded: no output byte changed.

buildFiles() returns the set as bytes and build() writes what it returns. The content-addressed cache moves from the Astro integration to vite/cache.mjs, with slot read and write beside the key, and the key now canonicalises vars given as a Map, which the merged options are.
manifestIcons() in lib/core.mjs lists the manifest's icon entries, and manifestJson writes the same bytes from it. favconIcons() hands them to vite-plugin-pwa's manifest.icons, which has no public API for another plugin to fill.
favcon/vite builds through the shared cache, emits the set at the output root in the client environment of a real build only, links it in index.html unless the page declares an icon, and exports links and files from virtual:favcon. A different file of the same name in public/ fails the build before dist/ is emptied. With vite-plugin-pwa present favcon leaves the manifest to it and warns about its pwaAssets. Settings are kept per mode, so a dev-mode server in the same process never decides the release bytes.
The dev server builds the set in fast mode on the first request for an icon and serves it from memory at base with its content type. A different file in public/ is served instead, with a warning. Editing the mark or the config file rebuilds, invalidates virtual:favcon and reloads the page; a broken mark is logged and the page keeps working.
The tarball carries vite/, exports maps ./vite with a types condition, and vite ^8 is an optional peer dependency. The types reject out and unknown keys.
The README gains a Vite section with the vite-plugin-pwa recipe; the CHANGELOG and the definition of done follow.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying favcon with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8224301
Status: ✅  Deploy successful!
Preview URL: https://5442a3eb.favcon.pages.dev
Branch Preview URL: https://feat-vite.favcon.pages.dev

View logs

@cevdetch
cevdetch merged commit 9e2c3a1 into main Oct 5, 2026
7 checks passed
@cevdetch
cevdetch deleted the feat/vite branch October 5, 2026 07:06
@cevdetch cevdetch changed the title feat: favcon/vite feat: favseed/vite Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant