Files
eacp_webapp/vite.config.js
T
2026-08-10 14:51:03 +08:00

234 lines
7.5 KiB
JavaScript

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')
const adminiveFrontend = path.join(__dirname, '..', 'Adminive', 'frontend')
const amisSdkSource = path.join(adminiveFrontend, 'node_modules', 'amis', 'sdk')
const amisPackage = JSON.parse(fs.readFileSync(path.join(adminiveFrontend, 'node_modules', 'amis', 'package.json'), 'utf8'))
const amisSdkUrlPrefix = `/ui/vendor/amis/${amisPackage.version}/`
function amisContentType(fileName) {
const extension = path.extname(fileName).toLowerCase()
if (extension === '.css') return 'text/css; charset=utf-8'
if (extension === '.js') return 'text/javascript; charset=utf-8'
if (extension === '.json') return 'application/json; charset=utf-8'
if (extension === '.svg') return 'image/svg+xml'
if (extension === '.woff') return 'font/woff'
if (extension === '.woff2') return 'font/woff2'
if (extension === '.ttf') return 'font/ttf'
return 'application/octet-stream'
}
function serveAmisSdk(server) {
server.middlewares.use((request, response, next) => {
const pathname = new URL(request.url || '/', 'http://localhost').pathname
if (!pathname.startsWith(amisSdkUrlPrefix)) {
next()
return
}
const relativePath = decodeURIComponent(pathname.slice(amisSdkUrlPrefix.length))
const sourcePath = path.resolve(amisSdkSource, relativePath)
if (sourcePath !== amisSdkSource && !sourcePath.startsWith(`${amisSdkSource}${path.sep}`)) {
next()
return
}
try {
response.statusCode = 200
response.setHeader('Content-Type', amisContentType(sourcePath))
response.end(fs.readFileSync(sourcePath))
} catch {
next()
}
})
}
function amisSdkPlugin() {
return {
name: 'ecap-adminive-amis-sdk',
enforce: 'pre',
resolveId(source) {
if (source === 'amis' || source.startsWith('amis/')) {
this.error(`Do not import ${source} into the Vite module graph; use the AMIS SDK runtime`)
}
return null
},
buildStart() {
const emitDirectory = (directory, prefix) => {
for (const entry of fs.readdirSync(directory)) {
const sourcePath = path.join(directory, entry)
const relativePath = `${prefix}${entry}`
if (fs.statSync(sourcePath).isDirectory()) {
emitDirectory(sourcePath, `${relativePath}/`)
} else {
this.emitFile({type: 'asset', fileName: `vendor/amis/${amisPackage.version}/${relativePath}`, source: fs.readFileSync(sourcePath)})
}
}
}
emitDirectory(amisSdkSource, '')
},
transformIndexHtml: {
order: 'post',
handler() {
return [
{tag: 'link', attrs: {rel: 'stylesheet', href: `${amisSdkUrlPrefix}sdk.css`}, injectTo: 'head-prepend'},
{tag: 'link', attrs: {rel: 'stylesheet', href: `${amisSdkUrlPrefix}helper.css`}, injectTo: 'head-prepend'},
{tag: 'link', attrs: {rel: 'stylesheet', href: `${amisSdkUrlPrefix}iconfont.css`}, injectTo: 'head-prepend'},
{tag: 'script', attrs: {src: `${amisSdkUrlPrefix}sdk.js`}, injectTo: 'head-prepend'}
]
}
},
configureServer(server) {
serveAmisSdk(server)
},
configurePreviewServer(server) {
serveAmisSdk(server)
}
}
}
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',
'/aircraftlist',
'/settings',
'/topology',
'/ui/map',
'/ui/map3d',
'/ui/aircraftlist',
'/ui/settings',
'/ui/topology'
])
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(), amisSdkPlugin(), 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'
}
})