mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 17:46:02 +00:00
- Index dashboard regains the 8 cards that were lost in the SPA port (3X-UI panel info, Operation Hours, System Load, Usage, Overall Speed, Total Data, IP Addresses, Connection Stats), plus a Config button that shows the live xray config.json. Version display falls back through panelUpdateInfo → window.__X_UI_CUR_VER__ → '?' so dev mode isn't blank. - Xray config no longer hangs on load: useXraySetting surfaces failures instead of leaving a perpetual spinner, and the Vite dev proxy stops hijacking POST requests to migrated routes (only GETs get bypassed). - Inbound page no longer throws __asyncLoader/emitsOptions errors — inbound.js was missing imports (NumberFormatter, SizeFormatter, Wireguard) and InboundList kept emitting after unmount. - Login round-trip works after logout: a public /csrf-token endpoint bootstraps the SPA before authentication, axios caches the token module-level, and the dev 401 handler navigates to /login.html instead of reloading the dashboard into a redirect loop. - legacy.css mirrors the legacy panel's surface/text variables so dark and ultra-dark themes match main; every SPA entry imports it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
97 lines
3.3 KiB
JavaScript
97 lines
3.3 KiB
JavaScript
import { defineConfig } from 'vite';
|
|
import vue from '@vitejs/plugin-vue';
|
|
import path from 'node:path';
|
|
|
|
// Output goes to web/dist/ at the repo root so the Go binary can embed it
|
|
// via embed.FS without reaching outside the web/ tree.
|
|
const outDir = path.resolve(__dirname, '../web/dist');
|
|
|
|
// In production the Go binary serves /panel/<route> from web/dist/<route>.html.
|
|
// In dev the Vue app lives at /index.html, /settings.html, ... while AppSidebar
|
|
// links use the production-style /panel/<route> URLs. Map each migrated route
|
|
// to its Vite entry so the sidebar works without relying on the Go backend
|
|
// for already-ported pages. Unmigrated routes (inbounds, xray) fall through
|
|
// to the proxy.
|
|
const MIGRATED_ROUTES = {
|
|
'/panel': '/index.html',
|
|
'/panel/': '/index.html',
|
|
'/panel/settings': '/settings.html',
|
|
'/panel/settings/': '/settings.html',
|
|
'/panel/inbounds': '/inbounds.html',
|
|
'/panel/inbounds/': '/inbounds.html',
|
|
'/panel/xray': '/xray.html',
|
|
'/panel/xray/': '/xray.html',
|
|
};
|
|
|
|
// Build a proxy config that suppresses ECONNREFUSED noise when the Go
|
|
// backend isn't running locally. Real errors (timeouts, 5xx, etc.) still
|
|
// surface in the Vite log.
|
|
function makeBackendProxy(target, patterns) {
|
|
const config = {};
|
|
for (const pattern of patterns) {
|
|
config[pattern] = {
|
|
target,
|
|
changeOrigin: true,
|
|
// Returning a path from bypass tells Vite to serve that file from
|
|
// its own dev server instead of forwarding the request — used here
|
|
// to short-circuit /panel/<route> for pages we've already migrated.
|
|
//
|
|
// Only GETs get bypassed: the xray page reuses its page URL
|
|
// (`POST /panel/xray/`) for data, so a method-blind bypass would
|
|
// hand HTML back to fetch calls and break the page in dev.
|
|
bypass(req) {
|
|
if (req.method !== 'GET') return undefined;
|
|
const url = req.url.split('?')[0];
|
|
if (Object.prototype.hasOwnProperty.call(MIGRATED_ROUTES, url)) {
|
|
return MIGRATED_ROUTES[url];
|
|
}
|
|
return undefined;
|
|
},
|
|
configure(proxy) {
|
|
proxy.on('error', (err) => {
|
|
if (err.code === 'ECONNREFUSED') return;
|
|
// eslint-disable-next-line no-console
|
|
console.error('[proxy]', err);
|
|
});
|
|
},
|
|
};
|
|
}
|
|
return config;
|
|
}
|
|
|
|
export default defineConfig({
|
|
plugins: [vue()],
|
|
resolve: {
|
|
alias: {
|
|
'@': path.resolve(__dirname, 'src'),
|
|
},
|
|
},
|
|
build: {
|
|
outDir,
|
|
emptyOutDir: true,
|
|
sourcemap: true,
|
|
target: 'es2020',
|
|
// Multiple HTML entries — one per legacy page we migrate.
|
|
// As pages get ported in later phases, add their entrypoints here.
|
|
rollupOptions: {
|
|
input: {
|
|
index: path.resolve(__dirname, 'index.html'),
|
|
login: path.resolve(__dirname, 'login.html'),
|
|
settings: path.resolve(__dirname, 'settings.html'),
|
|
inbounds: path.resolve(__dirname, 'inbounds.html'),
|
|
xray: path.resolve(__dirname, 'xray.html'),
|
|
},
|
|
},
|
|
},
|
|
server: {
|
|
port: 5173,
|
|
strictPort: true,
|
|
proxy: makeBackendProxy('http://localhost:2053', [
|
|
// Patterns are anchored regex so /login.html and /index.html
|
|
// (which Vite serves itself) are NOT forwarded — only the bare
|
|
// backend paths and their sub-routes.
|
|
'^/(login|logout|getTwoFactorEnable|csrf-token)$',
|
|
'^/(panel|server)(/|$)',
|
|
]),
|
|
},
|
|
});
|