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 +56 -2
- package/bin/dev-server.mjs +751 -27
- package/bin/error-overlay.mjs +2 -2
- package/bin/runtime/hmr-client.js +102 -0
- package/dist/router.d.ts +103 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +58 -0
- package/dist/router.js.map +1 -1
- package/package.json +12 -9
- package/tsconfig.base.json +21 -0
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, "
|
|
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 `&`.
|
|
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`);
|