import { createHash } from 'node:crypto' import { existsSync, readFileSync, renameSync } from 'node:fs' import path from 'node:path' import { defineConfig, loadEnv, type Plugin } from 'vite' import react from '@vitejs/plugin-react' // Vite always writes the HTML entry under its source name (index.html stays // index.html) — it only content-hashes what that HTML references (JS/CSS), // never the HTML file itself. The backend now reads the actual deployed // filename at deploy time instead of hardcoding it on the main portal, so // index.html needs a unique name too. // // index.html isn't part of the same bundle object the JS/CSS live in // (confirmed empirically — it never showed up in generateBundle's `bundle`), // so this hashes and renames the file directly on disk after the whole build // has finished writing it, rather than fighting the bundler's own emit step. function hashIndexHtml(): Plugin { let outDir = 'dist' return { name: 'hash-index-html', apply: 'build', configResolved(config) { outDir = config.build.outDir }, closeBundle() { const htmlPath = path.resolve(outDir, 'index.html') if (!existsSync(htmlPath)) return // Hashing the final content (already contains the hashed JS/CSS refs) // means this name only changes when something meaningful actually did. const hash = createHash('md5').update(readFileSync(htmlPath)).digest('hex').slice(0, 8) renameSync(htmlPath, path.resolve(outDir, `index-${hash}.html`)) }, } } // https://vite.dev/config/ export default defineConfig(({ mode }) => { // VITE_BASE_PATH is read here (config/Node context), so it needs an explicit // loadEnv call — unlike VITE_BITRIX_ORIGIN, which Vite injects into // import.meta.env automatically because it's only read from app code. const env = loadEnv(mode, process.cwd(), '') return { // Needed when the build is served from a subpath (e.g. local/diagram-app/ // inside the Bitrix docroot) instead of domain root — see // docs/bitrix-integration.md §7. base: env.VITE_BASE_PATH || '/', plugins: [react(), hashIndexHtml()], build: { // Same content hash Vite computes by default — just without its default // "assets/" subfolder prefix. The deploy target's own folder is itself // named assets (local/modules/vniigaz.bpmn/assets/), so keeping Vite's // default pattern would nest output at .../assets/assets/index-*.js (404). rolldownOptions: { output: { entryFileNames: '[name]-[hash].js', chunkFileNames: '[name]-[hash].js', assetFileNames: '[name]-[hash][extname]', }, }, }, } })