mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-20 17:02:53 -04:00
fix assets in dev
This commit is contained in:
@@ -7,6 +7,70 @@ import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
import { execSync } from 'child_process';
|
||||
import path from 'path';
|
||||
|
||||
// Dev-only CDN proxy. Media assets (splats, GLBs, images) are fetched with
|
||||
// fetch(), but the CDNs only send CORS headers for the production origin —
|
||||
// not localhost. The web adapter's fetchAsset rewrites absolute CDN URLs to
|
||||
// `/__cdn/<host>/<path>` in DEV; this middleware forwards them server-side
|
||||
// (no browser CORS) to whatever host is embedded in the path.
|
||||
//
|
||||
// NB: This must be a middleware, not a `server.proxy` entry. The previous
|
||||
// proxy config used a `router` option to pick the target host from the path,
|
||||
// but `router` is an http-proxy-middleware feature — Vite's http-proxy
|
||||
// silently ignores it, so every request went to the hardcoded default target
|
||||
// and any asset on a different host (e.g. the dev R2 bucket) came back 403.
|
||||
function cdnProxyPlugin() {
|
||||
return {
|
||||
name: 'cdn-proxy',
|
||||
configureServer(server: {
|
||||
middlewares: {
|
||||
use: (
|
||||
route: string,
|
||||
handler: (
|
||||
req: import('http').IncomingMessage,
|
||||
res: import('http').ServerResponse,
|
||||
) => void,
|
||||
) => void;
|
||||
};
|
||||
}) {
|
||||
server.middlewares.use('/__cdn', async (req, res) => {
|
||||
try {
|
||||
// Connect strips the `/__cdn` mount prefix from req.url.
|
||||
const match = (req.url ?? '').match(/^\/([^/?]+)(\/[^?]*)?(\?.*)?$/);
|
||||
if (!match) {
|
||||
res.statusCode = 400;
|
||||
res.end('Bad /__cdn path; expected /__cdn/<host>/<path>');
|
||||
return;
|
||||
}
|
||||
const [, host, assetPath = '/', query = ''] = match;
|
||||
const upstream = await fetch(`https://${host}${assetPath}${query}`, {
|
||||
method: req.method === 'HEAD' ? 'HEAD' : 'GET',
|
||||
headers: req.headers.range
|
||||
? { range: String(req.headers.range) }
|
||||
: undefined,
|
||||
});
|
||||
res.statusCode = upstream.status;
|
||||
for (const header of [
|
||||
'content-type',
|
||||
'content-length',
|
||||
'accept-ranges',
|
||||
'content-range',
|
||||
'etag',
|
||||
'cache-control',
|
||||
]) {
|
||||
const value = upstream.headers.get(header);
|
||||
if (value) res.setHeader(header, value);
|
||||
}
|
||||
const body = Buffer.from(await upstream.arrayBuffer());
|
||||
res.end(body);
|
||||
} catch (e) {
|
||||
res.statusCode = 502;
|
||||
res.end(`CDN proxy error: ${e}`);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Custom plugin to generate news.json on dev server start
|
||||
function generateNewsPlugin() {
|
||||
return {
|
||||
@@ -38,29 +102,15 @@ export default defineConfig(() => ({
|
||||
Origin: 'https://api.storyteller.ai',
|
||||
},
|
||||
},
|
||||
// Dev-only CDN proxy. Media assets (splats, GLBs, images) are fetched
|
||||
// from the CDN with fetch(), but the CDN only sends CORS headers for the
|
||||
// production origin — not localhost. The web adapter's fetchAsset rewrites
|
||||
// absolute CDN URLs to `/__cdn/<host>/<path>` in DEV; this forwards them
|
||||
// server-side (no browser CORS). The target host is taken from the path
|
||||
// so any cdn-N.fakeyou.com / Cloudflare host works.
|
||||
'/__cdn': {
|
||||
target: 'https://cdn-2.fakeyou.com',
|
||||
changeOrigin: true,
|
||||
secure: true,
|
||||
router: (req) => {
|
||||
const match = req.url?.match(/^\/__cdn\/([^/]+)/);
|
||||
return match ? `https://${match[1]}` : 'https://cdn-2.fakeyou.com';
|
||||
},
|
||||
rewrite: (path) => path.replace(/^\/__cdn\/[^/]+/, ''),
|
||||
},
|
||||
// NB: `/__cdn` asset proxying lives in `cdnProxyPlugin` above — it
|
||||
// needs per-request host routing, which `server.proxy` can't do.
|
||||
},
|
||||
},
|
||||
preview:{
|
||||
port: 4301,
|
||||
host: 'localhost',
|
||||
},
|
||||
plugins: [generateNewsPlugin(), nxViteTsPaths(), react(), wasm(), topLevelAwait()],
|
||||
plugins: [cdnProxyPlugin(), generateNewsPlugin(), nxViteTsPaths(), react(), wasm(), topLevelAwait()],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
|
||||
Reference in New Issue
Block a user