Files
bodyshop/client/vite.config.js
2026-03-16 11:02:48 -04:00

312 lines
9.6 KiB
JavaScript

/* eslint-disable */
import { sentryVitePlugin } from "@sentry/vite-plugin";
import react from "@vitejs/plugin-react";
import chalk from "chalk";
import * as child from "child_process";
import { promises as fsPromises } from "fs";
import { createLogger, defineConfig } from "vite";
import { ViteEjsPlugin } from "vite-plugin-ejs";
import eslint from "vite-plugin-eslint";
import { VitePWA } from "vite-plugin-pwa";
import InstanceRenderManager from "./src/utils/instanceRenderMgr";
import browserslist from "browserslist";
import { browserslistToTargets } from "lightningcss";
import { fileURLToPath } from "url";
import { dirname, resolve } from "path";
process.env.VITE_APP_GIT_SHA_DATE = new Date().toLocaleString("en-US", { timeZone: "America/Los_Angeles" });
const commitHash = child.execSync("git rev-parse HEAD").toString().trimEnd();
process.env.VITE_GIT_COMMIT_HASH = commitHash;
// Resolve browserslist from package.json and map to Lightning CSS targets
const lightningCssTargets = browserslistToTargets(
browserslist(undefined, {
path: process.cwd(),
env: process.env.NODE_ENV === "production" ? "production" : "development"
})
);
const pstFormatter = new Intl.DateTimeFormat("en-CA", {
timeZone: "America/Los_Angeles",
year: "numeric",
month: "2-digit",
day: "2-digit"
});
const currentDatePST = pstFormatter.format(new Date());
const getFormattedTimestamp = () =>
new Date().toLocaleTimeString("en-US", { hour12: true }).replace("AM", "a.m.").replace("PM", "p.m.");
export const logger = createLogger("info", { allowClearScreen: false });
// Read HTTPS certs once (used by both server + preview)
const httpsCerts = {
key: await fsPromises.readFile("../certs/key.pem"),
cert: await fsPromises.readFile("../certs/cert.pem")
};
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const pathSeparatorPattern = String.raw`[\\/]`;
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const packageChunkTest = (packageNames) => {
const names = Array.isArray(packageNames) ? packageNames : [packageNames];
return new RegExp(
`${pathSeparatorPattern}node_modules${pathSeparatorPattern}(?:${names
.map((name) => name.split("/").map(escapeRegex).join(pathSeparatorPattern))
.join("|")})(?:${pathSeparatorPattern}|$)`
);
};
const vendorCodeSplittingGroups = [
{ name: "antd", test: packageChunkTest("antd"), priority: 100 },
{ name: "react-redux", test: packageChunkTest("react-redux"), priority: 95 },
{ name: "redux", test: packageChunkTest("redux"), priority: 90 },
{ name: "lodash", test: packageChunkTest("lodash"), priority: 85 },
{ name: "@sentry/react", test: packageChunkTest("@sentry/react"), priority: 80 },
{ name: "@splitsoftware/splitio-react", test: packageChunkTest("@splitsoftware/splitio-react"), priority: 75 },
{ name: "logrocket", test: packageChunkTest("logrocket"), priority: 70 },
{ name: "firebase", test: packageChunkTest("@firebase"), priority: 65 },
{ name: "markerjs2", test: packageChunkTest("markerjs2"), priority: 60 },
{ name: "@apollo/client", test: packageChunkTest("@apollo/client"), priority: 55 },
{ name: "libphonenumber-js", test: packageChunkTest("libphonenumber-js"), priority: 50 },
{ name: "recharts", test: packageChunkTest("recharts"), priority: 45 }
];
export default defineConfig(({ command, mode }) => {
// React Compiler is always enabled for production/test builds
// In dev mode, it's enabled by default but can be disabled with VITE_DISABLE_COMPILER_IN_DEV=true
const isBuild = command === "build";
const isTestBuild =
mode === "test" || process.env.VITE_APP_IS_TEST === "true" || process.env.VITE_APP_IS_TEST === "1";
const enableReactCompiler =
(isBuild && (mode === "production" || isTestBuild)) || // Always enable for prod/test builds
process.env?.VITE_DISABLE_COMPILER_IN_DEV !== "true"; // In dev, enable unless explicitly disabled
logger.info(
enableReactCompiler ? chalk.green.bold("React Compiler enabled") : chalk.yellow.bold("React Compiler disabled")
);
return {
base: "/",
resolve: {
dedupe: ["styled-components", "react", "react-dom"],
alias: {
// Force all styled-components imports to resolve to the same location (absolute path)
"styled-components": resolve(__dirname, "node_modules/styled-components/dist/styled-components.browser.esm.js")
}
},
plugins: [
ViteEjsPlugin((viteConfig) => ({ env: viteConfig.env })),
// PWA only for production builds (faster dev)
VitePWA({
apply: "build",
injectRegister: "auto",
registerType: "prompt",
workbox: {
navigateFallbackDenylist: [/^\/api\//] // prevent caching API routes
},
manifest: {
short_name: InstanceRenderManager({
instance: process.env.VITE_APP_INSTANCE,
imex: "ImEX Online",
rome: "Rome Online"
}),
name: InstanceRenderManager({
instance: process.env.VITE_APP_INSTANCE,
imex: "ImEX Online",
rome: "Rome Online"
}),
description: "The ultimate bodyshop management system.",
icons: [
{
src: InstanceRenderManager({
instance: process.env.VITE_APP_INSTANCE,
imex: "favicon.png",
rome: "ro-favicon.png"
}),
sizes: "64x64 32x32 24x24 16x16",
type: "image/x-icon"
},
{
src: InstanceRenderManager({
instance: process.env.VITE_APP_INSTANCE,
imex: "logo192.png",
rome: "logo192.png"
}),
type: "image/png",
sizes: "192x192"
},
{
src: InstanceRenderManager({
instance: process.env.VITE_APP_INSTANCE,
imex: "logo512.png",
rome: "ro-favicon.png"
}),
type: "image/png",
sizes: "512x512"
}
],
theme_color: InstanceRenderManager({
instance: process.env.VITE_APP_INSTANCE,
imex: "#1890ff",
rome: "#fff"
}),
background_color: "#fff",
gcm_sender_id: "103953800507"
}
}),
react(
enableReactCompiler
? {
babel: {
plugins: [["babel-plugin-react-compiler"]]
}
}
: undefined
),
eslint(),
// Sentry only for production builds (no dev overhead)
sentryVitePlugin({
apply: "build",
org: "imex",
reactComponentAnnotation: { enabled: true },
release: {
name: `${process.env.VITE_APP_IS_TEST ? "test" : "production"}-${currentDatePST}-${commitHash}`.trim()
},
project: InstanceRenderManager({
instance: process.env.VITE_APP_INSTANCE,
imex: "imexonline",
rome: "rome-online"
})
})
],
define: {
APP_VERSION: JSON.stringify(process.env.npm_package_version),
__COMMIT_HASH__: JSON.stringify(commitHash)
},
server: {
host: true,
port: 3000,
open: true,
proxy: {
"/ws": {
target: "ws://localhost:4000",
secure: false,
ws: true
},
"/wss": {
target: "ws://localhost:4000",
secure: false,
ws: true
},
"/api": {
target: "http://localhost:4000",
changeOrigin: true,
secure: false,
ws: false,
rewrite: (path) => {
const replacedValue = path.replace(/^\/api/, "");
logger.info(
`${chalk.grey.bold(getFormattedTimestamp())} ${chalk.cyan.bold("[vite]")} ${chalk.green.bold("[API]")} ${chalk.blue(replacedValue)}`
);
return replacedValue;
}
}
},
https: httpsCerts
},
preview: {
port: 6000,
host: true,
open: true,
https: httpsCerts,
proxy: {
"/ws": {
target: "ws://localhost:4000",
rewriteWsOrigin: true,
secure: false,
ws: true
},
"/wss": {
target: "ws://localhost:4000",
rewriteWsOrigin: true,
secure: false,
ws: true
},
"/api": {
target: "http://localhost:4000",
changeOrigin: true,
secure: false,
ws: false
}
}
},
build: {
sourcemap: true,
rolldownOptions: {
output: {
codeSplitting: {
groups: vendorCodeSplittingGroups
},
comments: {
legal: false
}
}
},
cssMinify: "lightningcss"
},
optimizeDeps: {
include: [
"react",
"react-dom",
"antd",
"lodash",
"@sentry/react",
"@apollo/client",
"@reduxjs/toolkit",
"axios",
"react-router-dom",
"dayjs",
"redux",
"react-redux",
"@firebase/app",
"@firebase/analytics",
"@firebase/firestore",
"@firebase/auth",
"@firebase/messaging",
"@firebase/util",
"styled-components"
],
rolldownOptions: {
moduleTypes: { ".jsx": "jsx", ".tsx": "tsx" }
},
// Force styled-components to be pre-bundled and deduplicated
force: mode === "development"
},
css: {
transformer: "lightningcss",
lightningcss: {
targets: lightningCssTargets
},
preprocessorOptions: {
scss: { quietDeps: true }
}
}
};
});