91 lines
4.0 KiB
TypeScript
91 lines
4.0 KiB
TypeScript
import { createHash } from 'node:crypto'
|
|
import { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
|
|
import path from 'node:path'
|
|
import { defineConfig, 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.
|
|
// Stable entry point for hosts: never hashed, always present next to the build.
|
|
//
|
|
// Content is JSON, but the extension is .js on purpose: the Bitrix stand's
|
|
// nginx serves static straight from disk only for a fixed extension list
|
|
// (js|css|html|svg|png|...), and `json` is not in it — a .json file falls
|
|
// through to the Bitrix PHP router and comes back as a 404 HTML page
|
|
// (verified on the stand). `.js` is the one extension guaranteed to be served
|
|
// anywhere this build is deployed, since the build itself depends on it.
|
|
const MANIFEST_FILE_NAME = 'app-manifest.js'
|
|
|
|
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)
|
|
const fileName = `index-${hash}.html`
|
|
renameSync(htmlPath, path.resolve(outDir, fileName))
|
|
|
|
// Manifest with a STABLE name, so an embedding host can look the hashed
|
|
// entry up at runtime instead of hardcoding it (and re-deploying itself
|
|
// on every rebuild of this app). See docs/bitrix-integration.md §7.
|
|
writeFileSync(
|
|
path.resolve(outDir, MANIFEST_FILE_NAME),
|
|
`${JSON.stringify({ index: fileName }, null, 2)}
|
|
`,
|
|
)
|
|
},
|
|
}
|
|
}
|
|
|
|
// https://vite.dev/config/
|
|
export default defineConfig(() => {
|
|
return {
|
|
// Relative, so the build works from any directory it gets deployed to
|
|
// without being told where that is. The host always opens a concrete file
|
|
// (index-<hash>.html, see hashIndexHtml below), so asset URLs resolve
|
|
// against that file's own location — there is no client-side routing that
|
|
// would need an absolute base. This replaces the earlier VITE_BASE_PATH:
|
|
// a build-time path that had to match the deploy directory exactly, and
|
|
// silently produced a blank iframe when it didn't (html loads, its JS 404s).
|
|
base: './',
|
|
plugins: [react(), hashIndexHtml()],
|
|
// Порт фиксирован: portal-front проксирует сюда сборку в dev-режиме
|
|
// (см. docs/portal-front-integration.md, раздел 2). strictPort, чтобы
|
|
// при занятом порте preview падал, а не уезжал на соседний молча.
|
|
preview: {
|
|
port: 5800,
|
|
strictPort: true,
|
|
},
|
|
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]',
|
|
},
|
|
},
|
|
},
|
|
}
|
|
})
|