From a1b5502891145983f70c1555218bc36cb7023d9d Mon Sep 17 00:00:00 2001 From: zixu Date: Mon, 19 Aug 2024 18:10:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BD=BF=E7=94=A8=20tjs=20?= =?UTF-8?q?=E8=BF=90=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + Dockerfile | 29 +++++-- backend/app.ts | 164 ++++++++++++++++++++--------------- backend/font_util/font.ts | 5 +- backend/interface.ts | 37 ++++++++ backend/server/mime_type.ts | 26 +++--- backend/server/req_res.ts | 18 +--- backend/server/server.ts | 163 +++++++++++++++++++++++++++++++--- backend/server/tcp_server.ts | 2 +- backend/server/tjs.ts | 14 +++ backend/test.js | 20 +++++ package.json | 3 +- pnpm-lock.yaml | 8 ++ src/App.tsx | 3 +- tsconfig.app.json | 15 ++-- tsconfig.json | 15 +++- tsconfig.node.json | 13 +-- tsup.config.ts | 3 +- 18 files changed, 404 insertions(+), 136 deletions(-) create mode 100644 backend/interface.ts create mode 100644 backend/server/tjs.ts create mode 100644 backend/test.js diff --git a/.gitignore b/.gitignore index 9c05657..0b113ff 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ dist-ssr llrt* font/* +tjs +app *.tar dist_backend \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 971c0bb..0c8acf3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,25 @@ -FROM scratch -WORKDIR /home/ -COPY dist_backend/app.lrt /home/app.lrt -COPY llrt2 /home/llrt -COPY dist/ /home/dist/ -EXPOSE 80 -CMD ["/home/llrt", "/home/app.lrt"] +# FROM scratch +# WORKDIR /home/ +# COPY dist_backend/app.lrt /home/app.lrt +# COPY llrt2 /home/llrt +# COPY dist/ /home/dist/ +# EXPOSE 80 +# CMD ["/home/llrt", "/home/app.lrt"] + + +# FROM busybox + +FROM busybox +WORKDIR /app/ +COPY tjs /app/tjs +RUN chmod +x /app/tjs +COPY dist_backend/app.cjs /app/app.cjs +COPY dist/ /app/dist/ +CMD ["./tjs","run","./app.cjs"] # docker tag llej0/web-font:latest llej0/web-font:latest # docker push llej0/web-font:latest # docker build -t llej0/web-font:latest . -# docker save -o llej0.web-font.latest.tar llej0/web-font:latest \ No newline at end of file +# docker save -o llej0.web-font.latest.tar llej0/web-font:latest + +# docker inspect llej0/web-font:latest | grep -i "workingdir" \ No newline at end of file diff --git a/backend/app.ts b/backend/app.ts index 660f71a..d5afacf 100644 --- a/backend/app.ts +++ b/backend/app.ts @@ -1,51 +1,87 @@ -import fs, { readFile } from "fs/promises"; -import * as path from "path"; import { fontSubset } from "./font_util/font"; import { mimeTypes } from "./server/mime_type"; import type { cMiddleware } from "./server/req_res"; import { SimpleHttpServer } from "./server/server"; -const ROOT_DIR = path.resolve("dist"); // 静态文件目录 -const staticFileMiddleware: cMiddleware = async function (req, res, next) { - if (req.method === "GET") { - const filePath = path.join(ROOT_DIR, req.url === "/" ? "index.html" : req.url); +import { path_join, readFile, stat } from "./interface"; +import "./server/tjs"; +const ROOT_DIR = "dist"; // 静态文件目录 - try { - const stats = await fs.stat(filePath); - - if (stats.isFile()) { - const fileContent = await fs.readFile(filePath); - const extname = path.extname(filePath); - res.statusCode = 200; - res.headers["Content-Type"] = mimeTypes[extname] || "application/octet-stream"; - res.headers["Content-Length"] = `${stats.size}`; - res.body = fileContent; - } else { - // 文件不存在 - res.statusCode = 404; - res.headers["Content-Type"] = "text/plain"; - res.body = "404 Not Found"; - } - } catch (err) { - // 错误处理 - res.statusCode = 404; - res.headers["Content-Type"] = "text/plain"; - res.body = `404 Not Found`; - } - } else { - // 返回 405 Method Not Allowed - res.statusCode = 405; - res.headers["Content-Type"] = "text/plain"; - res.body = "Method Not Allowed"; - } - return next(req, res); -}; const logMiddleware: cMiddleware = async (req, res, next) => { const t1 = Date.now(); const r = await next(req, res); const t2 = Date.now(); - console.log(`[${t2 - t1}ms] ${req.url}`); + console.log(`[${t2 - t1}ms] ${req.url.split("?")[0]}`); return r; }; +const reqs: Promise[] = []; +const limitMiddleware: cMiddleware = async (req, res, next) => { + const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + while (reqs.length > 5) { + if (req.socket.destroyed) { + // 连接销毁,不再执行 + console.log("destroyed"); + + return { req, res }; + } + await sleep(50); + } + + const r = Promise.resolve(next(req, res)); + reqs.push(r); + r.finally(() => { + const index = reqs.indexOf(r); + if (index > -1) { + reqs.splice(index, 1); + } + }); + return r; +}; +const staticFileMiddleware: cMiddleware = async function (req, res, next) { + let newRes: Response; + if (req.method === "GET") { + const filePath = path_join(ROOT_DIR, req.url === "/" ? "index.html" : req.url); + try { + const stats = await stat(filePath); + + if (stats.isFile()) { + const fileContent = await readFile(filePath); + const extname = filePath.split(".").pop() ?? ""; + newRes = new Response(fileContent, { + status: 200, + headers: { + "Content-Type": mimeTypes[extname] || "application/octet-stream", + "Content-Length": `${stats.size}`, + }, + }); + } else { + // 文件不存在 + newRes = new Response("404 Not Found", { + status: 404, + headers: { + "Content-Type": "text/plain; charset=utf-8", + }, + }); + } + } catch (err) { + console.log("[err]", err); + // @ts-ignore + newRes = new Response(`服务器内部错误 Not Found\n${err}\n${err.stack}`, { + status: 500, + headers: { + "Content-Type": "text/plain; charset=utf-8", + }, + }); + } + } else { + newRes = new Response("Method Not Allowed", { + status: 405, + headers: { + "Content-Type": "text/plain; charset=utf-8", + }, + }); + } + return next(req, newRes); +}; const corsMiddleware: cMiddleware = async (req, res, next) => { // 允许所有域跨域请求 res.headers["Access-Control-Allow-Origin"] = "*"; @@ -68,51 +104,43 @@ const corsMiddleware: cMiddleware = async (req, res, next) => { } }; const fontCache: { [key: string]: any } = {}; -const ttfCache: { [key: string]: any } = {}; +const textCache: { [key: string]: any } = {}; const fontApiMiddleware: cMiddleware = async (req, res, next) => { if (!req.url.startsWith("/api")) return next(req, res); - res.statusCode = 200; - res.headers["Content-Type"] = "font/ttf"; // 创建一个新的 URL 对象(需要一个完整的 URL,必须包含协议和主机) const url = new URL(req.url, "http://test.com"); - // 使用 URLSearchParams 来解析查询参数 const params = new URLSearchParams(url.search); - // 获取参数的值 const font = params.get("font") || ""; const text = params.get("text") || ""; - const path = `font/${font}`; - const fontType = path.split(".").pop() as "ttf"; - if (ttfCache[req.url]) { - // @ts-ignore - res.body = ttfCache[req.url]; + if (text.length === 0) { return { req, res }; } + const path = `font/${font}`; + const fontType = path.split(".").pop() as "ttf"; const oldFontBuffer = fontCache[path] ?? new Uint8Array(await readFile(path)).buffer; - fontCache[path] = oldFontBuffer; const outType = "ttf"; const newFont = await fontSubset(oldFontBuffer, text, { outType: outType, sourceType: fontType, }); - // @ts-ignore - res.body = newFont; - ttfCache[req.url] = newFont; - return { req, res }; -}; -const server = new SimpleHttpServer({ port: 8087 }); -server.use(logMiddleware, corsMiddleware, fontApiMiddleware, staticFileMiddleware); -// const main = async () => { -// // const path = "backend/问藏书房.ttf"; //问藏书房 -// const path = "backend/令东齐伋复刻体.ttf"; -// // const path = "./backend/GoodHood-2.otf";//英文字体 -// const fontType = path.split(".").pop() as "ttf"; -// const oldFontBuffer = new Uint8Array(await readFile(path)).buffer; -// const outType = "ttf"; -// const newFont = await fontSubset(oldFontBuffer, "abc问书房令东齐伋复刻体", { -// outType: outType, -// sourceType: fontType, -// }); -// writeFile(`./public/font.${outType}`, newFont); -// }; + return { + req, + res: new Response(newFont, { + status: 200, + headers: { + "Content-Type": "font/ttf", + }, + }), + }; +}; + +const server = new SimpleHttpServer({ port: 8087 }); +server.use( + logMiddleware, + // limitMiddleware, + // corsMiddleware, + fontApiMiddleware, + staticFileMiddleware, +); diff --git a/backend/font_util/font.ts b/backend/font_util/font.ts index 7c59b4f..875a5e8 100644 --- a/backend/font_util/font.ts +++ b/backend/font_util/font.ts @@ -19,5 +19,8 @@ export const fontSubset = async ( const newFont = optimizedFont.write({ type: option.outType, }); - return newFont as unknown as DataView; + if (typeof newFont !== "string") { + return new Uint8Array(newFont); + } + return newFont; }; diff --git a/backend/interface.ts b/backend/interface.ts new file mode 100644 index 0000000..adfb18d --- /dev/null +++ b/backend/interface.ts @@ -0,0 +1,37 @@ +export let stat: (path: string) => Promise<{ + isFile: () => boolean; + size: number; +}>; + +export let readFile: (path: string) => Promise; + +export const implInterface = (options: { stat: typeof stat; readFile: typeof readFile }) => { + stat = options.stat; + readFile = options.readFile; +}; + +export function path_join(...paths: string[]) { + // 定义路径分隔符 + const sep = "/"; + + // 函数用来移除路径片段两端的斜杠 + function trimSlashes(p: string) { + return p.replace(/\/+$/, "").replace(/^\/+/, ""); + } + + // 处理路径片段 + let result = paths + .map((path) => trimSlashes(path)) // 移除每个路径片段的前后斜杠 + .filter(Boolean) // 过滤掉空片段 + .join(sep); // 使用分隔符连接路径片段 + + // 如果最终路径为空,返回根路径 + if (!result) return sep; + + // 确保路径以分隔符开头 + if (paths[0] && paths[0].startsWith(sep)) { + result = sep + result; + } + + return result; +} diff --git a/backend/server/mime_type.ts b/backend/server/mime_type.ts index 210af0a..6441b6c 100644 --- a/backend/server/mime_type.ts +++ b/backend/server/mime_type.ts @@ -1,16 +1,16 @@ // MIME 类型映射 export const mimeTypes: Record = { - ".html": "text/html", - ".css": "text/css", - ".js": "application/javascript", - ".json": "application/json", - ".png": "image/png", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".gif": "image/gif", - ".svg": "image/svg+xml", - ".woff": "font/woff", - ".woff2": "font/woff2", - ".ttf": "font/ttf", - ".otf": "font/otf", + "html": "text/html", + "css": "text/css", + "js": "application/javascript; charset=utf-8", + "json": "application/json", + "png": "image/png", + "jpg": "image/jpeg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "svg": "image/svg+xml", + "woff": "font/woff", + "woff2": "font/woff2", + "ttf": "font/ttf", + "otf": "font/otf", }; diff --git a/backend/server/req_res.ts b/backend/server/req_res.ts index cec27e1..ea16235 100644 --- a/backend/server/req_res.ts +++ b/backend/server/req_res.ts @@ -1,21 +1,7 @@ -// 解析请求 -export function parseRequest(requestBuffer: string): cRequest { - const [requestLine] = requestBuffer.split("\r\n"); - const [method, url] = requestLine.split(" "); - return { method, url }; -} // 请求和响应模型 -export interface cRequest { - method: string; - url: string; -} - -export interface cResponse { - statusCode: number; - headers: Record; - body: Buffer | string; -} +export type cRequest = Request; +export type cResponse = Response; export type cNext = ( req: cRequest, res: cResponse, diff --git a/backend/server/server.ts b/backend/server/server.ts index 14fdc35..8b14ae5 100644 --- a/backend/server/server.ts +++ b/backend/server/server.ts @@ -1,14 +1,13 @@ -import { cMiddleware, cRequest, cResponse } from "./req_res"; -import { createTcpServer } from "./tcp_server"; +import { cMiddleware, cRequest, cResponse, type cNext } from "./req_res"; +// import { createTcpServer } from "./tcp_server"; // 配置 - // 路由器类 export class cRouter { private middleware: cMiddleware[] = []; use(middleware: cMiddleware) { this.middleware.push(middleware); - return this + return this; } async handle(req: cRequest, res: cResponse) { @@ -24,23 +23,161 @@ export class cRouter { return next(req, res); } } - // 实现一个简化的 HTTP 服务器 export class SimpleHttpServer { private router: cRouter = new cRouter(); constructor(options: { port: number; hostname?: string }) { - const server = createTcpServer((req, res) => { - const r = this.router.handle(req, res); - return r; - }); - server.listen(options.port, options.hostname, () => { - console.log(`Server is listening on port ${options.port}`); - }); + console.log(`Server is listening on port ${options.port}`); + if (global.tjs) { + this.tjsServer(options); + return this; + } + // const server = createTcpServer((req, res) => { + // const r = this.router.handle(req, res); + // return r; + // }); + // server.listen(options.port, options.hostname, () => { + // console.log(`Server is listening on port ${options.port}`); + // }); + } + private async tjsServer(options: { port: number; hostname?: string }) { + const listener = (await global.tjs.listen( + "tcp", + options.hostname ?? "::", + options.port, + {}, + )) as tjs.Listener; + // listener.localAddress; + for await (const connection of listener) { + connectionHandle(connection, this.router.handle.bind(this.router)); + } } - use(...middlewares: cMiddleware[]) { middlewares.forEach((middleware) => this.router.use(middleware)); return this; } } +const decoder = new TextDecoder("utf-8"); +const encoder = new TextEncoder(); +// 请求头终止符 +const target = encoder.encode("\r\n\r\n"); +async function connectionHandle(connection: tjs.Connection, handle: cNext) { + const { header, body } = await createStreamAfterTarget(connection.readable, target); + if (!header) { + return; + } + const httpHeaderText = decoder.decode(header); + const httpHeader = parseHttpRequest(httpHeaderText); + const rawReq = new Request(httpHeader.url, { + method: httpHeader.method, + body: httpHeader.method === "GET" || httpHeader.method === "HEAD" ? undefined : body, + headers: httpHeader.headers, + }); + const rawRes = new Response(); + + const { req, res } = await handle(rawReq, rawRes); + + const resWriter = connection.writable.getWriter(); + let headerText: string[] = []; + res.headers.forEach((value, key) => { + headerText.push(`${key}: ${value}`); + }); + const resHeaertText = `HTTP/1.1 ${res.status} OK\r\n${headerText.join("\r\n")}\r\n\r\n`; + await resWriter.write(encoder.encode(resHeaertText)); + if (res.body) { + // https://github.com/saghul/txiki.js/issues/646 + await res.body?.pipeTo(connection.writable); + } else { + // @ts-expect-error + await resWriter.write(res._bodyInit); + // await resWriter.write(encoder.encode(r)); + } + if (!resWriter.closed) { + await resWriter.close(); + } + connection.close(); +} + +function parseHttpRequest(requestText: string) { + const lines = requestText.trim().split("\n"); + if (lines.length === 0) { + throw new Error("Invalid HTTP request"); + } + + // 解析请求行 + const [method, url, httpVersion] = lines[0].split(" "); + + // 解析头部 + const headers: Record = {}; + for (let i = 1; i < lines.length; i++) { + const line = lines[i]; + if (line === "") break; // 空行表示头部结束 + + const [key, ...valueParts] = line.split(":"); + const value = valueParts.join(":").trim(); + headers[key.trim()] = value; + } + + return { + method, + url, + httpVersion, + headers, + }; +} +async function createStreamAfterTarget( + originalStream: ReadableStream, + target: Uint8Array, +) { + const reader = originalStream.getReader(); + let buffer = new Uint8Array(); + + // Function to check if target is found in the buffer + function containsTarget(buffer: Uint8Array, target: Uint8Array): number { + for (let i = 0; i <= buffer.length - target.length; i++) { + if (buffer.slice(i, i + target.length).every((value, index) => value === target[index])) { + return i; + } + } + return -1; + } + let controller = null as unknown as ReadableStreamDefaultController; + while (true) { + const { done, value } = await reader.read(); + if (done) { + controller.close(); + break; // Stream ended + } + if (controller) { + controller.enqueue(value); + continue; + } + // Append the new chunk to the buffer + const newBuffer = new Uint8Array(buffer.length + value.length); + newBuffer.set(buffer); + newBuffer.set(value, buffer.length); + buffer = newBuffer; + + // Check if the target is found in the buffer + const targetIndex = containsTarget(buffer, target); + if (targetIndex !== -1) { + // Found the target data, return the remaining buffer after the target data + const start = targetIndex + target.length; + const header = buffer.slice(0, start); + const remainingData = buffer.slice(start); + const body = new ReadableStream({ + start(c) { + controller = c; + controller.enqueue(remainingData); + }, + }); + // Create a new stream from the remaining data + return { + header, + body, + }; + } + } + return { header: null, body: new ReadableStream() }; // Return an empty stream if the target is not found +} diff --git a/backend/server/tcp_server.ts b/backend/server/tcp_server.ts index c0367db..dcb317d 100644 --- a/backend/server/tcp_server.ts +++ b/backend/server/tcp_server.ts @@ -16,7 +16,7 @@ export function createTcpServer(handle: cNext) { // 如果收到请求头的结束标志,则处理请求 if (requestBuffer.includes("\r\n\r\n")) { - const req = parseRequest(requestBuffer); + const req = parseRequest(requestBuffer, socket); const res: cResponse = { statusCode: 200, headers: {}, body: "" }; try { // 处理请求 diff --git a/backend/server/tjs.ts b/backend/server/tjs.ts new file mode 100644 index 0000000..3663bb9 --- /dev/null +++ b/backend/server/tjs.ts @@ -0,0 +1,14 @@ +import { implInterface } from "../interface"; + +implInterface({ + async stat(path) { + const r = await global.tjs.stat(path); + return { + isFile: () => r.isFile, + size: r.size, + }; + }, + readFile(path) { + return global.tjs.readFile(path); + }, +}); diff --git a/backend/test.js b/backend/test.js new file mode 100644 index 0000000..168178b --- /dev/null +++ b/backend/test.js @@ -0,0 +1,20 @@ +// console.log("[global.tjs.engine]", global.tjs.engine.gc.enabled); +// global.tjs.engine.gc.threshold = 100; +// console.log("[global.tjs.engine]", global.tjs.engine.gc.threshold); + +function runGCTests() { + let objects = []; + for (let i = 0; i < 100000; i++) { + objects[i] = { index: i, data: new Array(1000).fill(i) }; + } + objects = null; // Dereference the objects to make them eligible for garbage collection +} + +runGCTests(); +setInterval(() => { + if (global.tjs) { + console.log("[global.tjs.engine]", global.tjs.engine.gc.run()); + } +}, 3000); +setTimeout(() => {}, 1000000); +// 168064 diff --git a/package.json b/package.json index 08d7678..a53a540 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc -b && vite build", + "build": "vite build", "build_backend": "tsup && ./llrt2 compile ./dist_backend/app.cjs ./dist_backend/app.lrt", "docker_build": "docker build -t llej0/web-font:${npm_package_version} -t llej0/web-font:latest .", "docker_push": "docker push llej0/web-font:${npm_package_version} && docker push llej0/web-font:latest", @@ -16,6 +16,7 @@ "solid-js": "^1.8.20" }, "devDependencies": { + "@txikijs/types": "^24.6.0", "@types/node": "^22.4.0", "tsup": "^8.2.4", "typescript": "^5.5.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d78c7ba..4776d9c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,6 +15,9 @@ importers: specifier: ^1.8.20 version: 1.8.21 devDependencies: + '@txikijs/types': + specifier: ^24.6.0 + version: 24.6.0 '@types/node': specifier: ^22.4.0 version: 22.4.0 @@ -522,6 +525,9 @@ packages: cpu: [x64] os: [win32] + '@txikijs/types@24.6.0': + resolution: {integrity: sha512-BKQvQCUddJBVlAnBxdaaMpBhGKYUaaZVboRwasH6x8TMwMNOrRm+gHywUqLopHXLmIBevECg5L3pAjT2wS+iMg==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1538,6 +1544,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.20.0': optional: true + '@txikijs/types@24.6.0': {} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.25.3 diff --git a/src/App.tsx b/src/App.tsx index 9fcbf26..eb64eed 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,7 +3,8 @@ import { createMemo, createSignal } from "solid-js"; function App() { const [text, set_text] = createSignal("天地无极,乾坤借法"); - const serverPath = import.meta.env.DEV ? "/" : "https://webfont.shenzilong.cn/"; + // const serverPath = import.meta.env.DEV ? "/" : "https://webfont.shenzilong.cn/"; + const serverPath = "/"; const style = createMemo( () => ` @font-face { diff --git a/tsconfig.app.json b/tsconfig.app.json index 8819bec..ee93c1c 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -3,9 +3,13 @@ "target": "ES2020", "useDefineForClassFields": true, "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": [ + "ES2020", + "DOM", + "DOM.Iterable" + ], + "types": [], "skipLibCheck": true, - /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, @@ -14,12 +18,13 @@ "noEmit": true, "jsx": "preserve", "jsxImportSource": "solid-js", - /* Linting */ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src"] -} + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 1ffef60..f70380e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,16 @@ { "files": [], + "compilerOptions": { + "types": [ + "txikijs" + ] + }, "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.node.json" + } ] -} +} \ No newline at end of file diff --git a/tsconfig.node.json b/tsconfig.node.json index db4ed3b..cac66fd 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,12 +1,14 @@ { "compilerOptions": { - "target": "ES2022", + "target": "ES2023", "lib": [ - "ES2023" + "ES2023","DOM" + ], + "typeRoots": [ + "node_modules/@txikijs/types" ], "module": "ESNext", "skipLibCheck": true, - "types": [], /* Bundler mode */ "moduleResolution": "bundler", "allowImportingTsExtensions": true, @@ -21,6 +23,7 @@ }, "include": [ "vite.config.ts", - "backend/*.ts" -, "backend/server/mime_type.ts", "backend/server/server.ts" ] + "backend/*.ts", + "backend/**/*.ts", + ] } \ No newline at end of file diff --git a/tsup.config.ts b/tsup.config.ts index 156bc87..53acdb3 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -7,5 +7,6 @@ export default defineConfig({ clean: true, bundle: true, noExternal: [/.*/], - outDir:"dist_backend" + external: ["@txikijs/types"], + outDir: "dist_backend", });