@devlusoft/devix 0.2.0 → 0.2.1
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/dist/cli/build.js +30 -308
- package/dist/cli/build.js.map +3 -3
- package/dist/cli/dev.js +32 -395
- package/dist/cli/dev.js.map +3 -3
- package/dist/cli/generate.js +30 -434
- package/dist/cli/generate.js.map +3 -3
- package/dist/cli/index.js +33 -698
- package/dist/cli/index.js.map +3 -3
- package/dist/cli/start.js +1 -89
- package/dist/cli/start.js.map +2 -2
- package/dist/config.js +1 -16
- package/dist/config.js.map +2 -2
- package/dist/runtime/api-context.js +1 -17
- package/dist/runtime/api-context.js.map +2 -2
- package/dist/runtime/client-router.js +1 -58
- package/dist/runtime/client-router.js.map +2 -2
- package/dist/runtime/context.js +1 -14
- package/dist/runtime/context.js.map +2 -2
- package/dist/runtime/error-boundary.js +1 -36
- package/dist/runtime/error-boundary.js.map +2 -2
- package/dist/runtime/fetch.js +1 -34
- package/dist/runtime/fetch.js.map +2 -2
- package/dist/runtime/head.js +1 -68
- package/dist/runtime/head.js.map +2 -2
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -367
- package/dist/runtime/index.js.map +3 -3
- package/dist/runtime/link.js +1 -42
- package/dist/runtime/link.js.map +2 -2
- package/dist/runtime/metadata.js +1 -21
- package/dist/runtime/metadata.js.map +2 -2
- package/dist/runtime/router-provider.js +1 -258
- package/dist/runtime/router-provider.js.map +2 -2
- package/dist/server/api-router.js +1 -64
- package/dist/server/api-router.js.map +2 -2
- package/dist/server/api.js +1 -123
- package/dist/server/api.js.map +2 -2
- package/dist/server/collect-css.js +1 -14
- package/dist/server/collect-css.js.map +2 -2
- package/dist/server/index.js +1 -132
- package/dist/server/index.js.map +2 -2
- package/dist/server/pages-router.js +1 -63
- package/dist/server/pages-router.js.map +2 -2
- package/dist/server/render.js +1 -305
- package/dist/server/render.js.map +2 -2
- package/dist/server/routes.js +1 -41
- package/dist/server/routes.js.map +2 -2
- package/dist/utils/async.js +1 -13
- package/dist/utils/async.js.map +2 -2
- package/dist/utils/banner.js +1 -33
- package/dist/utils/banner.js.map +2 -2
- package/dist/utils/cookies.js +1 -28
- package/dist/utils/cookies.js.map +2 -2
- package/dist/utils/duration.js +1 -21
- package/dist/utils/duration.js.map +2 -2
- package/dist/utils/env.js +1 -13
- package/dist/utils/env.js.map +2 -2
- package/dist/utils/html.js +1 -11
- package/dist/utils/html.js.map +2 -2
- package/dist/utils/patterns.js +1 -7
- package/dist/utils/patterns.js.map +2 -2
- package/dist/utils/response.d.ts +4 -1
- package/dist/utils/response.js +1 -9
- package/dist/utils/response.js.map +3 -3
- package/dist/vite/codegen/api.js +6 -12
- package/dist/vite/codegen/api.js.map +2 -2
- package/dist/vite/codegen/client-routes.js +6 -12
- package/dist/vite/codegen/client-routes.js.map +2 -2
- package/dist/vite/codegen/context.js +2 -8
- package/dist/vite/codegen/context.js.map +2 -2
- package/dist/vite/codegen/entry-client.js +4 -10
- package/dist/vite/codegen/entry-client.js.map +2 -2
- package/dist/vite/codegen/extract-methods.js +1 -15
- package/dist/vite/codegen/extract-methods.js.map +2 -2
- package/dist/vite/codegen/render.js +6 -12
- package/dist/vite/codegen/render.js.map +2 -2
- package/dist/vite/codegen/routes-dts.js +11 -49
- package/dist/vite/codegen/routes-dts.js.map +3 -3
- package/dist/vite/codegen/scan-api.js +1 -77
- package/dist/vite/codegen/scan-api.js.map +3 -3
- package/dist/vite/codegen/write-routes-dts.js +1 -16
- package/dist/vite/codegen/write-routes-dts.js.map +2 -2
- package/dist/vite/index.js +30 -247
- package/dist/vite/index.js.map +3 -3
- package/package.json +2 -2
package/dist/cli/dev.js
CHANGED
|
@@ -1,20 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { getRequestListener } from "@hono/node-server";
|
|
5
|
-
import { Hono } from "hono";
|
|
6
|
-
|
|
7
|
-
// src/vite/index.ts
|
|
8
|
-
import { mergeConfig } from "vite";
|
|
9
|
-
import react from "@vitejs/plugin-react";
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
11
|
-
import { dirname, resolve } from "node:path";
|
|
12
|
-
|
|
13
|
-
// src/vite/codegen/entry-client.ts
|
|
14
|
-
function generateEntryClient({ cssUrls }) {
|
|
15
|
-
const cssImports = cssUrls.map((u) => `import '${u}'`).join("\n");
|
|
16
|
-
return `
|
|
17
|
-
${cssImports}
|
|
1
|
+
import{createServer as xt}from"node:http";import{createServer as yt}from"vite";import{getRequestListener as Rt}from"@hono/node-server";import{Hono as vt}from"hono";import{mergeConfig as lt}from"vite";import ut from"@vitejs/plugin-react";import{fileURLToPath as pt}from"node:url";import{dirname as dt,resolve as f}from"node:path";function b({cssUrls:t}){return`
|
|
2
|
+
${t.map(r=>`import '${r}'`).join(`
|
|
3
|
+
`)}
|
|
18
4
|
import "@vitejs/plugin-react/preamble"
|
|
19
5
|
import React from "react"
|
|
20
6
|
import {hydrateRoot, createRoot} from 'react-dom/client'
|
|
@@ -68,17 +54,12 @@ if (!window.__DEVIX__) {
|
|
|
68
54
|
)
|
|
69
55
|
}
|
|
70
56
|
}
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// src/vite/codegen/client-routes.ts
|
|
75
|
-
function generateClientRoutes({ pagesDir, matcherPath }) {
|
|
76
|
-
return `
|
|
57
|
+
`}function L({pagesDir:t,matcherPath:e}){return`
|
|
77
58
|
import React from 'react'
|
|
78
|
-
import { createMatcher } from '${
|
|
79
|
-
const pageFiles = import.meta.glob(['/${
|
|
80
|
-
const layoutFiles = import.meta.glob('/${
|
|
81
|
-
const errorFiles = import.meta.glob('/${
|
|
59
|
+
import { createMatcher } from '${e}'
|
|
60
|
+
const pageFiles = import.meta.glob(['/${t}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
|
|
61
|
+
const layoutFiles = import.meta.glob('/${t}/**/layout.tsx')
|
|
62
|
+
const errorFiles = import.meta.glob('/${t}/**/error.tsx')
|
|
82
63
|
|
|
83
64
|
export const matchClientRoute = createMatcher(pageFiles, layoutFiles)
|
|
84
65
|
|
|
@@ -101,21 +82,16 @@ export function getDefaultErrorPage() {
|
|
|
101
82
|
)
|
|
102
83
|
}
|
|
103
84
|
}
|
|
104
|
-
|
|
105
|
-
}
|
|
85
|
+
`}function M({pagesDir:t,renderPath:e}){return`
|
|
86
|
+
import { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${e}'
|
|
106
87
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return `
|
|
110
|
-
import { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${renderPath}'
|
|
111
|
-
|
|
112
|
-
const _pages = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
|
|
113
|
-
const _layouts = import.meta.glob('/${pagesDir}/**/layout.tsx')
|
|
88
|
+
const _pages = import.meta.glob(['/${t}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
|
|
89
|
+
const _layouts = import.meta.glob('/${t}/**/layout.tsx')
|
|
114
90
|
|
|
115
91
|
const _glob = {
|
|
116
92
|
pages: _pages,
|
|
117
93
|
layouts: _layouts,
|
|
118
|
-
pagesDir: '/${
|
|
94
|
+
pagesDir: '/${t}',
|
|
119
95
|
}
|
|
120
96
|
|
|
121
97
|
export function render(url, request, options) {
|
|
@@ -129,384 +105,45 @@ export function runLoader(url, request, options) {
|
|
|
129
105
|
export function getStaticRoutes() {
|
|
130
106
|
return _getStaticRoutes(_glob)
|
|
131
107
|
}
|
|
132
|
-
|
|
133
|
-
}
|
|
108
|
+
`}function O({apiPath:t,appDir:e}){return`
|
|
109
|
+
import { handleApiRequest as _handleApiRequest } from '${t}'
|
|
134
110
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return `
|
|
138
|
-
import { handleApiRequest as _handleApiRequest } from '${apiPath}'
|
|
139
|
-
|
|
140
|
-
const _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])
|
|
141
|
-
const _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')
|
|
111
|
+
const _routes = import.meta.glob(['/${e}/api/**/*.ts', '!**/middleware.ts'])
|
|
112
|
+
const _middlewares = import.meta.glob('/${e}/api/**/middleware.ts')
|
|
142
113
|
|
|
143
114
|
const _glob = {
|
|
144
115
|
routes: _routes,
|
|
145
116
|
middlewares: _middlewares,
|
|
146
|
-
apiDir: '/${
|
|
117
|
+
apiDir: '/${e}/api',
|
|
147
118
|
}
|
|
148
119
|
|
|
149
120
|
export function handleApiRequest(url, request) {
|
|
150
121
|
return _handleApiRequest(url, request, _glob)
|
|
151
122
|
}
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// src/utils/patterns.ts
|
|
156
|
-
function routePattern(rel) {
|
|
157
|
-
return rel.replace(/\.(tsx|ts|jsx|js)$/, "").replace(/\(.*?\)\//g, "").replace(/^index$|\/index$/, "").replace(/\[([^\]]+)]/g, ":$1") || "/";
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// src/server/pages-router.ts
|
|
161
|
-
var cache = null;
|
|
162
|
-
function invalidatePagesCache() {
|
|
163
|
-
cache = null;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// src/server/api-router.ts
|
|
167
|
-
function keyToRoutePattern(key, apiDir) {
|
|
168
|
-
const rel = key.slice(apiDir.length + 1).replace(/\\/g, "/");
|
|
169
|
-
const pattern = routePattern(rel);
|
|
170
|
-
return pattern === "/" ? "/api" : `/api/${pattern}`.replace("/api//", "/api/");
|
|
171
|
-
}
|
|
172
|
-
var cache2 = null;
|
|
173
|
-
function invalidateApiCache() {
|
|
174
|
-
cache2 = null;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// src/vite/codegen/context.ts
|
|
178
|
-
function generateContext() {
|
|
179
|
-
return `
|
|
123
|
+
`}function x(t){return t.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var J=null;function y(){J=null}function I(t,e){let r=t.slice(e.length+1).replace(/\\/g,"/"),o=x(r);return o==="/"?"/api":`/api/${o}`.replace("/api//","/api/")}var Z=null;function R(){Z=null}function k(){return`
|
|
180
124
|
export {RouterContext} from '@devlusoft/devix/runtime/context'
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// src/vite/codegen/scan-api.ts
|
|
185
|
-
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
186
|
-
import { join, relative } from "node:path";
|
|
187
|
-
|
|
188
|
-
// src/vite/codegen/extract-methods.ts
|
|
189
|
-
var METHOD_EXPORT_RE = /export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;
|
|
190
|
-
function stripComments(content) {
|
|
191
|
-
return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
192
|
-
}
|
|
193
|
-
function extractHttpMethods(content) {
|
|
194
|
-
const found = /* @__PURE__ */ new Set();
|
|
195
|
-
for (const match of stripComments(content).matchAll(METHOD_EXPORT_RE)) {
|
|
196
|
-
found.add(match[1]);
|
|
197
|
-
}
|
|
198
|
-
return [...found];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// src/vite/codegen/routes-dts.ts
|
|
202
|
-
function filePathToIdentifier(filePath, apiDir) {
|
|
203
|
-
return "_api_" + filePath.slice(`${apiDir}/`.length).replace(/\.(ts|tsx)$/, "").replace(/[^a-zA-Z0-9]/g, "_");
|
|
204
|
-
}
|
|
205
|
-
function buildRouteEntry(filePath, apiDir, methods) {
|
|
206
|
-
return {
|
|
207
|
-
filePath,
|
|
208
|
-
urlPattern: keyToRoutePattern(filePath, apiDir),
|
|
209
|
-
identifier: filePathToIdentifier(filePath, apiDir),
|
|
210
|
-
methods
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
function generateRoutesDts(entries, apiDir) {
|
|
214
|
-
if (entries.length === 0) {
|
|
215
|
-
return `// auto-generado por devix \u2014 no editar
|
|
125
|
+
`}import{readFileSync as et,readdirSync as rt,statSync as ot}from"node:fs";import{join as w,relative as nt}from"node:path";var K=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g;function Q(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function U(t){let e=new Set;for(let r of Q(t).matchAll(K))e.add(r[1]);return[...e]}function tt(t,e){return"_api_"+t.slice(`${e}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function q(t,e,r){return{filePath:t,urlPattern:I(t,e),identifier:tt(t,e),methods:r}}function v(t,e){if(t.length===0)return`// auto-generado por devix \u2014 no editar
|
|
216
126
|
declare module '@devlusoft/devix' {
|
|
217
127
|
interface ApiRoutes {}
|
|
218
128
|
}
|
|
219
|
-
`;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return `import type * as ${e.identifier} from '${importPath}'`;
|
|
224
|
-
}).join("\n");
|
|
225
|
-
const routeLines = entries.flatMap(
|
|
226
|
-
(e) => e.methods.map(
|
|
227
|
-
(m) => ` '${m} ${e.urlPattern}': InferRoute<(typeof ${e.identifier})['${m}']>`
|
|
228
|
-
)
|
|
229
|
-
).join("\n");
|
|
230
|
-
return `// auto-generado por devix \u2014 no editar
|
|
231
|
-
${imports}
|
|
129
|
+
`;let r=t.map(n=>{let s="../"+n.filePath.replace(/\.(ts|tsx)$/,"");return`import type * as ${n.identifier} from '${s}'`}).join(`
|
|
130
|
+
`),o=t.flatMap(n=>n.methods.map(s=>` '${s} ${n.urlPattern}': InferRoute<(typeof ${n.identifier})['${s}']>`)).join(`
|
|
131
|
+
`);return`// auto-generado por devix \u2014 no editar
|
|
132
|
+
${r}
|
|
232
133
|
|
|
134
|
+
type JsonResponse<T> = Response & { readonly __body: T }
|
|
233
135
|
type InferRoute<T> = T extends (...args: any[]) => any
|
|
234
|
-
?
|
|
136
|
+
? Awaited<ReturnType<T>> extends JsonResponse<infer U>
|
|
137
|
+
? U
|
|
138
|
+
: Exclude<Awaited<ReturnType<T>>, Response | null | void>
|
|
235
139
|
: never
|
|
236
140
|
|
|
237
141
|
declare module '@devlusoft/devix' {
|
|
238
142
|
interface ApiRoutes {
|
|
239
|
-
${
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
`;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// src/vite/codegen/scan-api.ts
|
|
246
|
-
function walkDir(dir, root) {
|
|
247
|
-
const entries = [];
|
|
248
|
-
for (const name of readdirSync(dir)) {
|
|
249
|
-
const full = join(dir, name);
|
|
250
|
-
if (statSync(full).isDirectory()) {
|
|
251
|
-
entries.push(...walkDir(full, root));
|
|
252
|
-
} else if (/\.(ts|tsx)$/.test(name)) {
|
|
253
|
-
entries.push(relative(root, full).replace(/\\/g, "/"));
|
|
254
|
-
}
|
|
143
|
+
${o}
|
|
255
144
|
}
|
|
256
|
-
return entries;
|
|
257
145
|
}
|
|
258
|
-
function
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
try {
|
|
262
|
-
files = walkDir(apiDir, projectRoot);
|
|
263
|
-
} catch {
|
|
264
|
-
return [];
|
|
265
|
-
}
|
|
266
|
-
return files.filter((f) => !f.endsWith("middleware.ts") && !f.endsWith("middleware.tsx")).flatMap((filePath) => {
|
|
267
|
-
try {
|
|
268
|
-
const content = readFileSync(join(projectRoot, filePath), "utf-8");
|
|
269
|
-
const methods = extractHttpMethods(content);
|
|
270
|
-
if (methods.length === 0) return [];
|
|
271
|
-
return [buildRouteEntry(filePath, `${appDir}/api`, methods)];
|
|
272
|
-
} catch {
|
|
273
|
-
return [];
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// src/vite/codegen/write-routes-dts.ts
|
|
279
|
-
import { mkdirSync, readFileSync as readFileSync2, writeFileSync, existsSync } from "node:fs";
|
|
280
|
-
import { join as join2 } from "node:path";
|
|
281
|
-
function writeRoutesDts(content, projectRoot) {
|
|
282
|
-
const devixDir = join2(projectRoot, ".devix");
|
|
283
|
-
const outPath = join2(devixDir, "routes.d.ts");
|
|
284
|
-
mkdirSync(devixDir, { recursive: true });
|
|
285
|
-
if (existsSync(outPath) && readFileSync2(outPath, "utf-8") === content) {
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
writeFileSync(outPath, content, "utf-8");
|
|
289
|
-
return true;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// src/vite/index.ts
|
|
293
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
294
|
-
var VIRTUAL_ENTRY_CLIENT = "virtual:devix/entry-client";
|
|
295
|
-
var VIRTUAL_CLIENT_ROUTES = "virtual:devix/client-routes";
|
|
296
|
-
var VIRTUAL_RENDER = "virtual:devix/render";
|
|
297
|
-
var VIRTUAL_API = "virtual:devix/api";
|
|
298
|
-
var VIRTUAL_CONTEXT = "virtual:devix/context";
|
|
299
|
-
function devix(config2) {
|
|
300
|
-
const appDir = config2.appDir ?? "app";
|
|
301
|
-
const pagesDir = `${appDir}/pages`;
|
|
302
|
-
const cssUrls = (config2.css ?? []).map((u) => u.startsWith("/") ? u : `/${u.replace(/^\.\//, "")}`);
|
|
303
|
-
const renderPath = resolve(__dirname, "../server/render.js").replace(/\\/g, "/");
|
|
304
|
-
const apiPath = resolve(__dirname, "../server/api.js").replace(/\\/g, "/");
|
|
305
|
-
const matcherPath = resolve(__dirname, "../runtime/client-router.js").replace(/\\/g, "/");
|
|
306
|
-
const virtualPlugin = {
|
|
307
|
-
name: "devix",
|
|
308
|
-
enforce: "pre",
|
|
309
|
-
resolveId(id) {
|
|
310
|
-
if (id === VIRTUAL_ENTRY_CLIENT) return `\0${VIRTUAL_ENTRY_CLIENT}`;
|
|
311
|
-
if (id === VIRTUAL_CLIENT_ROUTES) return `\0${VIRTUAL_CLIENT_ROUTES}`;
|
|
312
|
-
if (id === VIRTUAL_RENDER) return `\0${VIRTUAL_RENDER}`;
|
|
313
|
-
if (id === VIRTUAL_API) return `\0${VIRTUAL_API}`;
|
|
314
|
-
if (id === VIRTUAL_CONTEXT) return `\0${VIRTUAL_CONTEXT}`;
|
|
315
|
-
},
|
|
316
|
-
load(id) {
|
|
317
|
-
if (id === `\0${VIRTUAL_ENTRY_CLIENT}`)
|
|
318
|
-
return generateEntryClient({ cssUrls });
|
|
319
|
-
if (id === `\0${VIRTUAL_CLIENT_ROUTES}`)
|
|
320
|
-
return generateClientRoutes({ pagesDir, matcherPath });
|
|
321
|
-
if (id === `\0${VIRTUAL_RENDER}`)
|
|
322
|
-
return generateRender({ pagesDir, renderPath });
|
|
323
|
-
if (id === `\0${VIRTUAL_API}`)
|
|
324
|
-
return generateApi({ apiPath, appDir });
|
|
325
|
-
if (id === `\0${VIRTUAL_CONTEXT}`)
|
|
326
|
-
return generateContext();
|
|
327
|
-
},
|
|
328
|
-
buildStart() {
|
|
329
|
-
const root = process.cwd();
|
|
330
|
-
const entries = scanApiFiles(appDir, root);
|
|
331
|
-
writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root);
|
|
332
|
-
},
|
|
333
|
-
configureServer(server) {
|
|
334
|
-
const root = process.cwd();
|
|
335
|
-
const regenerateDts = () => {
|
|
336
|
-
const entries = scanApiFiles(appDir, root);
|
|
337
|
-
writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root);
|
|
338
|
-
};
|
|
339
|
-
server.watcher.on("add", (file) => {
|
|
340
|
-
if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache();
|
|
341
|
-
if (file.includes(`${appDir}/api`)) {
|
|
342
|
-
invalidateApiCache();
|
|
343
|
-
regenerateDts();
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
server.watcher.on("unlink", (file) => {
|
|
347
|
-
if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache();
|
|
348
|
-
if (file.includes(`${appDir}/api`)) {
|
|
349
|
-
invalidateApiCache();
|
|
350
|
-
regenerateDts();
|
|
351
|
-
}
|
|
352
|
-
});
|
|
353
|
-
server.watcher.on("change", (file) => {
|
|
354
|
-
if (file.includes(`${appDir}/api`) && !file.endsWith("middleware.ts")) {
|
|
355
|
-
regenerateDts();
|
|
356
|
-
}
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
const base = {
|
|
361
|
-
plugins: [react(), virtualPlugin],
|
|
362
|
-
ssr: { noExternal: ["@devlusoft/devix"] },
|
|
363
|
-
...config2.envPrefix ? { envPrefix: config2.envPrefix } : {}
|
|
364
|
-
};
|
|
365
|
-
return mergeConfig(base, config2.vite ?? {});
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// src/server/routes.ts
|
|
369
|
-
function registerApiRoutes(app2, { apiModule: apiModule2, renderModule: renderModule2, loaderTimeout }) {
|
|
370
|
-
app2.all("/api/*", async (c) => {
|
|
371
|
-
try {
|
|
372
|
-
return await apiModule2.handleApiRequest(c.req.url, c.req.raw);
|
|
373
|
-
} catch (e) {
|
|
374
|
-
console.error(e);
|
|
375
|
-
return c.json({ error: "internal error" }, 500);
|
|
376
|
-
}
|
|
377
|
-
});
|
|
378
|
-
app2.get("/_data/*", async (c) => {
|
|
379
|
-
try {
|
|
380
|
-
const { pathname, search } = new URL(c.req.url, "http://localhost");
|
|
381
|
-
const url = pathname.replace(/^\/_data/, "") + search;
|
|
382
|
-
const data = await renderModule2.runLoader(url, c.req.raw, { loaderTimeout });
|
|
383
|
-
return c.json(data);
|
|
384
|
-
} catch (e) {
|
|
385
|
-
console.error(e);
|
|
386
|
-
return c.json({ error: "internal error" }, 500);
|
|
387
|
-
}
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// src/utils/banner.ts
|
|
392
|
-
import pc from "picocolors";
|
|
393
|
-
import { networkInterfaces } from "node:os";
|
|
394
|
-
import { createRequire } from "node:module";
|
|
395
|
-
function getNetworkUrl(port2) {
|
|
396
|
-
const nets = networkInterfaces();
|
|
397
|
-
for (const interfaces of Object.values(nets)) {
|
|
398
|
-
for (const net of interfaces ?? []) {
|
|
399
|
-
if (net.family === "IPv4" && !net.internal) {
|
|
400
|
-
return `http://${net.address}:${port2}/`;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
return null;
|
|
405
|
-
}
|
|
406
|
-
function printDevBanner(port2) {
|
|
407
|
-
const req = createRequire(import.meta.url);
|
|
408
|
-
const version = req("../../package.json").version;
|
|
409
|
-
const networkUrl = getNetworkUrl(port2);
|
|
410
|
-
console.log();
|
|
411
|
-
console.log(` ${pc.bold(pc.yellow("devix"))} ${pc.dim(`v${version}`)}`);
|
|
412
|
-
console.log();
|
|
413
|
-
console.log(` ${pc.green("\u279C")} ${pc.bold("Local:")} ${pc.cyan(`http://localhost:${port2}/`)}`);
|
|
414
|
-
if (networkUrl) {
|
|
415
|
-
console.log(` ${pc.green("\u279C")} ${pc.bold("Network:")} ${pc.cyan(networkUrl)}`);
|
|
416
|
-
} else {
|
|
417
|
-
console.log(` ${pc.green("\u279C")} ${pc.bold("Network:")} ${pc.dim("use --host to expose")}`);
|
|
418
|
-
}
|
|
419
|
-
console.log();
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// src/server/collect-css.ts
|
|
423
|
-
async function collectCss(vite2) {
|
|
424
|
-
const cssUrls = /* @__PURE__ */ new Set();
|
|
425
|
-
for (const [, mod] of vite2.moduleGraph.idToModuleMap) {
|
|
426
|
-
if (!mod.id) continue;
|
|
427
|
-
if (mod.id.endsWith(".css") || mod.id.includes(".css?")) {
|
|
428
|
-
cssUrls.add(mod.url);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
return [...cssUrls];
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
// src/utils/duration.ts
|
|
435
|
-
function parseDuration(value) {
|
|
436
|
-
if (typeof value === "number") return value;
|
|
437
|
-
const match = value.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);
|
|
438
|
-
if (!match) throw new Error(`[devix] Invalid duration: "${value}". Use a number (ms) or a string like "5s", "2m", "500ms".`);
|
|
439
|
-
const n = parseFloat(match[1]);
|
|
440
|
-
switch (match[2]) {
|
|
441
|
-
case "h":
|
|
442
|
-
return n * 36e5;
|
|
443
|
-
case "m":
|
|
444
|
-
return n * 6e4;
|
|
445
|
-
case "s":
|
|
446
|
-
return n * 1e3;
|
|
447
|
-
case "ms":
|
|
448
|
-
default:
|
|
449
|
-
return n;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// src/utils/env.ts
|
|
454
|
-
import { loadEnv } from "vite";
|
|
455
|
-
function loadDotenv(mode) {
|
|
456
|
-
const env = loadEnv(mode, process.cwd(), "");
|
|
457
|
-
for (const [key, value] of Object.entries(env)) {
|
|
458
|
-
if (process.env[key] === void 0) {
|
|
459
|
-
process.env[key] = value;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// src/cli/dev.ts
|
|
465
|
-
loadDotenv("development");
|
|
466
|
-
var VIRTUAL_RENDER2 = "virtual:devix/render";
|
|
467
|
-
var VIRTUAL_API2 = "virtual:devix/api";
|
|
468
|
-
var config = (await import(`${process.cwd()}/devix.config.ts`)).default;
|
|
469
|
-
var port = Number(process.env.PORT) || config.port || 3e3;
|
|
470
|
-
var host = typeof config.host === "string" ? config.host : config.host ? "0.0.0.0" : "localhost";
|
|
471
|
-
var vite = await createViteServer({
|
|
472
|
-
...devix(config),
|
|
473
|
-
configFile: false,
|
|
474
|
-
appType: "custom",
|
|
475
|
-
server: { middlewareMode: true }
|
|
476
|
-
});
|
|
477
|
-
var renderModule = {
|
|
478
|
-
render: async (...args) => (await vite.ssrLoadModule(VIRTUAL_RENDER2)).render(...args),
|
|
479
|
-
runLoader: async (...args) => (await vite.ssrLoadModule(VIRTUAL_RENDER2)).runLoader(...args)
|
|
480
|
-
};
|
|
481
|
-
var apiModule = {
|
|
482
|
-
handleApiRequest: async (...args) => (await vite.ssrLoadModule(VIRTUAL_API2)).handleApiRequest(...args)
|
|
483
|
-
};
|
|
484
|
-
var app = new Hono();
|
|
485
|
-
registerApiRoutes(app, { renderModule, apiModule });
|
|
486
|
-
app.get("*", async (c) => {
|
|
487
|
-
try {
|
|
488
|
-
const { html, statusCode, headers } = await renderModule.render(c.req.url, c.req.raw, { loaderTimeout: parseDuration(config.loaderTimeout ?? 1e4) });
|
|
489
|
-
const cssUrls = await collectCss(vite);
|
|
490
|
-
const cssLinks = cssUrls.map((url) => `<link rel="stylesheet" href="${url}">`).join("\n");
|
|
491
|
-
const htmlWithCss = cssLinks ? html.replace("</head>", `${cssLinks}
|
|
492
|
-
</head>`) : html;
|
|
493
|
-
const transformed = await vite.transformIndexHtml(c.req.url, `<!DOCTYPE html>${htmlWithCss}`);
|
|
494
|
-
const res = c.html(transformed, statusCode);
|
|
495
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
496
|
-
res.headers.set(key, value);
|
|
497
|
-
}
|
|
498
|
-
return res;
|
|
499
|
-
} catch (e) {
|
|
500
|
-
vite.ssrFixStacktrace(e);
|
|
501
|
-
console.error(e);
|
|
502
|
-
return c.text("Internal Server Error", 500);
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
var honoHandler = getRequestListener(app.fetch);
|
|
506
|
-
createServer(async (req, res) => {
|
|
507
|
-
await new Promise((resolve2) => vite.middlewares(req, res, resolve2));
|
|
508
|
-
if (!res.writableEnded) await honoHandler(req, res);
|
|
509
|
-
}).listen(port, host, () => {
|
|
510
|
-
printDevBanner(port);
|
|
511
|
-
});
|
|
146
|
+
`}function H(t,e){let r=[];for(let o of rt(t)){let n=w(t,o);ot(n).isDirectory()?r.push(...H(n,e)):/\.(ts|tsx)$/.test(o)&&r.push(nt(e,n).replace(/\\/g,"/"))}return r}function E(t,e){let r=w(e,t,"api"),o;try{o=H(r,e)}catch{return[]}return o.filter(n=>!n.endsWith("middleware.ts")&&!n.endsWith("middleware.tsx")).flatMap(n=>{try{let s=et(w(e,n),"utf-8"),l=U(s);return l.length===0?[]:[q(n,`${t}/api`,l)]}catch{return[]}})}import{mkdirSync as it,readFileSync as st,writeFileSync as at,existsSync as ct}from"node:fs";import{join as j}from"node:path";function $(t,e){let r=j(e,".devix"),o=j(r,"routes.d.ts");return it(r,{recursive:!0}),ct(o)&&st(o,"utf-8")===t?!1:(at(o,t,"utf-8"),!0)}var P=dt(pt(import.meta.url)),_="virtual:devix/entry-client",T="virtual:devix/client-routes",A="virtual:devix/render",D="virtual:devix/api",C="virtual:devix/context";function F(t){let e=t.appDir??"app",r=`${e}/pages`,o=(t.css??[]).map(i=>i.startsWith("/")?i:`/${i.replace(/^\.\//,"")}`),n=f(P,"../server/render.js").replace(/\\/g,"/"),s=f(P,"../server/api.js").replace(/\\/g,"/"),l=f(P,"../runtime/client-router.js").replace(/\\/g,"/"),g={name:"devix",enforce:"pre",resolveId(i){if(i===_)return`\0${_}`;if(i===T)return`\0${T}`;if(i===A)return`\0${A}`;if(i===D)return`\0${D}`;if(i===C)return`\0${C}`},load(i){if(i===`\0${_}`)return b({cssUrls:o});if(i===`\0${T}`)return L({pagesDir:r,matcherPath:l});if(i===`\0${A}`)return M({pagesDir:r,renderPath:n});if(i===`\0${D}`)return O({apiPath:s,appDir:e});if(i===`\0${C}`)return k()},buildStart(){let i=process.cwd(),u=E(e,i);$(v(u,`${e}/api`),i)},configureServer(i){let u=process.cwd(),h=()=>{let c=E(e,u);$(v(c,`${e}/api`),u)};i.watcher.on("add",c=>{c.startsWith(f(u,r))&&y(),c.includes(`${e}/api`)&&(R(),h())}),i.watcher.on("unlink",c=>{c.startsWith(f(u,r))&&y(),c.includes(`${e}/api`)&&(R(),h())}),i.watcher.on("change",c=>{c.includes(`${e}/api`)&&!c.endsWith("middleware.ts")&&h()})}},d={plugins:[ut(),g],ssr:{noExternal:["@devlusoft/devix"]},...t.envPrefix?{envPrefix:t.envPrefix}:{}};return lt(d,t.vite??{})}function N(t,{apiModule:e,renderModule:r,loaderTimeout:o}){t.all("/api/*",async n=>{try{return await e.handleApiRequest(n.req.url,n.req.raw)}catch(s){return console.error(s),n.json({error:"internal error"},500)}}),t.get("/_data/*",async n=>{try{let{pathname:s,search:l}=new URL(n.req.url,"http://localhost"),g=s.replace(/^\/_data/,"")+l,d=await r.runLoader(g,n.req.raw,{loaderTimeout:o});return n.json(d)}catch(s){return console.error(s),n.json({error:"internal error"},500)}})}import a from"picocolors";import{networkInterfaces as mt}from"node:os";import{createRequire as gt}from"node:module";function ft(t){let e=mt();for(let r of Object.values(e))for(let o of r??[])if(o.family==="IPv4"&&!o.internal)return`http://${o.address}:${t}/`;return null}function V(t){let r=gt(import.meta.url)("../../package.json").version,o=ft(t);console.log(),console.log(` ${a.bold(a.yellow("devix"))} ${a.dim(`v${r}`)}`),console.log(),console.log(` ${a.green("\u279C")} ${a.bold("Local:")} ${a.cyan(`http://localhost:${t}/`)}`),console.log(o?` ${a.green("\u279C")} ${a.bold("Network:")} ${a.cyan(o)}`:` ${a.green("\u279C")} ${a.bold("Network:")} ${a.dim("use --host to expose")}`),console.log()}async function W(t){let e=new Set;for(let[,r]of t.moduleGraph.idToModuleMap)r.id&&(r.id.endsWith(".css")||r.id.includes(".css?"))&&e.add(r.url);return[...e]}function X(t){if(typeof t=="number")return t;let e=t.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);if(!e)throw new Error(`[devix] Invalid duration: "${t}". Use a number (ms) or a string like "5s", "2m", "500ms".`);let r=parseFloat(e[1]);switch(e[2]){case"h":return r*36e5;case"m":return r*6e4;case"s":return r*1e3;default:return r}}import{loadEnv as ht}from"vite";function Y(t){let e=ht(t,process.cwd(),"");for(let[r,o]of Object.entries(e))process.env[r]===void 0&&(process.env[r]=o)}Y("development");var B="virtual:devix/render",wt="virtual:devix/api",m=(await import(`${process.cwd()}/devix.config.ts`)).default,G=Number(process.env.PORT)||m.port||3e3,Et=typeof m.host=="string"?m.host:m.host?"0.0.0.0":"localhost",p=await yt({...F(m),configFile:!1,appType:"custom",server:{middlewareMode:!0}}),z={render:async(...t)=>(await p.ssrLoadModule(B)).render(...t),runLoader:async(...t)=>(await p.ssrLoadModule(B)).runLoader(...t)},$t={handleApiRequest:async(...t)=>(await p.ssrLoadModule(wt)).handleApiRequest(...t)},S=new vt;N(S,{renderModule:z,apiModule:$t});S.get("*",async t=>{try{let{html:e,statusCode:r,headers:o}=await z.render(t.req.url,t.req.raw,{loaderTimeout:X(m.loaderTimeout??1e4)}),s=(await W(p)).map(i=>`<link rel="stylesheet" href="${i}">`).join(`
|
|
147
|
+
`),l=s?e.replace("</head>",`${s}
|
|
148
|
+
</head>`):e,g=await p.transformIndexHtml(t.req.url,`<!DOCTYPE html>${l}`),d=t.html(g,r);for(let[i,u]of Object.entries(o))d.headers.set(i,u);return d}catch(e){return p.ssrFixStacktrace(e),console.error(e),t.text("Internal Server Error",500)}});var Pt=Rt(S.fetch);xt(async(t,e)=>{await new Promise(r=>p.middlewares(t,e,r)),e.writableEnded||await Pt(t,e)}).listen(G,Et,()=>{V(G)});
|
|
512
149
|
//# sourceMappingURL=dev.js.map
|