wildpig 1.1.6 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/render.tsx CHANGED
@@ -1,13 +1,29 @@
1
- import ReactDOM from 'react-dom/client';
2
- import { App } from '@/App';
1
+ import { createRoot, hydrateRoot } from 'react-dom/client';
2
+ import { RouterProvider } from 'react-router';
3
3
  import "./tailwindcss4.js";
4
+ import { serverDataStore } from '../store/serverDataStore';
5
+ import { browserRouter } from '../router/index.js';
4
6
 
7
+ const isDev = process.env.NODE_ENV === 'development';
5
8
 
6
- document.addEventListener("DOMContentLoaded", () => {
9
+
10
+ // 确保在 DOM 加载完成后才进行水合
11
+ document?.addEventListener("DOMContentLoaded", () => {
7
12
  // 获取根元素
8
13
  const rootElement = document.getElementById('root')!;
9
14
 
10
- // 创建根并渲染组件
11
- const root = ReactDOM.createRoot(rootElement);
12
- root.render(<App />);
15
+ // 从 window 对象获取服务端数据
16
+ const serverData = (window as any).__SERVER_DATA__;
17
+
18
+ // 设置服务端数据到 store
19
+ serverDataStore.set(serverData);
20
+
21
+ if(isDev){
22
+ // 开发时,使用 createRoot 进行渲染
23
+ const root = createRoot(rootElement);
24
+ root.render(<RouterProvider router={browserRouter} />);
25
+ }else{
26
+ // 生产环境,使用 hydrateRoot 进行水合
27
+ hydrateRoot(rootElement, (<RouterProvider router={browserRouter} />));
28
+ }
13
29
  });
@@ -0,0 +1,38 @@
1
+ import { useEffect } from "react"
2
+ import { matchRoutes, Outlet, useLocation, useNavigate } from "react-router"
3
+ import pageRoutes from "@/router/routes";
4
+ import { serverDataStore } from "#/store/serverDataStore";
5
+
6
+ export const ServerDataGuard = () => {
7
+ const location = useLocation();
8
+ const navigate = useNavigate();
9
+ useEffect(() => {
10
+ // serverData清空
11
+ serverDataStore.set(undefined);
12
+
13
+ const url = location.pathname;
14
+ const matches = matchRoutes(pageRoutes, url);
15
+ const lastMatch = matches?.at(-1);
16
+ if(!lastMatch) {
17
+ // 404
18
+ navigate("/404");
19
+ return;
20
+ }
21
+ // 成功匹配
22
+ let serverDataApi = lastMatch.route.serverDataApi;
23
+ if(!serverDataApi)return;
24
+
25
+ // 替换参数
26
+ for(const [key, value] of Object.entries(lastMatch.params)){
27
+ if(value)serverDataApi = serverDataApi.replace(":" + key, value);
28
+ }
29
+ fetch(serverDataApi).then(res => res.json()).then(data => {
30
+ serverDataStore.set(data);
31
+ if(data.title){
32
+ document.title = data.title;
33
+ }
34
+ });
35
+ }, [location]);
36
+
37
+ return <Outlet />;
38
+ }
@@ -0,0 +1,15 @@
1
+ import { createBrowserRouter } from "react-router";
2
+ import { ServerDataGuard } from "./ServerDataGuard";
3
+
4
+ // 用户代码
5
+ import pageRoutes from "@/router/routes";
6
+
7
+
8
+ /** 生成路由器,可用于监听路由变化 */
9
+ export const browserRouter = createBrowserRouter([
10
+ {
11
+ path: "/",
12
+ Component: ServerDataGuard,
13
+ children: pageRoutes,
14
+ },
15
+ ]);
@@ -0,0 +1,7 @@
1
+ import { RouteObject } from "react-router";
2
+
3
+ export type WildPigRouteObject = RouteObject & {
4
+ // 是否需要登录
5
+ serverDataApi?: string;
6
+ children?: WildPigRouteObject[];
7
+ }
@@ -0,0 +1,104 @@
1
+ import chalk from "chalk";
2
+ // import { routes, metaRoutes } from "./prepareRoutes";
3
+ import { readFileSync } from "node:fs";
4
+ import { getApiRouteModules } from "./apiRoutes";
5
+ import { renderToReadableStream } from "react-dom/server";
6
+ import devHtml from "../public/devHtml.html"
7
+
8
+ import { createStaticHandler, createStaticRouter, matchRoutes } from "react-router";
9
+
10
+
11
+ const __dirname = import.meta.dirname;
12
+
13
+
14
+ // 用户代码
15
+ import pageRoutes from "#/src/router/routes";
16
+ import { App } from "@/App"
17
+ import path from "node:path";
18
+
19
+ const env = process.env;
20
+ const port = env.PORT || 3000;
21
+ const hostname = env.HOSTNAME || "localhost";
22
+ const isDev = env.NODE_ENV === "development";
23
+
24
+ const apiModules = await getApiRouteModules(isDev ? "dev" : "prod") as any;
25
+
26
+
27
+ if(isDev){
28
+ setTimeout(() => {import("../public/render")}, 0);
29
+ /** 打包js */
30
+ await Bun.build({
31
+ entrypoints: [path.resolve(__dirname, "../public/render.tsx")],
32
+ outdir: path.resolve(__dirname, "../public"),
33
+ format: "esm",
34
+ minify: false,
35
+ });
36
+ }
37
+
38
+ export const startServer = async () => {
39
+ Bun.serve({
40
+ port,
41
+ hostname,
42
+ routes:{
43
+ ...apiModules,
44
+ // 这个来自用户文件
45
+ "/favicon.ico": () => new Response(Bun.file("./public/favicon.ico"), {
46
+ headers: {
47
+ "content-type": "image/x-icon",
48
+ }
49
+ }),
50
+ "/render.js": () => new Response((readFileSync(path.resolve(__dirname, "../public/render.js"))), {
51
+ headers: {
52
+ "Content-Type": "text/javascript; charset=utf-8",
53
+ "Cache-Control": isDev ? "no-cache" : "public, max-age=31536000, immutable"
54
+ }
55
+ }),
56
+ "/*": isDev ? devHtml : async (request: Request) => {
57
+ // 判断pathname是否匹配pageRoutes
58
+ const url = new URL(request.url);
59
+ const matches = matchRoutes(pageRoutes, url.pathname);
60
+ if(!matches){
61
+ return new Response("404 Not Found", {
62
+ status: 404,
63
+ headers: {
64
+ "content-type": "text/plain; charset=utf-8",
65
+ "Access-Control-Allow-Origin": "*",
66
+ }
67
+ })
68
+ }
69
+
70
+ let { query, dataRoutes } = createStaticHandler(pageRoutes);
71
+ let context = await query(request);
72
+ if (context instanceof Response) return context;
73
+ let router = createStaticRouter(dataRoutes, context);
74
+
75
+ // 请求服务端数据
76
+ const matchRoute = matches.at(-1)!;
77
+ let serverDataApi = matchRoute.route.serverDataApi;
78
+ const getServerData = async () => {
79
+ if(!serverDataApi)return undefined;
80
+ // 需要请求服务端数据, 替换动态参数
81
+ for(const [key, value] of Object.entries(matchRoute.params)){
82
+ if(value)serverDataApi = serverDataApi.replace(":" + key, value);
83
+ }
84
+ const pathname = serverDataApi.split("?")[0]; // 获取路径
85
+ const handleUrl = "http://" + hostname + ":" + port + pathname;
86
+ const serverData = await fetch(handleUrl).then(r => r.json());
87
+ return serverData;
88
+ };
89
+ let serverData = await getServerData();
90
+
91
+
92
+ const stream = await renderToReadableStream(<App router={router} serverData={serverData} />);
93
+ return new Response(stream, {
94
+ headers: {
95
+ "content-type": "text/html; charset=utf-8",
96
+ "Access-Control-Allow-Origin": "*",
97
+ }
98
+ })
99
+ },
100
+ },
101
+ development: isDev,
102
+
103
+ })
104
+ }
@@ -0,0 +1,98 @@
1
+ import { readdirSync, statSync, writeFileSync } from "fs";
2
+ import { middleware } from "@/api/middleware";
3
+
4
+ const getFilePaths = (dir: string) => {
5
+ const res: string[] = [];
6
+ const files = readdirSync(dir);
7
+ files.forEach(file => {
8
+ const filePath = `${dir}/${file}`;
9
+ const stat = statSync(filePath);
10
+ if (stat.isDirectory()) {
11
+ res.push(...getFilePaths(filePath));
12
+ } else {
13
+ res.push(filePath);
14
+ }
15
+ });
16
+ return res;
17
+ }
18
+
19
+
20
+ const makeDynamicRoute = (route: string) => route.replaceAll(/\[([^\]]*)\]/g, ':$1');
21
+
22
+ export const makeApiRoutePathObj = () => {
23
+ // 扫描用户代码路径
24
+ const apiDir = "./src/api";
25
+ const apiPaths = getFilePaths(apiDir);
26
+ const result: Record<string, string> = {};
27
+
28
+ for(const apiPath of apiPaths) {
29
+ const importPath = apiPath.replace("./src/api", "#/src/api");
30
+ if(!apiPath.includes("index.ts")) continue;
31
+ const route = apiPath.replace("./src/api", "/api").replace("/index.ts", "");
32
+ result[route] = importPath.replace(".ts", "");
33
+ }
34
+ return result;
35
+ }
36
+
37
+ /**
38
+ * 生成api路由的配置文件
39
+ */
40
+ export const packageApiRoutes = async () => {
41
+ const apiRoutes = makeApiRoutePathObj();
42
+ let identId = 0;
43
+ let importsText = `import { middleware } from "@/api/middleware" \n`;
44
+ let routesText = "export default {\n";
45
+ for(const route of Object.keys(apiRoutes)) {
46
+ const importPath = apiRoutes[route];
47
+ // 尝试从文件中获取路由
48
+ const module = await import(importPath);
49
+ // 没有接口,就跳过
50
+ if(!module.GET && !module.POST) continue;
51
+ // 标识id
52
+ identId ++;
53
+ importsText += `import {\n`;
54
+ routesText += `\t"${makeDynamicRoute(route)}": {\n`;
55
+ if(module.GET) {
56
+ importsText += `\tGET as GET${identId},\n`;
57
+ routesText += `\t\tGET: (req: any) => middleware(req, GET${identId}),\n`;
58
+ }
59
+ if(module.POST) {
60
+ importsText += `\tPOST as POST${identId},\n`;
61
+ routesText += `\t\tPOST: (req: any) => middleware(req, POST${identId}),\n`;
62
+ }
63
+ importsText += `} from "${importPath}";\n`;
64
+ routesText += `\t},\n`;
65
+ }
66
+ routesText += "}";
67
+ writeFileSync("./build/built-api-routes.ts", importsText + "\n" + routesText);
68
+ };
69
+
70
+ /**
71
+ * 获取api路由,dev模式,直接导入
72
+ */
73
+ export const getApiRouteModules = async (mode: "dev" | "prod") => {
74
+ if(mode === "dev"){
75
+ const apiRoutes = makeApiRoutePathObj();
76
+ const result: Record<string, {
77
+ GET?: (req: any) => Promise<Response>,
78
+ POST?: (req: any) => Promise<Response>
79
+ } > = {};
80
+ for(const route of Object.keys(apiRoutes)) {
81
+ const importPath = apiRoutes[route];
82
+ const module = await import(importPath.replace(".ts", ""));
83
+ if(!module.GET && !module.POST) continue;
84
+
85
+ // 新建一个路由
86
+ const dynamicRoute = makeDynamicRoute(route);
87
+ console.log(`[apiRoutes] ${dynamicRoute}`)
88
+ result[dynamicRoute] = {};
89
+ if(module.GET) result[dynamicRoute].GET = (req: any) => middleware(req, module.GET);
90
+ if(module.POST) result[dynamicRoute].POST = (req: any) => middleware(req, module.POST);
91
+ }
92
+ return result;
93
+ } else {
94
+ // prod模式,直接从文件中导入
95
+ const module = await import("../build/built-api-routes"!);
96
+ return module.default;
97
+ }
98
+ }
@@ -0,0 +1,23 @@
1
+ import path from "node:path";
2
+ import { packageApiRoutes } from "./apiRoutes";
3
+ import { packageStatic } from "./packageStatic";
4
+
5
+ const prebuild = async () => {
6
+ await packageStatic();
7
+ await packageApiRoutes();
8
+ };
9
+
10
+
11
+ export const build = async () => {
12
+ // 前处理
13
+ await prebuild();
14
+ // 正式编译
15
+ await Bun.build({
16
+ entrypoints: [path.resolve(__dirname, "./server.ts")],
17
+ compile: true,
18
+ outdir: "./dist",
19
+ define: {
20
+ "process.env.NODE_ENV": JSON.stringify("production"),
21
+ },
22
+ });
23
+ }
@@ -1,12 +1,14 @@
1
1
  import Bun from "bun";
2
2
  import fs from "node:fs";
3
+ import path from "node:path";
3
4
 
5
+ const __dirname = import.meta.dirname;
4
6
 
5
7
  export const packageStatic = async () => {
6
8
  /** 打包js */
7
9
  await Bun.build({
8
- entrypoints: ["./public/render.tsx"],
9
- outdir: "./dist/public",
10
+ entrypoints: [path.resolve(__dirname, "../public/render.tsx")],
11
+ outdir: path.resolve(__dirname, "../dist/public"),
10
12
  format: "esm",
11
13
  minify: true,
12
14
  });
@@ -0,0 +1,38 @@
1
+ import chalk from "chalk";
2
+ import path from "node:path";
3
+ import { startServer } from "./WildPig";
4
+ const env = process.env;
5
+
6
+
7
+ const port = env.PORT || 3000;
8
+ const hostname = env.HOSTNAME || "localhost";
9
+ const isDev = env.NODE_ENV === "development";
10
+
11
+ const getPackageInfo = async () => {
12
+ const packageJson = await Bun.file(path.resolve(__dirname, "../package.json")).json();
13
+ return packageJson;
14
+ }
15
+ const packageInfo = await getPackageInfo();
16
+
17
+
18
+ startServer();
19
+
20
+ const afterStart = () => {
21
+ // 启动后的文字
22
+ console.log(` __ __ _ _ _ ____ _
23
+ \\ \\ / /(_)| | __| | | _ \\ (_) __ _
24
+ \\ \\ /\\ / / | || | / _\` | | |_) || | / _\` |
25
+ \\ V V / | || || (_| | | __/ | || (_| |
26
+ \\_/\\_/ |_||_| \\__,_| |_| |_| \\__, |
27
+ |___/ `)
28
+ console.log(chalk.blue.bgGreen(` 🐗 WildPig version ${packageInfo?.version} by ${packageInfo?.author} `));
29
+ console.log(chalk.green(" Strong & Fast Fullstack Framework\n"));
30
+ console.log(chalk.green("✨ WildPig is running on port " + env.PORT || 3000));
31
+ if(isDev){
32
+ console.log(chalk.yellow("💻 Wildpig is Running in development mode."));
33
+ }else{
34
+ console.log(chalk.green("💻 Wildpig is Running in production mode."));
35
+ }
36
+ console.log(chalk.green(`🔗 Click to debug in Browser: http://${hostname}:${port}`));
37
+ }
38
+ afterStart();
@@ -0,0 +1,4 @@
1
+ import { atom } from "nanostores";
2
+
3
+
4
+ export const serverDataStore = atom<any>(undefined);
@@ -1,4 +0,0 @@
1
- export default {
2
- "/_WILDPIG_META_API/home": require("#/src/page/home/meta.ts").getMeta,
3
- "/_WILDPIG_META_API/": require("#/src/page/meta.ts").getMeta,
4
- }
@@ -1,9 +0,0 @@
1
- import { middleware } from "@/middleware";
2
-
3
- export default {
4
- "/api/hello": {GET: (req: any) => middleware(req, require("#/src/api/hello/index.ts").GET),
5
- POST: (req: any) => middleware(req, require("#/src/api/hello/index.ts").POST),
6
- PUT: (req: any) => middleware(req, require("#/src/api/hello/index.ts").PUT),
7
- DELETE: (req: any) => middleware(req, require("#/src/api/hello/index.ts").DELETE),
8
- },
9
- }
package/index.ts DELETED
@@ -1,3 +0,0 @@
1
- import { startServer } from "./scripts/WildPig";
2
-
3
- export { startServer };
@@ -1,13 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="wildpig-environment" content="development">
7
- <script src="./render.tsx" type="module"></script>
8
- <title>WildPig - 开发环境(生产环境下会被替换为meta信息)</title>
9
- </head>
10
- <body>
11
- <div id="root"></div>
12
- </body>
13
- </html>
package/public/index.html DELETED
@@ -1,17 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <meta name="wildpig-environment" content="production">
7
-
8
- <title>{{TITLE}}</title>
9
- <meta name="description" content="{{DESCRIPTION}}">
10
- <meta name="keywords" content="{{KEYWORDS}}">
11
-
12
- <script src="/render.js" type="module"></script>
13
- </head>
14
- <body>
15
- <div id="root"></div>
16
- </body>
17
- </html>
@@ -1,38 +0,0 @@
1
- import { getBrowserEnvironment } from "../utils/client/environment";
2
- import { createBrowserRouter } from "react-router";
3
- // 为了获取type而创建的router
4
- const browserRouterForType = createBrowserRouter([
5
- {
6
- path: "/just-for-type",
7
- Component: null,
8
- }
9
- ]);
10
- export type BrowserRouter = typeof browserRouterForType;
11
-
12
-
13
- /**
14
- * 获取meta信息
15
- * @param url like "/home?a=1"
16
- */
17
- const refreshMeta = (url: string) =>{
18
- console.log("get url:", url);
19
- fetch("/_WILDPIG_META_API" + url).then(res => res.json()).then(({title}) => {
20
- document.title = title;
21
- });
22
- }
23
-
24
- export const RouterMetaGuard = (browserRouter: BrowserRouter): BrowserRouter => {
25
-
26
- // 检查meta,判断是否是dev环境
27
- const isDev = getBrowserEnvironment() === "development";
28
- if(isDev){
29
- // 开发环境首次执行,生产阶段为了seo,无需首次执行
30
- refreshMeta(window.location.pathname + window.location.search);
31
- }
32
-
33
- // 每次跳转都会触发,包括 <Link>/navigate/前进后退
34
- browserRouter.subscribe(({ location }) => {
35
- refreshMeta(location.pathname + location.search);
36
- });
37
- return browserRouter;
38
- }
@@ -1,74 +0,0 @@
1
- import chalk from "chalk";
2
- import { htmlString } from "./htmlString";
3
- import { routes, metaRoutes } from "./prepareRoutes";
4
- import { readFileSync } from "node:fs";
5
- import devIndexHtml from "#/public/devIndex.html"
6
-
7
- const env = process.env;
8
- const isDev = env.NODE_ENV === "development";
9
-
10
- // console.log(metaRoutes);
11
-
12
- export const startServer = () => {
13
- Bun.serve({
14
- port: env.PORT || 3000,
15
- hostname: env.HOST || "0.0.0.0",
16
- routes:{
17
- ...routes,
18
- ...metaRoutes,
19
- "/favicon.ico": () => new Response(Bun.file("./public/favicon.ico"), {
20
- headers: {
21
- "content-type": "image/x-icon",
22
- }
23
- }),
24
- "/render.js": () => new Response((readFileSync("./public/render.js")), {
25
- headers: {
26
- "Content-Type": "text/javascript; charset=utf-8",
27
- "Cache-Control": isDev ? "no-cache" : "public, max-age=31536000, immutable"
28
- }
29
- }),
30
- "/*":
31
- isDev ? devIndexHtml :
32
- async (request: Request) => {
33
- const pathname = "/_WILDPIG_META_API/" + (request.url.split("/")[3].split("?")[0] || "");
34
- let resHtml = htmlString;
35
-
36
- if(pathname in metaRoutes){
37
- try{
38
- const metaResponse = await metaRoutes[pathname](request);
39
- const meta = await metaResponse.json();
40
- if(meta.title)resHtml = resHtml.replace("{{TITLE}}", meta.title);
41
- if(meta.description)resHtml = resHtml.replace("{{DESCRIPTION}}", meta.description);
42
- if(meta.keywords)resHtml = resHtml.replace("{{KEYWORDS}}", meta.keywords.join(", "));
43
- }catch(e){
44
- console.error("获取meta信息失败,请检查是否设置了meta信息", e);
45
- }
46
- }
47
-
48
- return new Response(resHtml, {
49
- headers: {
50
- "content-type": "text/html; charset=utf-8",
51
- "Access-Control-Allow-Origin": "*",
52
- }
53
- })
54
- },
55
- },
56
- development: isDev
57
- })
58
- console.clear();
59
- console.log(` __ __ _ _ _ ____ _
60
- \\ \\ / /(_)| | __| | | _ \\ (_) __ _
61
- \\ \\ /\\ / / | || | / _\` | | |_) || | / _\` |
62
- \\ V V / | || || (_| | | __/ | || (_| |
63
- \\_/\\_/ |_||_| \\__,_| |_| |_| \\__, |
64
- |___/ `)
65
- console.log(chalk.blue.bgGreen(" 🐗 WildPig version 1.1.6 by eriktse "));
66
- console.log(chalk.green(" Strong & Fast Fullstack Framework\n"));
67
- console.log(chalk.green("✨ WildPig is running on port " + env.PORT || 3000));
68
- if(isDev){
69
- console.log(chalk.yellow("💻 Wildpig is Running in development mode."));
70
- }else{
71
- console.log(chalk.green("💻 Wildpig is Running in production mode."));
72
- }
73
- console.log(chalk.green("🔗 Click to debug in Browser: http://localhost" + ":" + (env.PORT || 3000)));
74
- }
@@ -1,99 +0,0 @@
1
- // scripts/scan-routes.js
2
- import { middleware } from '@/middleware';
3
- import { statSync, readdirSync, writeFileSync } from 'fs';
4
-
5
- /** 获取文件的相对路径 */
6
- const getFilePaths = (dir: string) => {
7
- const res: string[] = [];
8
- const files = readdirSync(dir);
9
- files.forEach(file => {
10
- const filePath = `${dir}/${file}`;
11
- const stat = statSync(filePath);
12
- if (stat.isDirectory()) {
13
- res.push(...getFilePaths(filePath));
14
- } else {
15
- res.push(filePath);
16
- }
17
- });
18
- return res;
19
- }
20
-
21
- export const scanRoutes = () => {
22
- // 扫描src文件夹
23
- const files = getFilePaths("./src/api");
24
- const routes: {[key: string]: {
25
- GET?: (req: any) => any;
26
- POST?: (req: any) => any;
27
- PUT?: (req: any) => any;
28
- DELETE?: (req: any) => any;
29
- }} = {};
30
-
31
-
32
- const routeScripts: {[key: string]: string} = {}; // 存储路由对应的脚本文件路径
33
- for(const file of files) {
34
- const filepath = file.replace("./", "#/");
35
- if(!filepath.includes("index.ts")) continue;
36
-
37
- // 尝试从文件中获取GET函数
38
- const handler = require(filepath);
39
- if(handler) {
40
- const route = filepath.replace("#/src/api", "/api").replace("/index.ts", "");
41
- routes[route] = {
42
- GET: (req: any) => middleware(req, handler.GET),
43
- POST: (req: any) => middleware(req, handler.POST),
44
- PUT: (req: any) => middleware(req, handler.PUT),
45
- DELETE: (req: any) => middleware(req, handler.DELETE),
46
- };
47
- routeScripts[route] = filepath;
48
- }
49
- }
50
- return {routes, routeScripts};
51
- }
52
-
53
- export const genRoutes = async () => {
54
- const {routeScripts} = scanRoutes();
55
- let text = "import { middleware } from \"@/middleware\";\n\nexport default {\n";
56
- for(const route in routeScripts) {
57
- text += `"${route}": {`;
58
- text += `GET: (req: any) => middleware(req, require("${routeScripts[route]}").GET), \n`;
59
- text += `POST: (req: any) => middleware(req, require("${routeScripts[route]}").POST), \n`;
60
- text += `PUT: (req: any) => middleware(req, require("${routeScripts[route]}").PUT), \n`;
61
- text += `DELETE: (req: any) => middleware(req, require("${routeScripts[route]}").DELETE), \n`;
62
- text += `},\n`;
63
- }
64
- text += "}";
65
- writeFileSync("./build/built-routes.ts", text);
66
- }
67
-
68
-
69
-
70
- export const scanMetaRoutes = () => {
71
- // 扫描src文件夹
72
- const files = getFilePaths("./src/page");
73
- const routes: {[key: string]: () => Promise<Response>} = {};
74
- const routeScripts: {[key: string]: string} = {}; // 存储路由对应的脚本文件路径
75
- for(const file of files) {
76
- const filepath = file.replace("./", "#/");
77
- if(!filepath.includes("meta.ts")) continue;
78
-
79
- // 尝试从文件中获取GET函数
80
- const { getMeta } = require(filepath);
81
- if( getMeta ) {
82
- let route = filepath.replace("#/src/page", "").replace("/meta.ts", "");
83
- route = "/_WILDPIG_META_API" + (route || "/");
84
- routes[route] = getMeta;
85
- routeScripts[route] = filepath;
86
- }
87
- }
88
- return {routes, routeScripts};
89
- }
90
-
91
- export const genMetaRoutes = async () => {
92
- const {routeScripts} = scanMetaRoutes();
93
- let text = "export default {\n";
94
- for(const route in routeScripts) {
95
- text += ` "${route}": require("${routeScripts[route]}").getMeta, \n`;
96
- }
97
- text += "}";
98
- writeFileSync("./build/built-meta-routes.ts", text);
99
- }
@@ -1,2 +0,0 @@
1
- import IndexHtml from "#/public/index.html" with { type: "text" };
2
- export const htmlString = (IndexHtml as unknown as string);
@@ -1,8 +0,0 @@
1
- import { genMetaRoutes, genRoutes } from "./genRoutes";
2
- import { packageStatic } from "./packageStatic";
3
-
4
- export const prebuild = async () => {
5
- await packageStatic();
6
- await genRoutes();
7
- await genMetaRoutes();
8
- }