import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import fs from 'fs' import path from 'path' import { fileURLToPath } from 'url' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const cesiumSource = path.join(__dirname, 'node_modules', 'cesium', 'Build', 'Cesium') const modelSource = path.join(__dirname, 'model') function copyDir(source, target) { fs.mkdirSync(target, { recursive: true }) for (const entry of fs.readdirSync(source, { withFileTypes: true })) { const sourcePath = path.join(source, entry.name) const targetPath = path.join(target, entry.name) if (entry.isDirectory()) { copyDir(sourcePath, targetPath) } else { fs.copyFileSync(sourcePath, targetPath) } } } function cesiumAssetsPlugin() { let outDir = path.join(__dirname, 'wwwroot') const serveStatic = (root, req, res, next) => { const urlPath = decodeURIComponent((req.url || '').split('?')[0]).replace(/^\/+/, '') const filePath = path.normalize(path.join(root, urlPath)) if (!filePath.startsWith(root) || !fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) { next() return } const contentType = filePath.endsWith('.js') ? 'application/javascript' : filePath.endsWith('.css') ? 'text/css' : filePath.endsWith('.json') ? 'application/json' : filePath.endsWith('.glb') ? 'model/gltf-binary' : 'application/octet-stream' res.setHeader('Content-Type', contentType) fs.createReadStream(filePath).pipe(res) } return { name: 'ecap-cesium-assets', configResolved(config) { outDir = path.isAbsolute(config.build.outDir) ? config.build.outDir : path.join(config.root, config.build.outDir) }, configureServer(server) { server.middlewares.use('/ui/cesium', (req, res, next) => { serveStatic(cesiumSource, req, res, next) }) server.middlewares.use('/ui/model', (req, res, next) => { serveStatic(modelSource, req, res, next) }) }, closeBundle() { copyDir(cesiumSource, path.join(outDir, 'cesium')) copyDir(modelSource, path.join(outDir, 'model')) } } } const spaAliasPaths = new Set([ '/map', '/map3d', '/dsp', '/aircraftlist', '/settings', '/ui/map', '/ui/map3d', '/ui/dsp', '/ui/aircraftlist', '/ui/settings' ]) function spaAliasesPlugin() { return { name: 'ecap-spa-aliases', configureServer(server) { server.middlewares.use(async (req, res, next) => { const urlPath = decodeURIComponent((req.url || '').split('?')[0]) if (!spaAliasPaths.has(urlPath)) { next() return } try { const indexPath = path.join(__dirname, 'index.html') let html = fs.readFileSync(indexPath, 'utf-8') html = await server.transformIndexHtml('/ui/index.html', html) res.statusCode = 200 res.setHeader('Content-Type', 'text/html') res.end(html) } catch (error) { next(error) } }) } } } // https://vite.dev/config/ export default defineConfig({ base: '/ui/', publicDir: 'public', // 默认就是 public define: { CESIUM_BASE_URL: JSON.stringify('/ui/cesium/') }, plugins: [react(), cesiumAssetsPlugin(), spaAliasesPlugin()], server: { proxy: { '/map/imagery': { target: 'http://127.0.0.1', changeOrigin: true, }, '/map/terrain': { target: 'http://127.0.0.1', changeOrigin: true, }, '/map/resources': { target: 'http://127.0.0.1', changeOrigin: true, }, '/map/graphics': { target: 'http://127.0.0.1', changeOrigin: true, }, '/map/view': { target: 'http://127.0.0.1', changeOrigin: true, }, '/map/models': { target: 'http://127.0.0.1', changeOrigin: true, }, '/tiles': { target: 'http://127.0.0.1', changeOrigin: true, }, '/api': { target: 'http://127.0.0.1', changeOrigin: true, }, '/ws': { target: 'http://127.0.0.1', // drogon 的端口!! ws: true, // ☆ 必须 ☆ changeOrigin: true }, '/aircraftlist.json': { target: 'http://127.0.0.1' }, }, fs:{ strict: false } }, build: { outDir: 'wwwroot' } })