build(frontend): Phase 2 — scaffold Vite + Vue 3 + AD-Vue 4

Adds a frontend/ directory that lives alongside the legacy web/html/
Vue 2 templates during the migration. Vite builds into ../web/dist/
so the Go binary will be able to embed the result via embed.FS once
Phase 4 starts moving real pages over.

- package.json pins Vue 3.5, Ant Design Vue 4.2, Vite 6, vue-i18n 10
- vite.config.js: dev server on :5173 with API proxy to the Go panel
  on :2053; build output to ../web/dist/
- src/App.vue is currently a smoke-test placeholder — delete once the
  first real page (login) lands in Phase 4
- node_modules and dist are already ignored at repo root

To verify locally:
  cd frontend && npm install && npm run dev

Pages will be migrated one at a time on the vue3-migration branch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
MHSanaei 2026-05-08 10:36:03 +02:00
parent f874060a4d
commit 179c025250
No known key found for this signature in database
GPG key ID: 7E4060F2FBE5AB7A
7 changed files with 183 additions and 0 deletions

3
frontend/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
node_modules/
.vite/
*.log

43
frontend/README.md Normal file
View file

@ -0,0 +1,43 @@
# 3x-ui frontend
Vue 3 + Ant Design Vue 4 + Vite. Builds into `../web/dist/`, which the
Go binary will embed via `embed.FS` once the migration reaches the page
handlers (Phase 4+).
This directory exists alongside the legacy `web/html/` Vue 2 templates
during the migration. Pages will move over one at a time on the
`vue3-migration` branch.
## Dev
```sh
cd frontend
npm install
npm run dev
```
The dev server runs on `http://localhost:5173/` and proxies API calls to
the Go panel at `http://localhost:2053/` — start the Go panel first
(`go run main.go`), then start Vite.
## Production build
```sh
npm run build
```
Outputs to `../web/dist/`. The Go binary picks it up at compile time via
`embed.FS`.
## Where things live
- `src/main.js` — app entrypoint (createApp, install Antd, mount)
- `src/App.vue` — root component (currently a smoke-test placeholder)
- `vite.config.js` — build + dev-server config
- `index.html` — Vite HTML template
## Adding new pages
For each legacy page being migrated, add an entry to
`vite.config.js` `rollupOptions.input`. Each entry produces its own
HTML file in `web/dist/`, which the Go panel route handler will serve.

12
frontend/index.html Normal file
View file

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>3x-ui</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

28
frontend/package.json Normal file
View file

@ -0,0 +1,28 @@
{
"name": "x-ui-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"description": "3x-ui panel frontend (Vue 3 + Ant Design Vue 4). Built with Vite into ../web/dist/ and embedded by the Go binary.",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint src --ext .js,.vue"
},
"dependencies": {
"ant-design-vue": "^4.2.6",
"@ant-design/icons-vue": "^7.0.1",
"axios": "^1.7.9",
"moment": "^2.30.1",
"qrious": "^4.0.2",
"vue": "^3.5.13",
"vue-i18n": "^10.0.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"eslint": "^9.17.0",
"eslint-plugin-vue": "^9.32.0",
"vite": "^6.0.7"
}
}

48
frontend/src/App.vue Normal file
View file

@ -0,0 +1,48 @@
<script setup>
import { ref } from 'vue';
const message = ref('Vue 3 + Ant Design Vue 4 scaffold is alive');
const count = ref(0);
</script>
<template>
<a-layout class="layout">
<a-layout-header class="header">
<h1>3x-ui (vue3-migration scaffold)</h1>
</a-layout-header>
<a-layout-content class="content">
<a-space direction="vertical" :size="16" style="width: 100%">
<a-alert :message="message" type="success" show-icon />
<a-card title="Smoke test">
<p>If you see this card with a styled button below, the toolchain works.</p>
<a-space>
<a-button type="primary" @click="count++">Clicked {{ count }} times</a-button>
<a-button @click="count = 0">Reset</a-button>
</a-space>
</a-card>
</a-space>
</a-layout-content>
</a-layout>
</template>
<style>
.layout {
min-height: 100vh;
}
.header {
background: #001529;
color: #fff;
display: flex;
align-items: center;
padding: 0 24px;
}
.header h1 {
color: #fff;
margin: 0;
font-size: 18px;
}
.content {
padding: 24px;
background: #f0f2f5;
}
</style>

9
frontend/src/main.js Normal file
View file

@ -0,0 +1,9 @@
import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/reset.css';
import App from './App.vue';
const app = createApp(App);
app.use(Antd);
app.mount('#app');

40
frontend/vite.config.js Normal file
View file

@ -0,0 +1,40 @@
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');
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'),
},
},
},
server: {
port: 5173,
strictPort: true,
proxy: {
// Proxy API calls during `npm run dev` to the local Go panel.
'/panel': 'http://localhost:2053',
'/server': 'http://localhost:2053',
'/login': 'http://localhost:2053',
'/logout': 'http://localhost:2053',
},
},
});