diff --git a/hub/.gitignore b/hub/.gitignore index 9830097..b5e8e21 100644 --- a/hub/.gitignore +++ b/hub/.gitignore @@ -12,3 +12,6 @@ dist/ admin-web/node_modules/ admin-web/build/ admin-web/.svelte-kit/ +filelib-web/node_modules/ +filelib-web/build/ +filelib-web/.svelte-kit/ diff --git a/hub/filelib-web/index.html b/hub/filelib-web/index.html deleted file mode 100644 index e395a5c..0000000 --- a/hub/filelib-web/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - 文件库 - - -
- - - diff --git a/hub/filelib-web/package-lock.json b/hub/filelib-web/package-lock.json index 8a6f9c7..f306d41 100644 --- a/hub/filelib-web/package-lock.json +++ b/hub/filelib-web/package-lock.json @@ -8,6 +8,8 @@ "name": "filelib-web", "version": "0.1.0", "devDependencies": { + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.63.0", "@sveltejs/vite-plugin-svelte": "^7.1.2", "@tailwindcss/vite": "^4.3.2", "svelte": "^5.56.1", @@ -130,6 +132,13 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", @@ -412,6 +421,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.11.tgz", @@ -422,6 +438,58 @@ "acorn": "^8.9.0" } }, + "node_modules/@sveltejs/adapter-static": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-static/-/adapter-static-3.0.10.tgz", + "integrity": "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.70.1", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.70.1.tgz", + "integrity": "sha512-nY9SPHGOZro3doud9vZXDBwl9tCZIouuJztjgSHs6PAIrv9M/z5O7eOhPV5xU7CgVHA976Jwu3BA1hIFvXztkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@sveltejs/acorn-typescript": "^1.0.9", + "@types/cookie": "^0.6.0", + "acorn": "^8.16.0", + "cookie": "^0.6.0", + "devalue": "^5.8.1", + "esm-env": "^1.2.2", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "set-cookie-parser": "^3.0.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": "^5.3.3 || ^6.0.0", + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/@sveltejs/load-config": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@sveltejs/load-config/-/load-config-0.2.0.tgz", @@ -747,6 +815,13 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -820,6 +895,16 @@ "node": ">=6" } }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -946,6 +1031,16 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -1246,6 +1341,16 @@ "node": ">=4" } }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/nanoid": { "version": "3.3.16", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", @@ -1389,6 +1494,28 @@ "node": ">=6" } }, + "node_modules/set-cookie-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.2.tgz", + "integrity": "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1490,6 +1617,16 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", diff --git a/hub/filelib-web/package.json b/hub/filelib-web/package.json index 43c706a..08320e6 100644 --- a/hub/filelib-web/package.json +++ b/hub/filelib-web/package.json @@ -4,12 +4,15 @@ "version": "0.1.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite dev", "build": "vite build", "preview": "vite preview", - "check": "svelte-check --tsconfig ./tsconfig.json" + "prepare": "svelte-kit sync || echo ''", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "devDependencies": { + "@sveltejs/adapter-static": "^3.0.10", + "@sveltejs/kit": "^2.63.0", "@sveltejs/vite-plugin-svelte": "^7.1.2", "@tailwindcss/vite": "^4.3.2", "svelte": "^5.56.1", diff --git a/hub/filelib-web/src/App.svelte b/hub/filelib-web/src/App.svelte deleted file mode 100644 index cc69f92..0000000 --- a/hub/filelib-web/src/App.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - -{#if !$authChecked} -
加载中…
-{:else if $me} - -{:else} - -{/if} - - diff --git a/hub/filelib-web/src/app.d.ts b/hub/filelib-web/src/app.d.ts new file mode 100644 index 0000000..e1551fc --- /dev/null +++ b/hub/filelib-web/src/app.d.ts @@ -0,0 +1,12 @@ +// See https://svelte.dev/docs/kit/types#app +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/hub/filelib-web/src/app.html b/hub/filelib-web/src/app.html new file mode 100644 index 0000000..1e7531f --- /dev/null +++ b/hub/filelib-web/src/app.html @@ -0,0 +1,16 @@ + + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/hub/filelib-web/src/main.ts b/hub/filelib-web/src/main.ts deleted file mode 100644 index 727d356..0000000 --- a/hub/filelib-web/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { mount } from "svelte"; -import App from "./App.svelte"; -import "./app.css"; - -export default mount(App, { target: document.getElementById("app")! }); diff --git a/hub/filelib-web/svelte.config.js b/hub/filelib-web/svelte.config.js new file mode 100644 index 0000000..87af393 --- /dev/null +++ b/hub/filelib-web/svelte.config.js @@ -0,0 +1,35 @@ +import adapter from '@sveltejs/adapter-static'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** + * 老师端 /app 与管理后台 /database/* 共用这一份 SPA 构建产物,由 hub 后端静态托管 + * (见 hub/src/database/static.ts)。服务端不渲染任何页面,只提供 /database/api/*。 + * + * 两个关键配置: + * + * - `appDir: '_filelib'` —— 默认 `_app` 会与 admin-web 在同一个 Fastify 实例上注册的 + * 根 `/_app/*` 资源路由撞车(见 hub/src/admin/static.ts),Fastify 重复路由会直接 + * 在启动时抛错。改名后两套 SPA 的资源路径互不干扰。 + * + * - `paths.relative: false` —— 同一份 index.html 会在不同深度的 URL 下被送出 + * (`/app`、`/database/dashboard/users`),相对资源路径会解析错。必须用绝对路径。 + */ +const config = { + preprocess: vitePreprocess(), + kit: { + adapter: adapter({ + pages: 'build', + assets: 'build', + fallback: 'index.html', + precompress: false, + strict: false, + }), + appDir: '_filelib', + paths: { + base: '', + relative: false, + }, + }, +}; + +export default config; diff --git a/hub/filelib-web/tsconfig.json b/hub/filelib-web/tsconfig.json index 80e1189..0d61fe3 100644 --- a/hub/filelib-web/tsconfig.json +++ b/hub/filelib-web/tsconfig.json @@ -1,4 +1,5 @@ { + "extends": "./.svelte-kit/tsconfig.json", "compilerOptions": { "target": "ES2022", "module": "ESNext", @@ -12,6 +13,5 @@ "resolveJsonModule": true, "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"] - }, - "include": ["src/**/*.ts", "src/**/*.svelte"] + } } diff --git a/hub/filelib-web/vite.config.ts b/hub/filelib-web/vite.config.ts index 9e4b9c6..ef7e8d4 100644 --- a/hub/filelib-web/vite.config.ts +++ b/hub/filelib-web/vite.config.ts @@ -1,25 +1,27 @@ -import { defineConfig } from "vite"; -import { svelte } from "@sveltejs/vite-plugin-svelte"; +import { sveltekit } from "@sveltejs/kit/vite"; import tailwindcss from "@tailwindcss/vite"; +import { defineConfig } from "vite"; -// 老师端独立 SPA:构建产物由 hub 后端静态托管于 /app; -// 开发时 vite dev(:5173)把 API/认证请求代理到后端(:8788)。 +// 老师端 /app + 管理后台 /database/* 的唯一前端工程;构建产物由 hub 后端静态托管。 +// 开发时 vite dev(:5173)把 API/认证/一键登录请求代理到后端(:8788); +// 页面路由全部由 SvelteKit 客户端路由处理,后端不参与。 const backend = "http://127.0.0.1:8788"; export default defineConfig({ - plugins: [svelte(), tailwindcss()], - base: "/app/", - build: { - outDir: "dist", - emptyOutDir: true, - }, + plugins: [tailwindcss(), sveltekit()], server: { port: 5173, proxy: { "/database/api": backend, + // 免鉴权 bootstrap(org slug + dev 开关);登录页和用户管理页都靠它。 + "/database/config": backend, "/auth": backend, + // 后端拥有的 DEV 一键登录端点(签 cookie 后 302);不代理会被 SPA 回退吃掉。 + "/database/dev-login": backend, "/app/dev-login": backend, "/app/dev-login-teacher": backend, + // 平台层 org 成员 API(用户管理面板)。 + "/api/org": backend, }, }, });