Skip to content

feat(devframe): remote client assets — serve SPA dists through a caching CDN back-proxy - #236

Open
antfubot wants to merge 5 commits into
mainfrom
feat/remote-client-assets
Open

feat(devframe): remote client assets — serve SPA dists through a caching CDN back-proxy#236
antfubot wants to merge 5 commits into
mainfrom
feat/remote-client-assets

Conversation

@antfubot

Copy link
Copy Markdown
Collaborator

What

Lets a devframe's browser assets live in their own npm package instead of shipping inside the node tarball: every static-assets seam — cli.distDir, hostStatic, mountStatic, and the shared serve-static engine — now accepts a version-locked RemoteAssets declaration ({ package, version }) alongside a local directory, served through an on-demand, caching CDN back-proxy.

Why

~91% of the published bytes across the asset-shipping packages (~19.7 MB of 21.6 MB) is prebuilt browser assets — @devframes/plugin-git alone carries a 12.2 MB client. This core seam is the first step toward slim node packages with lockstep-published -client asset packages, with no extra install required in the happy path and a zero-network story for air-gapped setups.

How it resolves (per request, version-locked)

  1. Locally installed assets package — resolved from the declaration's resolveFrom (import.meta.url), so npm i <pkg>-client serves with zero network. Minor/patch skew warns (DF0061); a major mismatch throws (DF0060).
  2. Per-file cache<project storage>/.remote-assets/<pkg>@<version>/.
  3. CDN providerjsdelivr (default), unpkg, or a custom mirror; the file streams through to the browser while being teed into the cache.

Request paths resolve against the provider's file listing (correct 404s + SPA fallback), degrading to per-file probing when the listing API is down (DF0058). HTML navigations that can't be satisfied render a styled error page with the local-install fix; other requests get a plain 502 (DF0059). Static builds (createBuild) materialize the full file set from the listing so their output stays self-contained (DF0063).

Surface

  • New devframe/utils/remote-assets: resolveStaticAssetsSource(), createRemoteAssetsStore(), resolveInstalledRemoteAssets(), cache-path helpers, error page.
  • New types: RemoteAssets, StaticAssetsSource, RemoteAssetsStore, provider types.
  • Widened: cli.distDir, InitDevframeOptions.distDir, CreateDevServerOptions.distDir, CreateBuildOptions.distDir, DevframeViewHost.hostStatic, DevframeHost.mountStatic, serveStaticHandler / mountStaticHandler / serveStaticNodeMiddleware.
  • Diagnostics DF0058DF0063 with docs/errors/ pages.
  • Consumers pass through: hub installDevframe, @devframes/vite static mount, @devframes/next host.

API snapshots updated accordingly (input-widening; DevframeHost.mountStatic implementors now also receive stores — acceptable pre-1.0).

Out of scope (follow-ups)

  • Converting the built-in plugins to lockstep -client packages.
  • json-render-ui renderer-module seam.
  • The community-facing "deferred client assets" docs guide.

Created with the help of an agent.

…ing CDN back-proxy

Every static-assets seam (cli.distDir, hostStatic, mountStatic, the
serve-static engine) now accepts a version-locked RemoteAssets
declaration ({ package, version }) alongside a local directory, so a
plugin's browser bundle can live in its own npm package instead of
shipping inside the node tarball.

Resolution order per request: a locally installed copy of the assets
package (resolved from the declaration's resolveFrom, warning on
minor/patch skew and rejecting a major mismatch), the per-file cache
under <project storage>/.remote-assets/<pkg>@<version>/, then the CDN
provider (jsdelivr by default, unpkg or a custom mirror via provider) —
streaming through to the browser while teeing into the cache. Request
paths resolve against the provider's file listing (correct 404s and SPA
fallback), degrading to per-file probing when the listing is
unreachable. HTML navigations that cannot be satisfied get a styled
error page pointing at the local-install fix; static builds materialize
the full file set so their output stays self-contained.

New diagnostics DF0058–DF0063 cover listing/fetch/cache/materialization
failures and version skew, each with a docs page.
@netlify

netlify Bot commented Aug 15, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit 01acd22
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a80220658fa1800088dc8a8
😎 Deploy Preview https://deploy-preview-236--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

…sets

# Conflicts:
#	docs/errors/DF0058.md
#	packages/devframe/src/node/diagnostics.ts
#	packages/devframe/src/node/host-h3.ts
#	tests/__snapshots__/tsnapi/devframe/adapters/build.snapshot.d.ts
#	tests/__snapshots__/tsnapi/devframe/index.snapshot.d.ts
#	tests/__snapshots__/tsnapi/devframe/internal.snapshot.d.ts
#	tests/__snapshots__/tsnapi/devframe/types.snapshot.d.ts
Collapse the remote-assets module's public API from eight exports to one
(resolveStaticAssetsSource) — cache-path helpers, createRemoteAssetsStore,
resolveInstalledRemoteAssets, and the store options interfaces are now
private, and the error page moves into serve-static as an internal helper.

resolveStaticAssetsSource takes the project storage dir directly (dropping
the options object), so every call site loses the cacheRoot plumbing; the
build adapter reuses it too instead of hand-rolling install/materialize.

RemoteAssetsStore.serve now returns a web Response, letting serve-static
drop the RemoteAssetsServedFile / RemoteAssetsServeOptions types and the
bespoke miss/stream/cancel handling. Net ~370 fewer lines.
The installed-package resolution returns pathe (forward-slash) paths, but
the tests built the expected distDir with node:path — backslashes on
Windows — so the equality assertions failed only on windows-latest.
Compare both sides normalized to forward slashes.
A remote source's `package` and `version` are interpolated into CDN URLs
and the on-disk cache path, so `resolveStaticAssetsSource` now rejects a
value that isn't a valid npm package name / exact semver version (new
`DF0065`) — closing off malformed URLs and cache-path traversal (e.g. a
`..` version segment).
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