71 lines
2.7 KiB
JavaScript
71 lines
2.7 KiB
JavaScript
import { defineConfig } from "vite";
|
|
|
|
// The ported desktop modules import node:* modules; in the browser they map to small shims.
|
|
// Root-relative paths on purpose: an absolute path made "node:fs" a different module URL than the
|
|
// worker's own "./vfs.js" import, so two vfs instances existed and the ported modules saw no mounts.
|
|
const nodeShims = {
|
|
"node:fs": "/src/worker/vfs.js",
|
|
"node:fs/promises": "/src/worker/shims/fs-promises.js",
|
|
"node:zlib": "/src/worker/shims/zlib.js",
|
|
"node:crypto": "/src/worker/shims/crypto.js",
|
|
"node:path": "path-browserify",
|
|
path: "path-browserify",
|
|
"node:os": "/src/worker/shims/os.js",
|
|
"node:child_process": "/src/worker/shims/child_process.js",
|
|
electron: "/src/worker/shims/electron.js",
|
|
};
|
|
|
|
// Exact matches only: "node:fs" must not also rewrite "node:fs/promises".
|
|
const aliases = Object.entries(nodeShims).map(([find, replacement]) => ({ find: new RegExp(`^${find.replace(/[/:]/g, "\\$&")}$`), replacement }));
|
|
|
|
// Dev only: /__testgame/<file> serves files from LSTOOLS_TEST_DIR (a COPY of a client folder is
|
|
// best), used with ?devgame=rs.iop,map.iop to test pages without the native folder picker.
|
|
const testGame = {
|
|
name: "losadev-test-game",
|
|
apply: "serve",
|
|
configureServer(server) {
|
|
const dir = process.env.LSTOOLS_TEST_DIR;
|
|
if (!dir) return;
|
|
// Range requests: the worker reads the packs piecewise with sync XHR (vfs.remoteFile).
|
|
server.middlewares.use("/__testgame/", async (req, res) => {
|
|
const { createReadStream, statSync } = await import("node:fs");
|
|
const { join, basename } = await import("node:path");
|
|
const name = basename(decodeURIComponent(req.url.split("?")[0]));
|
|
const file = join(dir, name);
|
|
let size;
|
|
try {
|
|
size = statSync(file).size;
|
|
} catch {
|
|
res.statusCode = 404;
|
|
return res.end();
|
|
}
|
|
res.setHeader("Accept-Ranges", "bytes");
|
|
res.setHeader("Cache-Control", "no-store");
|
|
if (req.method === "HEAD") {
|
|
res.setHeader("Content-Length", size);
|
|
return res.end();
|
|
}
|
|
const m = /bytes=(\d+)-(\d*)/.exec(req.headers.range || "");
|
|
if (m) {
|
|
const start = Number(m[1]);
|
|
const end = Math.min(size - 1, m[2] ? Number(m[2]) : size - 1);
|
|
res.statusCode = 206;
|
|
res.setHeader("Content-Range", `bytes ${start}-${end}/${size}`);
|
|
res.setHeader("Content-Length", end - start + 1);
|
|
return createReadStream(file, { start, end }).pipe(res);
|
|
}
|
|
res.setHeader("Content-Length", size);
|
|
createReadStream(file).pipe(res);
|
|
});
|
|
},
|
|
};
|
|
|
|
export default defineConfig({
|
|
server: { port: 4700 },
|
|
plugins: [testGame],
|
|
define: { __LEGACY_VER__: JSON.stringify(String(Date.now())) },
|
|
resolve: { alias: aliases },
|
|
worker: { format: "es", plugins: () => [] },
|
|
build: { target: "es2022", sourcemap: true },
|
|
});
|