@kentcdodds/package-app-kit
Design tokens, PWA install/update, About/version, cache helpers, and optional realtime notes sync for Kody package apps.
starter-remix/STARTER.md
75 lines · 4.1 KB · MarkdownRemix starter template
Canonical scaffolder template for @kentcdodds/package-app-kit create-package-app (embeds via src/starter-templates.ts / scripts/embed-starter.mjs).
Requires the framework-agnostic package-app host (kody#2312+). Remix is a recipe with remount / tsconfig / island-id boilerplate — do not set kody.app.runtime.
The archived fetch template lives at starter-fetch/.
Layout (Remix recipe)
tsconfig.json # jsx react-jsx, jsxImportSource remix/ui (+ dual file pragmas on SSR .tsx)
app/router.ts # kody.app.entry — remount + export default { fetch }
app/routes.ts # route(packageContext?.appBasePath ?? '', { … })
app/controllers/*.tsx # home, about, notes, manifest, icons, version
app/middleware/*.ts # request-id (example)
app/data/*.ts # notes via get(KodyRuntime).packageStorage()
app/ui/*.tsx # Document, layout, clientEntry('kody:app#…') islands
app/assets/entry.ts # kody.app.client — run() + island registry
public/ # kody.app.assets — styles.css + sw.js (__version.json precache)package.json#kody.app (no runtime field — entry is a fetch handler):
{
"entry": "./app/router.ts",
"client": "./app/assets/entry.ts",
"assets": "./public"
}Hard rules
- Import platform
remix/*only (remix/ui,remix/router,remix/ui/server, …). - Use
devDependencies.remixfor editor types only — never a fat runtimeremixdependency or@remix-run/*. - Mount-prefixed routes via
packageContext.appBasePath, with remount inapp/router.ts. - Controllers use
get(KodyRuntime)for storage/context (no custom Kody middleware). - Root
tsconfig.jsonsets"jsx": "react-jsx"+"jsxImportSource": "remix/ui"(supporting config). - Every SSR
.tsxthat uses JSX starts with both pragmas so host esbuild emits remix/ui automatic JSX:/** @jsxRuntime automatic */ /** @jsxImportSource remix/ui */ - Islands use explicit ids:
clientEntry('kody:app#Name', function Name…). - No Vite/HMR; no import map for Remix (platform inlines
remix/ui). - SW in
public/sw.jsreads/_assets/__version.json— no hash in source. - Keep
app/ui/layout.tsx(and anything that importsroutes) out of the browser island registry — SSR-only.
Placeholders
__PACKAGE_NAME__, __PACKAGE_ID__, __APP_TITLE__, __CACHE_NAME__, __KODY_DESCRIPTION__
List / identity mark
.kody/icon.svg is the scaffolded list mark (create-package-app / packageSave text lane). Prefer .kody/icon.png when adding a binary logo via Artifacts git. Never scaffold root community-icon.*. PWA icons/icon-192.png / icon-512.png stay product install assets — do not move them into .kody/.
After scaffold
Default tokens/theme-color are Remix-dark charcoal + cyan (match or replace when branding). Follow the After scaffolding checklist in AGENTS.template.md (becomes AGENTS.md in the new package): brand .kody/icon + PWA icons/icon-192.png / icons/icon-512.png, fill titles/description/packageName, keep local src/version.ts + src/record-version.ts, call this app's ./record-version after each publish, confirm the Remix recipe (tsconfig jsx, remount + { fetch }, clientEntry('kody:app#…')), and match manifest themeColor / backgroundColor to the mark. Optional: Lucide via scripts/add-lucide-icon.mjs.
Then smoke with packageAppFetch on /, /notes, /about, /manifest.webmanifest, icons, and /health.
Layout stability
Prefer zero content layout shift. Update prompts are a fixed dismissible toast, not an in-flow card. Same rule for other late UI: overlays or reserved space.
Press feedback
Taps that start work get immediate pending state. Busy labels use spin-delay timing (app/ui/busy.ts) so loading text does not flash on fast actions.
Errors
Use app/ui/error-banner.tsx (ErrorBanner) when a failure replaces expected content (validation, About check failed, SSR catch). Prefer toasts for short-lived action failures so layout stays stable.