mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
* feat: add embedded GCode viewer Adds PrettyGCode as a built-in GCode visualiser embedded directly in the Bambuddy layout, so users can preview and inspect GCode files without leaving the dashboard.
103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
import { defineConfig } from 'vite'
|
|
import react from '@vitejs/plugin-react'
|
|
import path from 'path'
|
|
import fs from 'fs'
|
|
import type { Connect } from 'vite'
|
|
|
|
// Backend port for dev server proxy (default: 8000)
|
|
const backendPort = process.env.BACKEND_PORT || '8000'
|
|
const backendUrl = `http://localhost:${backendPort}`
|
|
|
|
// Absolute path to the gcode_viewer directory at the repo root
|
|
const gcodeViewerDir = path.resolve(__dirname, '../gcode_viewer')
|
|
|
|
// MIME types for static files served from gcode_viewer/
|
|
const MIME: Record<string, string> = {
|
|
'.html': 'text/html; charset=utf-8',
|
|
'.js': 'application/javascript',
|
|
'.css': 'text/css',
|
|
'.obj': 'model/obj',
|
|
'.mtl': 'model/mtl',
|
|
'.png': 'image/png',
|
|
'.jpg': 'image/jpeg',
|
|
'.svg': 'image/svg+xml',
|
|
'.json': 'application/json',
|
|
'.woff': 'font/woff',
|
|
'.woff2':'font/woff2',
|
|
}
|
|
|
|
/**
|
|
* Vite dev-server plugin: serves ../gcode_viewer/ at /gcode-viewer/
|
|
* without needing a proxy to uvicorn. In production uvicorn handles it
|
|
* via the StaticFiles mount in main.py.
|
|
*/
|
|
function serveGcodeViewer() {
|
|
return {
|
|
name: 'serve-gcode-viewer',
|
|
configureServer(server: { middlewares: Connect.Server }) {
|
|
server.middlewares.use((req, res, next) => {
|
|
const url = req.url ?? ''
|
|
if (!url.startsWith('/gcode-viewer')) return next()
|
|
|
|
// Strip prefix, default to index.html
|
|
let rel = url.slice('/gcode-viewer'.length)
|
|
if (rel === '' || rel === '/') rel = '/index.html'
|
|
// Strip query string
|
|
rel = rel.split('?')[0]
|
|
|
|
const absPath = path.join(gcodeViewerDir, rel)
|
|
|
|
try {
|
|
const stat = fs.statSync(absPath)
|
|
if (stat.isFile()) {
|
|
const ext = path.extname(absPath).toLowerCase()
|
|
res.setHeader('Content-Type', MIME[ext] ?? 'application/octet-stream')
|
|
res.end(fs.readFileSync(absPath))
|
|
return
|
|
}
|
|
} catch {
|
|
// file not found — fall through to index.html
|
|
}
|
|
|
|
// SPA fallback: serve index.html for any unmatched /gcode-viewer/* path
|
|
const index = path.join(gcodeViewerDir, 'index.html')
|
|
if (fs.existsSync(index)) {
|
|
res.setHeader('Content-Type', 'text/html; charset=utf-8')
|
|
res.end(fs.readFileSync(index))
|
|
return
|
|
}
|
|
|
|
next()
|
|
})
|
|
},
|
|
}
|
|
}
|
|
|
|
export default defineConfig({
|
|
plugins: [react(), serveGcodeViewer()],
|
|
build: {
|
|
outDir: '../static',
|
|
emptyOutDir: true,
|
|
chunkSizeWarningLimit: 3000,
|
|
},
|
|
server: {
|
|
host: '0.0.0.0',
|
|
proxy: {
|
|
'/api/v1/ws': {
|
|
target: backendUrl,
|
|
ws: true,
|
|
changeOrigin: true,
|
|
},
|
|
'/api': {
|
|
target: backendUrl,
|
|
changeOrigin: true,
|
|
},
|
|
},
|
|
},
|
|
resolve: {
|
|
alias: {
|
|
'@': path.resolve(__dirname, './src'),
|
|
},
|
|
},
|
|
})
|