diff --git a/Island.cfm b/Island.cfm index 93c3216..c640890 100644 --- a/Island.cfm +++ b/Island.cfm @@ -49,7 +49,10 @@ function resolveAsset(required string path) { if (cfg.isDev) { // Strip leading "./" so we get a clean URL join var clean = reReplace(arguments.path, "^\./", ""); - return "http://localhost:#cfg.vitePort#/#clean#"; + // viteUrl override (from COLDSPA_VITE_URL env) lets the browser reach + // a Vite dev server that isn't on localhost (e.g. host.docker.internal). + var viteBase = cfg.viteUrl ?: ("http://localhost:" & cfg.vitePort); + return viteBase & "/" & clean; } // Production: look up content-hashed file in vite manifest @@ -97,10 +100,37 @@ if (isSimpleValue(rendered)) { } bootImports = rendered.imports; bootBody = rendered.body; + +// Server-side rendering. If the renderer supports ssrRender(), call the SSR +// sidecar and embed the returned HTML inside the mount div. The client's +// createSSRApp().mount() will hydrate it on load. If SSR fails or isn't +// available, we just emit an empty div and the client mounts fresh -- so the +// page works either way (just no JS-off rendering in that case). +ssrHtml = ""; +ssrError = ""; +if (structKeyExists(attributes.framework, "ssrRender")) { + ssrResult = attributes.framework.ssrRender(componentGlobKey, attributes.props); + // Tolerate older renderers that returned a plain string. + if (isStruct(ssrResult)) { + ssrHtml = ssrResult.html ?: ""; + ssrError = ssrResult.error ?: ""; + } else { + ssrHtml = ssrResult; + } +} - -
+ + + + + + + + + + +
#ssrHtml#
diff --git a/README.md b/README.md new file mode 100644 index 0000000..a5ba989 --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +# Coldspa + +Astro-style framework islands for ColdFusion. Mount Vue (and React, soon) components into CFML pages with server-side rendering and progressive hydration. + +```cfml + + + + +``` + +## Quick start + +```bash +npm install +npm run dev # Vite dev server (HMR) +npm run ssr # Node SSR sidecar +``` + +For production: + +```bash +npm run build # builds client + SSR bundles +npm run ssr:prod # runs the sidecar against the built bundle +``` + +## Configuration + +Coldspa resolves config in this order (highest priority first): + +1. **Environment variables** — for CI/CD, Docker, prod +2. **`island-config.json`** in the webroot — for local dev / Admin UI +3. **Built-in defaults** + +### Environment variables + +| Variable | Effect | +|---------------------|--------------------------------------------------------------------------| +| `CF_ENV` | `development` / `dev` switches Coldspa to dev mode | +| `COLDSPA_SSR_URL` | Where **CF** reaches the SSR sidecar (server-to-server) | +| `COLDSPA_VITE_URL` | Where the **browser** reaches the Vite dev server (used for asset URLs) | +| `COLDSPA_SSR_PORT` | (sidecar) Port to listen on. Default `5174` | +| `COLDSPA_SSR_HOST` | (sidecar) Bind address. Default `0.0.0.0`. Use `127.0.0.1` to lock down | +| `NODE_ENV` | (sidecar) `production` switches sidecar to use built bundle | + +### `island-config.json` + +Lives in the webroot. Should be `.gitignore`d (it can be edited via the CF Admin UI). Any keys you set here are merged on top of defaults but overridden by env vars. + +```json +{ + "isDev": true, + "ssrUrl": "http://127.0.0.1:5174", + "viteUrl": "http://localhost:5173", + "vitePort": "5173" +} +``` + +| Key | Default | Description | +|------------|--------------------------|-------------------------------------------------------------| +| `isDev` | `false` | Dev mode (uses Vite dev server) vs prod (uses `dist/`) | +| `ssrUrl` | `http://127.0.0.1:5174` | SSR sidecar URL (server-to-server) | +| `viteUrl` | unset | Browser-facing Vite URL. Falls back to `localhost:vitePort` | +| `vitePort` | `"5173"` | Used to build the default `viteUrl` if `viteUrl` is unset | + +After editing `island-config.json`, request any page with `?reloadApp=1` to bust the cached config (or restart CF). + +### Docker / cross-host setups + +Two URLs need to work from **different perspectives**: + +- `ssrUrl` — CF → Node sidecar (server-to-server). Set this on the CF container. +- `viteUrl` — Browser → Vite dev server. Set this so generated `