website
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
/.cache
|
||||
/build
|
||||
.env
|
||||
.react-router
|
||||
.DS_Store
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.ts",
|
||||
"css": "src/styles/globals.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "website/src/components",
|
||||
"utils": "website/src/lib/utils",
|
||||
"ui": "website/src/components/ui",
|
||||
"lib": "website/src/lib",
|
||||
"hooks": "website/src/lib/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "website",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "react-router build",
|
||||
"dev": "react-router dev --port 8044",
|
||||
"start": "node ./build/server/server.js",
|
||||
"typecheck": "react-router typegen && tsc"
|
||||
},
|
||||
"exports": {
|
||||
"./*": "./*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"@react-router/fs-routes": "^7.11.0",
|
||||
"@react-router/node": "^7.11.0",
|
||||
"@sentry/node": "^10.32.1",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"isbot": "^5.1.32",
|
||||
"lucide-react": "^0.562.0",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-router": "^7.11.0",
|
||||
"sentries": "^0.2.2",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"tw-animate-css": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-router/dev": "^7.11.0",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@types/node": "^25.0.3",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"@xmorse/deployment-utils": "^0.7.2",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.0",
|
||||
"vite-plugin-environment": "^1.1.3",
|
||||
"vite-tsconfig-paths": "^6.0.3",
|
||||
"vitest": "^4.0.16"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,6 @@
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
appDirectory: "src",
|
||||
prerender: ["/", "/defer-example"],
|
||||
} satisfies Config;
|
||||
@@ -0,0 +1,7 @@
|
||||
import { startTransition } from "react";
|
||||
import { hydrateRoot } from "react-dom/client";
|
||||
import { HydratedRouter } from "react-router/dom";
|
||||
|
||||
startTransition(() => {
|
||||
hydrateRoot(document, <HydratedRouter />);
|
||||
});
|
||||
@@ -0,0 +1,163 @@
|
||||
import { PassThrough } from "node:stream";
|
||||
import { createReadableStreamFromReadable } from "@react-router/node";
|
||||
import { isbot } from "isbot";
|
||||
import { renderToPipeableStream } from "react-dom/server";
|
||||
import type {
|
||||
ActionFunctionArgs,
|
||||
AppLoadContext,
|
||||
EntryContext,
|
||||
LoaderFunctionArgs,
|
||||
} from "react-router";
|
||||
import { isRouteErrorResponse, ServerRouter } from "react-router";
|
||||
import { notifyError } from "./lib/errors";
|
||||
|
||||
export const streamTimeout = 60 * 20 * 1_000;
|
||||
|
||||
export default function handleRequest(
|
||||
request: Request,
|
||||
responseStatusCode: number,
|
||||
responseHeaders: Headers,
|
||||
reactRouterContext: EntryContext,
|
||||
// This is ignored so we can keep it in the template for visibility. Feel
|
||||
// free to delete this parameter in your app if you're not using it!
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
loadContext: AppLoadContext
|
||||
) {
|
||||
return isbot(request.headers.get("user-agent") || "")
|
||||
? handleBotRequest(
|
||||
request,
|
||||
responseStatusCode,
|
||||
responseHeaders,
|
||||
reactRouterContext
|
||||
)
|
||||
: handleBrowserRequest(
|
||||
request,
|
||||
responseStatusCode,
|
||||
responseHeaders,
|
||||
reactRouterContext
|
||||
);
|
||||
}
|
||||
|
||||
function handleBotRequest(
|
||||
request: Request,
|
||||
responseStatusCode: number,
|
||||
responseHeaders: Headers,
|
||||
reactRouterContext: EntryContext
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let shellRendered = false;
|
||||
let timeoutId: NodeJS.Timeout;
|
||||
const { pipe, abort } = renderToPipeableStream(
|
||||
<ServerRouter
|
||||
context={reactRouterContext}
|
||||
url={request.url}
|
||||
// abortDelay={ABORT_DELAY}
|
||||
/>,
|
||||
{
|
||||
onAllReady() {
|
||||
shellRendered = true;
|
||||
const body = new PassThrough();
|
||||
const stream = createReadableStreamFromReadable(body);
|
||||
|
||||
responseHeaders.set("Content-Type", "text/html");
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
resolve(
|
||||
new Response(stream, {
|
||||
headers: responseHeaders,
|
||||
status: responseStatusCode,
|
||||
})
|
||||
);
|
||||
|
||||
pipe(body);
|
||||
},
|
||||
onShellError(error: unknown) {
|
||||
clearTimeout(timeoutId);
|
||||
reject(error);
|
||||
},
|
||||
onError(error: unknown) {
|
||||
responseStatusCode = 500;
|
||||
// Log streaming rendering errors from inside the shell. Don't log
|
||||
// errors encountered during initial shell rendering since they'll
|
||||
// reject and get logged in handleDocumentRequest.
|
||||
if (shellRendered) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
timeoutId = setTimeout(abort, streamTimeout);
|
||||
});
|
||||
}
|
||||
|
||||
function handleBrowserRequest(
|
||||
request: Request,
|
||||
responseStatusCode: number,
|
||||
responseHeaders: Headers,
|
||||
reactRouterContext: EntryContext
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let shellRendered = false;
|
||||
let timeoutId: NodeJS.Timeout;
|
||||
const { pipe, abort } = renderToPipeableStream(
|
||||
<ServerRouter
|
||||
context={reactRouterContext}
|
||||
url={request.url}
|
||||
// abortDelay={ABORT_DELAY}
|
||||
/>,
|
||||
{
|
||||
onShellReady() {
|
||||
shellRendered = true;
|
||||
const body = new PassThrough();
|
||||
const stream = createReadableStreamFromReadable(body);
|
||||
|
||||
responseHeaders.set("Content-Type", "text/html");
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
resolve(
|
||||
new Response(stream, {
|
||||
headers: responseHeaders,
|
||||
status: responseStatusCode,
|
||||
})
|
||||
);
|
||||
|
||||
pipe(body);
|
||||
},
|
||||
onShellError(error: unknown) {
|
||||
clearTimeout(timeoutId);
|
||||
reject(error);
|
||||
},
|
||||
onError(error: unknown) {
|
||||
responseStatusCode = 500;
|
||||
// Log streaming rendering errors from inside the shell. Don't log
|
||||
// errors encountered during initial shell rendering since they'll
|
||||
// reject and get logged in handleDocumentRequest.
|
||||
if (shellRendered) {
|
||||
console.error(error);
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
timeoutId = setTimeout(abort, streamTimeout);
|
||||
});
|
||||
}
|
||||
|
||||
export function handleError(
|
||||
error: any,
|
||||
{ request, params, context }: LoaderFunctionArgs | ActionFunctionArgs
|
||||
) {
|
||||
// https://github.com/remix-run/remix/discussions/8933
|
||||
if (request.signal.aborted || isRouteErrorResponse(error)) {
|
||||
return;
|
||||
}
|
||||
if (error?.["status"] === 404) {
|
||||
return;
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
notifyError(error, "unhandled remix error");
|
||||
} else {
|
||||
console.error("error", error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { captureException, flush, init } from "sentries";
|
||||
|
||||
init({
|
||||
dsn: "https://3e3f1075fec9ee2de1e0f79026b5f734@o4508014272446464.ingest.de.sentry.io/4508014292697168",
|
||||
integrations: [],
|
||||
tracesSampleRate: 0.01,
|
||||
profilesSampleRate: 0.01,
|
||||
beforeSend(event) {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return null;
|
||||
}
|
||||
if (process.env.BYTECODE_RUN) {
|
||||
return null;
|
||||
}
|
||||
if (event?.["name"] === "AbortError") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return event;
|
||||
},
|
||||
});
|
||||
|
||||
export async function notifyError(error: any, msg?: string) {
|
||||
console.error(msg, error);
|
||||
captureException(error, { extra: { msg } });
|
||||
await flush(1000);
|
||||
}
|
||||
|
||||
export class AppError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "AppError";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export const sleep = (ms: number): Promise<void> => {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
};
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import "website/src/styles/globals.css";
|
||||
import { Route } from "./+types/root";
|
||||
import {
|
||||
isRouteErrorResponse,
|
||||
Links,
|
||||
Meta,
|
||||
Outlet,
|
||||
Scripts,
|
||||
ScrollRestoration,
|
||||
} from "react-router";
|
||||
|
||||
export function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html className="" lang="en">
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<Meta />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
{children}
|
||||
<ScrollRestoration />
|
||||
<Scripts />
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
|
||||
if (isRouteErrorResponse(error)) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen p-8 text-center">
|
||||
<h1 className="text-4xl font-bold mb-4">
|
||||
{error.status} {error.statusText}
|
||||
</h1>
|
||||
<p className="text-lg text-gray-600">{error.data}</p>
|
||||
</div>
|
||||
);
|
||||
} else if (error instanceof Error) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen p-8 text-center max-w-4xl mx-auto">
|
||||
<h1 className="text-4xl font-bold mb-4">Error</h1>
|
||||
<p className="text-lg text-gray-600 mb-6">{error.message}</p>
|
||||
<p className="text-sm text-gray-500 mb-2">The stack trace is:</p>
|
||||
<pre className="bg-gray-100 p-4 rounded-lg text-xs text-left overflow-auto max-w-full border">
|
||||
{error.stack}
|
||||
</pre>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<h1 className="text-4xl font-bold text-center">Unknown Error</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return <Outlet />;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import type { RouteConfig } from "@react-router/dev/routes";
|
||||
import { flatRoutes } from "@react-router/fs-routes";
|
||||
|
||||
export default flatRoutes() satisfies RouteConfig;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { redirect } from 'react-router';
|
||||
|
||||
export const loader = () => {
|
||||
return redirect('https://github.com/remorses/playwriter');
|
||||
};
|
||||
|
||||
export default function Index() {
|
||||
return null;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
import { sleep } from "../lib/utils";
|
||||
import { Route } from "./+types/defer-example";
|
||||
|
||||
async function getProjectLocation() {
|
||||
return Promise.resolve().then(() => sleep(1000).then(() => "hi"));
|
||||
}
|
||||
|
||||
export async function loader({}: Route.LoaderArgs) {
|
||||
return {
|
||||
project: getProjectLocation(),
|
||||
};
|
||||
}
|
||||
|
||||
export default function ProjectRoute({ loaderData }: Route.ComponentProps) {
|
||||
const location = React.use(loaderData.project);
|
||||
|
||||
return (
|
||||
<main>
|
||||
<h1>Let's locate your project</h1>
|
||||
<p>Your project is at {location}.</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
@import "tailwindcss";
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
:root {
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.141 0.005 285.823);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.141 0.005 285.823);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.141 0.005 285.823);
|
||||
--primary: oklch(0.21 0.006 285.885);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.967 0.001 286.375);
|
||||
--secondary-foreground: oklch(0.21 0.006 285.885);
|
||||
--muted: oklch(0.967 0.001 286.375);
|
||||
--muted-foreground: oklch(0.552 0.016 285.938);
|
||||
--accent: oklch(0.967 0.001 286.375);
|
||||
--accent-foreground: oklch(0.21 0.006 285.885);
|
||||
--destructive: oklch(0.637 0.237 25.331);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.92 0.004 286.32);
|
||||
--input: oklch(0.871 0.006 286.286);
|
||||
--ring: oklch(0.871 0.006 286.286);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--radius: 0.625rem;
|
||||
--sidebar: oklch(0.21 0.006 285.885);
|
||||
--sidebar-foreground: oklch(0.871 0.006 286.286);
|
||||
--sidebar-primary: oklch(0.37 0.013 285.805);
|
||||
--sidebar-primary-foreground: oklch(0.871 0.006 286.286);
|
||||
--sidebar-accent: oklch(0.274 0.006 286.033);
|
||||
--sidebar-accent-foreground: oklch(0.871 0.006 286.286);
|
||||
--sidebar-border: oklch(0.92 0.004 286.32);
|
||||
--sidebar-ring: oklch(0.871 0.006 286.286);
|
||||
}
|
||||
.dark {
|
||||
--background: oklch(0.21 0.006 285.885);
|
||||
--foreground: oklch(0.985 0 0);
|
||||
--card: oklch(0.21 0.006 285.885);
|
||||
--card-foreground: oklch(0.985 0 0);
|
||||
--popover: oklch(0.21 0.006 285.885);
|
||||
--popover-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.985 0 0);
|
||||
--primary-foreground: oklch(0.21 0.006 285.885);
|
||||
--secondary: oklch(0.274 0.006 286.033);
|
||||
--secondary-foreground: oklch(0.985 0 0);
|
||||
--muted: oklch(0.274 0.006 286.033);
|
||||
--muted-foreground: oklch(0.705 0.015 286.067);
|
||||
--accent: oklch(0.274 0.006 286.033);
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.637 0.237 25.331);
|
||||
--destructive-foreground: oklch(0.637 0.237 25.331);
|
||||
--border: oklch(0.274 0.006 286.033);
|
||||
--input: oklch(0.274 0.006 286.033);
|
||||
--ring: oklch(0.442 0.017 285.786);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: #000;
|
||||
--sidebar-foreground: oklch(0.871 0.006 286.286);
|
||||
--sidebar-primary: oklch(0.37 0.013 285.805);
|
||||
--sidebar-primary-foreground: oklch(0.871 0.006 286.286);
|
||||
--sidebar-accent: oklch(0.274 0.006 286.033);
|
||||
--sidebar-accent-foreground: oklch(0.871 0.006 286.286);
|
||||
--sidebar-border: oklch(0.274 0.006 286.033);
|
||||
--sidebar-ring: oklch(0.442 0.017 285.786);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
|
||||
--radius-lg: var(--radius);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom scrollbar styles: shadcn-inspired */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: transparent;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--color-muted);
|
||||
border-radius: var(--radius-md);
|
||||
border: none;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-muted-foreground);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"include": ["src"],
|
||||
"compilerOptions": {
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
||||
"types": ["@react-router/node", "vite/client", "@types/node"],
|
||||
"isolatedModules": true,
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react-jsx",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"target": "ES2022",
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"allowArbitraryExtensions": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"noImplicitAny": false,
|
||||
"useUnknownInCatchVariables": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"rootDirs": [".", "./.react-router/types"],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"website/*": ["./*"]
|
||||
},
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/// <reference types="vitest/config" />
|
||||
import { reactRouter } from "@react-router/dev/vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import EnvironmentPlugin from "vite-plugin-environment";
|
||||
import { defineConfig } from "vite";
|
||||
import {
|
||||
viteExternalsPlugin,
|
||||
enablePreserveModulesPlugin,
|
||||
} from "@xmorse/deployment-utils/dist/vite-externals-plugin.js";
|
||||
import { reactRouterServerPlugin } from "@xmorse/deployment-utils/dist/react-router.js";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
|
||||
const NODE_ENV = JSON.stringify(process.env.NODE_ENV || "production");
|
||||
|
||||
export default defineConfig({
|
||||
clearScreen: false,
|
||||
define: {
|
||||
"process.env.NODE_ENV": NODE_ENV,
|
||||
},
|
||||
test: {
|
||||
pool: "threads",
|
||||
exclude: ["**/dist/**", "**/esm/**", "**/node_modules/**", "**/e2e/**"],
|
||||
poolOptions: {
|
||||
threads: {
|
||||
isolate: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
EnvironmentPlugin("all", { prefix: "PUBLIC" }),
|
||||
EnvironmentPlugin("all", { prefix: "NEXT_PUBLIC" }),
|
||||
process.env.VITEST ? react() : reactRouter(),
|
||||
tsconfigPaths(),
|
||||
// viteExternalsPlugin({
|
||||
// externals: ["@sentry/node"],
|
||||
// }),
|
||||
// enablePreserveModulesPlugin(),
|
||||
reactRouterServerPlugin({ port: process.env.PORT || '8044' }),
|
||||
tailwindcss(),
|
||||
],
|
||||
build: {
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user