Files
edr-platform/apps/edr-freight-web/backoffice/vite.config.ts
Dagimassefa b3bfa899f5 update
2026-06-22 12:29:48 +03:00

131 lines
4.2 KiB
TypeScript

import path from "node:path";
import { fileURLToPath } from "node:url";
import { createRequire } from "node:module";
import { defineConfig } from "vitest/config";
import { loadEnv, type Plugin } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const require = createRequire(import.meta.url);
const streamBrowserifyPath = require.resolve("stream-browserify");
function createIamApiAdapter(apiBaseUrl: string): Plugin {
const upstreamBaseUrl = `${apiBaseUrl.replace(/\/+$/, "")}/api`;
return {
name: "iam-api-adapter",
configureServer(server) {
server.middlewares.use("/um-api", async (req, res) => {
const requestPath = req.url ?? "/";
const normalizedPath = requestPath.replace(/^\/+/, "");
const targetUrl = new URL(normalizedPath, `${upstreamBaseUrl}/`);
try {
const headers = new Headers();
for (const [key, value] of Object.entries(req.headers)) {
if (!value || key.toLowerCase() === "host") {
continue;
}
if (Array.isArray(value)) {
for (const item of value) {
headers.append(key, item);
}
continue;
}
headers.set(key, value);
}
const body =
req.method === "GET" || req.method === "HEAD"
? undefined
: await new Promise<Buffer>((resolve, reject) => {
const chunks: Buffer[] = [];
req.on("data", (chunk) =>
chunks.push(
Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk),
),
);
req.on("end", () => resolve(Buffer.concat(chunks)));
req.on("error", reject);
});
const upstreamResponse = await fetch(targetUrl, {
method: req.method,
headers,
body,
});
if (targetUrl.pathname.endsWith("/auth/me")) {
const payload = await upstreamResponse.json();
const unwrappedPayload =
payload &&
typeof payload === "object" &&
"success" in payload &&
"data" in payload
? payload.data
: payload;
res.statusCode = upstreamResponse.status;
res.setHeader("content-type", "application/json; charset=utf-8");
res.end(JSON.stringify(unwrappedPayload));
return;
}
res.statusCode = upstreamResponse.status;
upstreamResponse.headers.forEach((value, key) => {
res.setHeader(key, value);
});
res.end(Buffer.from(await upstreamResponse.arrayBuffer()));
} catch (error) {
server.ssrFixStacktrace(error as Error);
res.statusCode = 502;
res.setHeader("content-type", "application/json; charset=utf-8");
res.end(
JSON.stringify({
message: "Failed to forward IAM request",
}),
);
}
});
},
};
}
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, __dirname, "");
const apiBaseUrl =
env.VITE_BASE_API_URL?.trim() || "http://localhost:3000";
return {
plugins: [react(), tailwindcss(), createIamApiAdapter(apiBaseUrl)],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
"node:buffer": "buffer",
"node:stream": streamBrowserifyPath,
// Resolve from TS source so Vite gets ESM named exports (dist is CommonJS).
"@edr/types": path.resolve(
__dirname,
"../../../packages/types/src/index.ts",
),
},
// Force a single copy of these singletons so MantineProvider context is
// shared between the backoffice app and @edr/ui-common (which ships its
// own node_modules copy). Without this, two separate @mantine/core
// instances are bundled and the context lookup fails at runtime.
dedupe: ["react", "react-dom", "@mantine/core", "@mantine/hooks"],
},
server: {
port: 5183,
host: "0.0.0.0",
},
test: {
environment: "node",
},
};
});