70 lines
2.9 KiB
TypeScript
70 lines
2.9 KiB
TypeScript
import { defineConfig } from 'vite';
|
|
import react from '@vitejs/plugin-react';
|
|
|
|
// Minimal typing for process.env so we don't need @types/node just for this.
|
|
declare const process: { env: Record<string, string | undefined> };
|
|
|
|
// Where a `vite dev` session sends its API calls. Playpen prefers 8420 and walks
|
|
// upward if it's taken, so this is right unless you have two windows open — in
|
|
// which case read the real one out of PLAYPEN_REVIEW_URL in any of its terminals.
|
|
const apiPort = process.env.PLAYPEN_REVIEW_PORT || '8420';
|
|
const apiTarget = `http://127.0.0.1:${apiPort}`;
|
|
|
|
export default defineConfig({
|
|
plugins: [react()],
|
|
|
|
resolve: {
|
|
// The syntax highlighter runs in a worker (see src/lib/highlight.ts), and one
|
|
// package deep under refractor — decode-named-character-reference, pulled in
|
|
// by the markup language to decode HTML entities — ships a browser build
|
|
// that calls `document.createElement` at module scope. A worker has no
|
|
// document, so importing refractor there threw before a line was highlighted.
|
|
//
|
|
// The package publishes a document-free build for exactly this case and
|
|
// lists it first in its export map, under `worker`. Asking for that
|
|
// condition is what picks it up. It resolves for the main bundle too, which
|
|
// is what we want: it is the same function with a lookup table in place of
|
|
// the DOM's entity parser, and one implementation beats two.
|
|
conditions: ['worker'],
|
|
},
|
|
|
|
// Relative asset URLs, because the page is served from a tab's path
|
|
// (`/t/tab3/`) and not from the server root. With an absolute base the
|
|
// browser would ask for `/assets/app.js` and get the tab router instead.
|
|
base: './',
|
|
|
|
server: {
|
|
port: 5173,
|
|
proxy: {
|
|
// A tab's own API and event stream. Matched as a regex so the HTML at
|
|
// `/t/<id>/` still comes from Vite — only the calls underneath it are
|
|
// forwarded, which is what lets hot reloading work against a live review.
|
|
//
|
|
// Open http://localhost:5173/t/<tabId>/ to develop against a real tab.
|
|
'^/t/[^/]+/api': { target: apiTarget, changeOrigin: true },
|
|
// The app-wide endpoints: /api/tabs and /api/health.
|
|
'/api': { target: apiTarget, changeOrigin: true },
|
|
},
|
|
},
|
|
|
|
build: {
|
|
outDir: 'dist',
|
|
emptyOutDir: true,
|
|
|
|
// Fixed filenames rather than Vite's content hashes. The bundle is embedded
|
|
// in the playpen binary (src/review/assets.zig), so the Zig side has to be
|
|
// able to name the files at compile time — and cache busting buys nothing
|
|
// for a bundle that only changes when the binary does.
|
|
rollupOptions: {
|
|
output: {
|
|
entryFileNames: 'assets/app.js',
|
|
chunkFileNames: 'assets/app.js',
|
|
assetFileNames: 'assets/app[extname]',
|
|
// One file, so there is one name to embed. The app is a few hundred
|
|
// kilobytes loaded from localhost; splitting it saves nothing.
|
|
manualChunks: undefined,
|
|
},
|
|
},
|
|
},
|
|
});
|