swift-rust 1.0.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/build.mjs CHANGED
@@ -15,7 +15,7 @@ import { join, resolve, dirname, sep } from "node:path";
15
15
  import { fileURLToPath } from "node:url";
16
16
 
17
17
  const cwd = process.cwd();
18
- const APP_DIR_CANDIDATES = [resolve(cwd, "app", "src"), resolve(cwd, "app")];
18
+ const APP_DIR_CANDIDATES = [resolve(cwd, "src", "app"), resolve(cwd, "app")];
19
19
  const APP_DIR = APP_DIR_CANDIDATES.find((p) => existsSync(p)) ?? resolve(cwd, "app");
20
20
  const PUBLIC_DIR = resolve(cwd, "public");
21
21
  const OUT_DIR = resolve(cwd, ".vercel", "output");
@@ -200,6 +200,15 @@ function stripHmrScript(html) {
200
200
  return html.replace(/\s*<script src="\/_swift-rust\/hmr-client\.js"[^>]*>\s*<\/script>/g, "");
201
201
  }
202
202
 
203
+ // The dev-time image endpoint (/_swift-rust/image) only exists while the dev
204
+ // server runs. On Vercel the platform serves an optimizing endpoint at
205
+ // /_vercel/image with the exact same query contract (url, w, q), so we swap the
206
+ // path prefix at build time. The `images` config written into config.json
207
+ // enables (and bounds) that optimizer. Handles `src`, `srcset`, and `&amp;`.
208
+ function rewriteImageUrls(html) {
209
+ return html.split("/_swift-rust/image?").join("/_vercel/image?");
210
+ }
211
+
203
212
  function writeStaticFile(outDir, pathname, html) {
204
213
  const rel = pathname === "/" ? "index.html" : `${pathname.replace(/^\//, "")}/index.html`;
205
214
  const outPath = join(outDir, rel);
@@ -214,6 +223,41 @@ function writeRawFile(outDir, name, contents) {
214
223
  writeFileSync(outPath, contents);
215
224
  }
216
225
 
226
+ // Client-island hydration: a "use client" page's HTML references the dev-only
227
+ // bundle at /_swift-rust/island.js?p=<file>. For the static export we fetch
228
+ // that bundle, write it as a real file, and rewrite the script src to point at
229
+ // it — so hydration works on the deployed site, not just in `bun dev`.
230
+ const islandWritten = new Map();
231
+ function simpleHash(s) {
232
+ let h = 2166136261;
233
+ for (let i = 0; i < s.length; i++) {
234
+ h ^= s.charCodeAt(i);
235
+ h = Math.imul(h, 16777619);
236
+ }
237
+ return (h >>> 0).toString(36);
238
+ }
239
+ async function localizeIslands(html) {
240
+ const re = /\/_swift-rust\/island\.js\?p=([^"]+)/g;
241
+ const found = new Set();
242
+ let m;
243
+ while ((m = re.exec(html)) !== null) found.add(m[1]);
244
+ if (found.size === 0) return html;
245
+ let out = html;
246
+ for (const enc of found) {
247
+ let staticUrl = islandWritten.get(enc);
248
+ if (!staticUrl) {
249
+ const { status, body } = await fetchRoute(`/_swift-rust/island.js?p=${enc}`);
250
+ if (status !== 200) continue;
251
+ const rel = `_swift-rust/island/${simpleHash(enc)}.js`;
252
+ writeRawFile(STATIC_DIR, rel, body);
253
+ staticUrl = `/${rel}`;
254
+ islandWritten.set(enc, staticUrl);
255
+ }
256
+ out = out.split(`/_swift-rust/island.js?p=${enc}`).join(staticUrl);
257
+ }
258
+ return out;
259
+ }
260
+
217
261
  function writeConfigJson(outDir, _hasPublic) {
218
262
  // Build Output API v3 config. Only schema-valid fields here — unknown
219
263
  // top-level fields or route properties are rejected at "Deploying outputs".
@@ -228,6 +272,16 @@ function writeConfigJson(outDir, _hasPublic) {
228
272
  overrides: {
229
273
  "404.html": { path: "404", contentType: "text/html; charset=utf-8" },
230
274
  },
275
+ // Enables Vercel's image optimizer (/_vercel/image). `sizes` MUST match the
276
+ // widths <Image> requests (packages/image DEVICE_SIZES) or requests 400.
277
+ images: {
278
+ sizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
279
+ formats: ["image/avif", "image/webp"],
280
+ minimumCacheTTL: 86400,
281
+ // Allow optimizing local SVG assets (e.g. blog covers); sandboxed by CSP.
282
+ dangerouslyAllowSVG: true,
283
+ contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
284
+ },
231
285
  };
232
286
  writeFileSync(join(outDir, "config.json"), `${JSON.stringify(config, null, 2)}\n`);
233
287
  }
@@ -290,7 +344,7 @@ async function main() {
290
344
  try {
291
345
  const { status, body } = await fetchRoute(route);
292
346
  if (status === 200) {
293
- const cleaned = stripHmrScript(body);
347
+ const cleaned = rewriteImageUrls(await localizeIslands(stripHmrScript(body)));
294
348
  writeStaticFile(STATIC_DIR, route, cleaned);
295
349
  okCount++;
296
350
  process.stdout.write(` ${paint("green", "✓")} ${route}\n`);