Files
bodyshop/client/vite.config.js

305 lines
8.9 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);
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: "http://localhost:4000",
secure: false,
ws: true
},
"/wss": {
target: "http://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: "http://localhost:4000",
rewriteWsOrigin: true,
secure: false,
ws: true
},
"/wss": {
target: "http://localhost:4000",
rewriteWsOrigin: true,
secure: false,
ws: true
},
"/api": {
target: "http://localhost:4000",
changeOrigin: true,
secure: false,
ws: false
}
}
},
build: {
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
antd: ["antd"],
"react-redux": ["react-redux"],
redux: ["redux"],
lodash: ["lodash"],
"@sentry/react": ["@sentry/react"],
"@splitsoftware/splitio-react": ["@splitsoftware/splitio-react"],
logrocket: ["logrocket"],
firebase: [
"@firebase/analytics",
"@firebase/app",
"@firebase/firestore",
"@firebase/auth",
"@firebase/messaging"
],
markerjs2: ["markerjs2"],
"@apollo/client": ["@apollo/client"],
"libphonenumber-js": ["libphonenumber-js"],
recharts: ["recharts"]
}
}
},
cssMinify: "lightningcss"
},
// Strip console/debugger in prod to shrink bundles
esbuild: {
// drop: mode === "production" ? ["console", "debugger"] : [],
legalComments: "none" // Remove license comments in production
},
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"
],
esbuildOptions: {
loader: { ".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 }
}
}
};
});