@devlusoft/devix 0.1.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/README.md +6 -4
- package/dist/cli/build.js +39 -178
- package/dist/cli/build.js.map +4 -4
- package/dist/cli/dev.js +41 -253
- package/dist/cli/dev.js.map +4 -4
- package/dist/cli/generate.js +39 -281
- package/dist/cli/generate.js.map +4 -4
- package/dist/cli/index.js +44 -527
- package/dist/cli/index.js.map +4 -4
- package/dist/cli/start.js +1 -77
- package/dist/cli/start.js.map +4 -4
- package/dist/config.js +1 -16
- package/dist/config.js.map +2 -2
- package/dist/runtime/api-context.d.ts +3 -2
- package/dist/runtime/api-context.js +1 -17
- package/dist/runtime/api-context.js.map +3 -3
- 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.d.ts +19 -0
- package/dist/runtime/fetch.js +2 -0
- package/dist/runtime/fetch.js.map +7 -0
- package/dist/runtime/head.js +1 -68
- package/dist/runtime/head.js.map +2 -2
- package/dist/runtime/index.d.ts +7 -1
- package/dist/runtime/index.js +1 -299
- package/dist/runtime/index.js.map +4 -4
- 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.d.ts +1 -0
- package/dist/server/api-router.js +1 -63
- package/dist/server/api-router.js.map +3 -3
- package/dist/server/api.js +1 -122
- package/dist/server/api.js.map +3 -3
- 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 +3 -3
- 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.d.ts +12 -0
- package/dist/utils/cookies.js +2 -0
- package/dist/utils/cookies.js.map +7 -0
- package/dist/utils/duration.js +1 -21
- package/dist/utils/duration.js.map +2 -2
- package/dist/utils/env.d.ts +1 -0
- package/dist/utils/env.js +2 -0
- package/dist/utils/env.js.map +7 -0
- 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 +6 -0
- package/dist/utils/response.js +2 -0
- package/dist/utils/response.js.map +7 -0
- 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.d.ts +4 -0
- package/dist/vite/codegen/extract-methods.js +2 -0
- package/dist/vite/codegen/extract-methods.js.map +7 -0
- package/dist/vite/codegen/render.js +6 -12
- package/dist/vite/codegen/render.js.map +2 -2
- package/dist/vite/codegen/routes-dts.d.ts +10 -0
- package/dist/vite/codegen/routes-dts.js +23 -0
- package/dist/vite/codegen/routes-dts.js.map +7 -0
- package/dist/vite/codegen/scan-api.d.ts +2 -0
- package/dist/vite/codegen/scan-api.js +2 -0
- package/dist/vite/codegen/scan-api.js.map +7 -0
- package/dist/vite/codegen/write-routes-dts.d.ts +1 -0
- package/dist/vite/codegen/write-routes-dts.js +2 -0
- package/dist/vite/codegen/write-routes-dts.js.map +7 -0
- package/dist/vite/index.js +41 -119
- package/dist/vite/index.js.map +4 -4
- package/package.json +2 -2
package/dist/cli/generate.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
// src/vite/codegen/entry-client.ts
|
|
7
|
-
function generateEntryClient({ cssUrls }) {
|
|
8
|
-
const cssImports = cssUrls.map((u) => `import '${u}'`).join("\n");
|
|
9
|
-
return `
|
|
10
|
-
${cssImports}
|
|
1
|
+
var s=(t,e)=>()=>(t&&(e=t(t=0)),e);function M({cssUrls:t}){return`
|
|
2
|
+
${t.map(r=>`import '${r}'`).join(`
|
|
3
|
+
`)}
|
|
11
4
|
import "@vitejs/plugin-react/preamble"
|
|
12
5
|
import React from "react"
|
|
13
6
|
import {hydrateRoot, createRoot} from 'react-dom/client'
|
|
@@ -61,22 +54,12 @@ if (!window.__DEVIX__) {
|
|
|
61
54
|
)
|
|
62
55
|
}
|
|
63
56
|
}
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
var init_entry_client = __esm({
|
|
67
|
-
"src/vite/codegen/entry-client.ts"() {
|
|
68
|
-
"use strict";
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// src/vite/codegen/client-routes.ts
|
|
73
|
-
function generateClientRoutes({ pagesDir, matcherPath }) {
|
|
74
|
-
return `
|
|
57
|
+
`}var O=s(()=>{"use strict"});function L({pagesDir:t,matcherPath:e}){return`
|
|
75
58
|
import React from 'react'
|
|
76
|
-
import { createMatcher } from '${
|
|
77
|
-
const pageFiles = import.meta.glob(['/${
|
|
78
|
-
const layoutFiles = import.meta.glob('/${
|
|
79
|
-
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')
|
|
80
63
|
|
|
81
64
|
export const matchClientRoute = createMatcher(pageFiles, layoutFiles)
|
|
82
65
|
|
|
@@ -99,26 +82,16 @@ export function getDefaultErrorPage() {
|
|
|
99
82
|
)
|
|
100
83
|
}
|
|
101
84
|
}
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
var init_client_routes = __esm({
|
|
105
|
-
"src/vite/codegen/client-routes.ts"() {
|
|
106
|
-
"use strict";
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// src/vite/codegen/render.ts
|
|
111
|
-
function generateRender({ pagesDir, renderPath }) {
|
|
112
|
-
return `
|
|
113
|
-
import { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${renderPath}'
|
|
85
|
+
`}var I=s(()=>{"use strict"});function k({pagesDir:t,renderPath:e}){return`
|
|
86
|
+
import { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${e}'
|
|
114
87
|
|
|
115
|
-
const _pages = import.meta.glob(['/${
|
|
116
|
-
const _layouts = import.meta.glob('/${
|
|
88
|
+
const _pages = import.meta.glob(['/${t}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
|
|
89
|
+
const _layouts = import.meta.glob('/${t}/**/layout.tsx')
|
|
117
90
|
|
|
118
91
|
const _glob = {
|
|
119
92
|
pages: _pages,
|
|
120
93
|
layouts: _layouts,
|
|
121
|
-
pagesDir: '/${
|
|
94
|
+
pagesDir: '/${t}',
|
|
122
95
|
}
|
|
123
96
|
|
|
124
97
|
export function render(url, request, options) {
|
|
@@ -132,258 +105,43 @@ export function runLoader(url, request, options) {
|
|
|
132
105
|
export function getStaticRoutes() {
|
|
133
106
|
return _getStaticRoutes(_glob)
|
|
134
107
|
}
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
var init_render = __esm({
|
|
138
|
-
"src/vite/codegen/render.ts"() {
|
|
139
|
-
"use strict";
|
|
140
|
-
}
|
|
141
|
-
});
|
|
108
|
+
`}var U=s(()=>{"use strict"});function F({apiPath:t,appDir:e}){return`
|
|
109
|
+
import { handleApiRequest as _handleApiRequest } from '${t}'
|
|
142
110
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return `
|
|
146
|
-
import { handleApiRequest as _handleApiRequest } from '${apiPath}'
|
|
147
|
-
|
|
148
|
-
const _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])
|
|
149
|
-
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')
|
|
150
113
|
|
|
151
114
|
const _glob = {
|
|
152
115
|
routes: _routes,
|
|
153
116
|
middlewares: _middlewares,
|
|
154
|
-
apiDir: '/${
|
|
117
|
+
apiDir: '/${e}/api',
|
|
155
118
|
}
|
|
156
119
|
|
|
157
120
|
export function handleApiRequest(url, request) {
|
|
158
121
|
return _handleApiRequest(url, request, _glob)
|
|
159
122
|
}
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
var init_api = __esm({
|
|
163
|
-
"src/vite/codegen/api.ts"() {
|
|
164
|
-
"use strict";
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// src/utils/patterns.ts
|
|
169
|
-
var init_patterns = __esm({
|
|
170
|
-
"src/utils/patterns.ts"() {
|
|
171
|
-
"use strict";
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// src/server/pages-router.ts
|
|
176
|
-
function invalidatePagesCache() {
|
|
177
|
-
cache = null;
|
|
178
|
-
}
|
|
179
|
-
var cache;
|
|
180
|
-
var init_pages_router = __esm({
|
|
181
|
-
"src/server/pages-router.ts"() {
|
|
182
|
-
"use strict";
|
|
183
|
-
init_patterns();
|
|
184
|
-
cache = null;
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
// src/server/api-router.ts
|
|
189
|
-
function invalidateApiCache() {
|
|
190
|
-
cache2 = null;
|
|
191
|
-
}
|
|
192
|
-
var cache2;
|
|
193
|
-
var init_api_router = __esm({
|
|
194
|
-
"src/server/api-router.ts"() {
|
|
195
|
-
"use strict";
|
|
196
|
-
init_patterns();
|
|
197
|
-
cache2 = null;
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// src/vite/codegen/context.ts
|
|
202
|
-
function generateContext() {
|
|
203
|
-
return `
|
|
123
|
+
`}var H=s(()=>{"use strict"});function m(t){return t.replace(/\.(tsx|ts|jsx|js)$/,"").replace(/\(.*?\)\//g,"").replace(/^index$|\/index$/,"").replace(/\[([^\]]+)]/g,":$1")||"/"}var f=s(()=>{"use strict"});function h(){ct=null}var ct,j=s(()=>{"use strict";f();ct=null});function q(t,e){let r=t.slice(e.length+1).replace(/\\/g,"/"),i=m(r);return i==="/"?"/api":`/api/${i}`.replace("/api//","/api/")}function x(){lt=null}var lt,y=s(()=>{"use strict";f();lt=null});function N(){return`
|
|
204
124
|
export {RouterContext} from '@devlusoft/devix/runtime/context'
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const matcherPath = resolve(__dirname, "../runtime/client-router.js").replace(/\\/g, "/");
|
|
225
|
-
const virtualPlugin = {
|
|
226
|
-
name: "devix",
|
|
227
|
-
enforce: "pre",
|
|
228
|
-
resolveId(id) {
|
|
229
|
-
if (id === VIRTUAL_ENTRY_CLIENT) return `\0${VIRTUAL_ENTRY_CLIENT}`;
|
|
230
|
-
if (id === VIRTUAL_CLIENT_ROUTES) return `\0${VIRTUAL_CLIENT_ROUTES}`;
|
|
231
|
-
if (id === VIRTUAL_RENDER) return `\0${VIRTUAL_RENDER}`;
|
|
232
|
-
if (id === VIRTUAL_API) return `\0${VIRTUAL_API}`;
|
|
233
|
-
if (id === VIRTUAL_CONTEXT) return `\0${VIRTUAL_CONTEXT}`;
|
|
234
|
-
},
|
|
235
|
-
load(id) {
|
|
236
|
-
if (id === `\0${VIRTUAL_ENTRY_CLIENT}`)
|
|
237
|
-
return generateEntryClient({ cssUrls });
|
|
238
|
-
if (id === `\0${VIRTUAL_CLIENT_ROUTES}`)
|
|
239
|
-
return generateClientRoutes({ pagesDir, matcherPath });
|
|
240
|
-
if (id === `\0${VIRTUAL_RENDER}`)
|
|
241
|
-
return generateRender({ pagesDir, renderPath });
|
|
242
|
-
if (id === `\0${VIRTUAL_API}`)
|
|
243
|
-
return generateApi({ apiPath, appDir });
|
|
244
|
-
if (id === `\0${VIRTUAL_CONTEXT}`)
|
|
245
|
-
return generateContext();
|
|
246
|
-
},
|
|
247
|
-
configureServer(server) {
|
|
248
|
-
server.watcher.on("add", (file) => {
|
|
249
|
-
if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache();
|
|
250
|
-
if (file.includes(`${appDir}/api`)) invalidateApiCache();
|
|
251
|
-
});
|
|
252
|
-
server.watcher.on("unlink", (file) => {
|
|
253
|
-
if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache();
|
|
254
|
-
if (file.includes(`${appDir}/api`)) invalidateApiCache();
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
const base = {
|
|
259
|
-
plugins: [react(), virtualPlugin],
|
|
260
|
-
ssr: { noExternal: ["@devlusoft/devix"] },
|
|
261
|
-
...config2.envPrefix ? { envPrefix: config2.envPrefix } : {}
|
|
262
|
-
};
|
|
263
|
-
return mergeConfig(base, config2.vite ?? {});
|
|
264
|
-
}
|
|
265
|
-
var __dirname, VIRTUAL_ENTRY_CLIENT, VIRTUAL_CLIENT_ROUTES, VIRTUAL_RENDER, VIRTUAL_API, VIRTUAL_CONTEXT;
|
|
266
|
-
var init_vite = __esm({
|
|
267
|
-
"src/vite/index.ts"() {
|
|
268
|
-
"use strict";
|
|
269
|
-
init_entry_client();
|
|
270
|
-
init_client_routes();
|
|
271
|
-
init_render();
|
|
272
|
-
init_api();
|
|
273
|
-
init_pages_router();
|
|
274
|
-
init_api_router();
|
|
275
|
-
init_context();
|
|
276
|
-
__dirname = dirname(fileURLToPath(import.meta.url));
|
|
277
|
-
VIRTUAL_ENTRY_CLIENT = "virtual:devix/entry-client";
|
|
278
|
-
VIRTUAL_CLIENT_ROUTES = "virtual:devix/client-routes";
|
|
279
|
-
VIRTUAL_RENDER = "virtual:devix/render";
|
|
280
|
-
VIRTUAL_API = "virtual:devix/api";
|
|
281
|
-
VIRTUAL_CONTEXT = "virtual:devix/context";
|
|
282
|
-
}
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
// src/utils/duration.ts
|
|
286
|
-
function parseDuration(value) {
|
|
287
|
-
if (typeof value === "number") return value;
|
|
288
|
-
const match = value.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);
|
|
289
|
-
if (!match) throw new Error(`[devix] Invalid duration: "${value}". Use a number (ms) or a string like "5s", "2m", "500ms".`);
|
|
290
|
-
const n = parseFloat(match[1]);
|
|
291
|
-
switch (match[2]) {
|
|
292
|
-
case "h":
|
|
293
|
-
return n * 36e5;
|
|
294
|
-
case "m":
|
|
295
|
-
return n * 6e4;
|
|
296
|
-
case "s":
|
|
297
|
-
return n * 1e3;
|
|
298
|
-
case "ms":
|
|
299
|
-
default:
|
|
300
|
-
return n;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
var init_duration = __esm({
|
|
304
|
-
"src/utils/duration.ts"() {
|
|
305
|
-
"use strict";
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// src/cli/build.ts
|
|
310
|
-
var build_exports = {};
|
|
311
|
-
import { writeFileSync } from "node:fs";
|
|
312
|
-
import { resolve as resolve2 } from "node:path";
|
|
313
|
-
import { build } from "vite";
|
|
314
|
-
var config, baseConfig, runtimeConfig;
|
|
315
|
-
var init_build = __esm({
|
|
316
|
-
async "src/cli/build.ts"() {
|
|
317
|
-
"use strict";
|
|
318
|
-
init_vite();
|
|
319
|
-
init_duration();
|
|
320
|
-
config = (await import(`${process.cwd()}/devix.config.ts`)).default;
|
|
321
|
-
baseConfig = devix(config);
|
|
322
|
-
await build({
|
|
323
|
-
...baseConfig,
|
|
324
|
-
configFile: false,
|
|
325
|
-
build: {
|
|
326
|
-
outDir: "dist/client",
|
|
327
|
-
manifest: true,
|
|
328
|
-
rolldownOptions: {
|
|
329
|
-
input: "virtual:devix/entry-client"
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
await build({
|
|
334
|
-
...baseConfig,
|
|
335
|
-
configFile: false,
|
|
336
|
-
build: {
|
|
337
|
-
ssr: true,
|
|
338
|
-
outDir: "dist/server",
|
|
339
|
-
rolldownOptions: {
|
|
340
|
-
input: {
|
|
341
|
-
render: "virtual:devix/render",
|
|
342
|
-
api: "virtual:devix/api"
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
runtimeConfig = {
|
|
348
|
-
port: config.port ?? 3e3,
|
|
349
|
-
host: config.host ?? false,
|
|
350
|
-
loaderTimeout: parseDuration(config.loaderTimeout ?? 1e4),
|
|
351
|
-
output: config.output ?? "server"
|
|
352
|
-
};
|
|
353
|
-
writeFileSync(
|
|
354
|
-
resolve2(process.cwd(), "dist/devix.config.json"),
|
|
355
|
-
JSON.stringify(runtimeConfig, null, 2),
|
|
356
|
-
"utf-8"
|
|
357
|
-
);
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
// src/cli/generate.ts
|
|
362
|
-
import { readFileSync, mkdirSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
363
|
-
import { resolve as resolve3, join } from "node:path";
|
|
364
|
-
var userConfig = (await import(`${process.cwd()}/devix.config.ts`)).default;
|
|
365
|
-
if (userConfig.output !== "static") {
|
|
366
|
-
console.warn('[devix] Tip: set output: "static" in devix.config.ts to skip the SSR server at runtime.');
|
|
367
|
-
}
|
|
368
|
-
await init_build().then(() => build_exports);
|
|
369
|
-
var t = Date.now();
|
|
370
|
-
var renderModule = await import(resolve3(process.cwd(), "dist/server/render.js") + `?t=${t}`);
|
|
371
|
-
var manifest = JSON.parse(
|
|
372
|
-
readFileSync(resolve3(process.cwd(), "dist/client/.vite/manifest.json"), "utf-8")
|
|
373
|
-
);
|
|
374
|
-
var urls = await renderModule.getStaticRoutes();
|
|
375
|
-
console.log(`[devix] Generating ${urls.length} static page${urls.length === 1 ? "" : "s"}...`);
|
|
376
|
-
for (const url of urls) {
|
|
377
|
-
const fullUrl = `http://localhost${url}`;
|
|
378
|
-
const { html, statusCode } = await renderModule.render(fullUrl, new Request(fullUrl), { manifest });
|
|
379
|
-
if (statusCode !== 200) {
|
|
380
|
-
console.warn(`[devix] Skipping ${url} \u2014 status ${statusCode}`);
|
|
381
|
-
continue;
|
|
125
|
+
`}var W=s(()=>{"use strict"});function pt(t){return t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/\/\/.*$/gm,"")}function V(t){let e=new Set;for(let r of pt(t).matchAll(ut))e.add(r[1]);return[...e]}var ut,G=s(()=>{"use strict";ut=/export\s+(?:const|async\s+function|function)\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\b/g});function dt(t,e){return"_api_"+t.slice(`${e}/`.length).replace(/\.(ts|tsx)$/,"").replace(/[^a-zA-Z0-9]/g,"_")}function J(t,e,r){return{filePath:t,urlPattern:q(t,e),identifier:dt(t,e),methods:r}}function R(t,e){if(t.length===0)return`// auto-generado por devix \u2014 no editar
|
|
126
|
+
declare module '@devlusoft/devix' {
|
|
127
|
+
interface ApiRoutes {}
|
|
128
|
+
}
|
|
129
|
+
`;let r=t.map(o=>{let c="../"+o.filePath.replace(/\.(ts|tsx)$/,"");return`import type * as ${o.identifier} from '${c}'`}).join(`
|
|
130
|
+
`),i=t.flatMap(o=>o.methods.map(c=>` '${c} ${o.urlPattern}': InferRoute<(typeof ${o.identifier})['${c}']>`)).join(`
|
|
131
|
+
`);return`// auto-generado por devix \u2014 no editar
|
|
132
|
+
${r}
|
|
133
|
+
|
|
134
|
+
type JsonResponse<T> = Response & { readonly __body: T }
|
|
135
|
+
type InferRoute<T> = T extends (...args: any[]) => any
|
|
136
|
+
? Awaited<ReturnType<T>> extends JsonResponse<infer U>
|
|
137
|
+
? U
|
|
138
|
+
: Exclude<Awaited<ReturnType<T>>, Response | null | void>
|
|
139
|
+
: never
|
|
140
|
+
|
|
141
|
+
declare module '@devlusoft/devix' {
|
|
142
|
+
interface ApiRoutes {
|
|
143
|
+
${i}
|
|
382
144
|
}
|
|
383
|
-
const outPath = url === "/" ? join(process.cwd(), "dist/client/index.html") : join(process.cwd(), "dist/client", url, "index.html");
|
|
384
|
-
mkdirSync(join(outPath, ".."), { recursive: true });
|
|
385
|
-
writeFileSync2(outPath, `<!DOCTYPE html>${html}`, "utf-8");
|
|
386
|
-
console.log(` \u2713 ${url}`);
|
|
387
145
|
}
|
|
388
|
-
console.log("[devix] Generation complete.");
|
|
146
|
+
`}var v=s(()=>{"use strict";y()});import{readFileSync as gt,readdirSync as mt,statSync as ft}from"node:fs";import{join as w,relative as ht}from"node:path";function X(t,e){let r=[];for(let i of mt(t)){let o=w(t,i);ft(o).isDirectory()?r.push(...X(o,e)):/\.(ts|tsx)$/.test(i)&&r.push(ht(e,o).replace(/\\/g,"/"))}return r}function E(t,e){let r=w(e,t,"api"),i;try{i=X(r,e)}catch{return[]}return i.filter(o=>!o.endsWith("middleware.ts")&&!o.endsWith("middleware.tsx")).flatMap(o=>{try{let c=gt(w(e,o),"utf-8"),d=V(c);return d.length===0?[]:[J(o,`${t}/api`,d)]}catch{return[]}})}var Y=s(()=>{"use strict";G();v()});import{mkdirSync as xt,readFileSync as yt,writeFileSync as Rt,existsSync as vt}from"node:fs";import{join as z}from"node:path";function P(t,e){let r=z(e,".devix"),i=z(r,"routes.d.ts");return xt(r,{recursive:!0}),vt(i)&&yt(i,"utf-8")===t?!1:(Rt(i,t,"utf-8"),!0)}var B=s(()=>{"use strict"});import{mergeConfig as wt}from"vite";import Et from"@vitejs/plugin-react";import{fileURLToPath as Pt}from"node:url";import{dirname as $t,resolve as u}from"node:path";function Z(t){let e=t.appDir??"app",r=`${e}/pages`,i=(t.css??[]).map(n=>n.startsWith("/")?n:`/${n.replace(/^\.\//,"")}`),o=u($,"../server/render.js").replace(/\\/g,"/"),c=u($,"../server/api.js").replace(/\\/g,"/"),d=u($,"../runtime/client-router.js").replace(/\\/g,"/"),st={name:"devix",enforce:"pre",resolveId(n){if(n===_)return`\0${_}`;if(n===D)return`\0${D}`;if(n===T)return`\0${T}`;if(n===A)return`\0${A}`;if(n===C)return`\0${C}`},load(n){if(n===`\0${_}`)return M({cssUrls:i});if(n===`\0${D}`)return L({pagesDir:r,matcherPath:d});if(n===`\0${T}`)return k({pagesDir:r,renderPath:o});if(n===`\0${A}`)return F({apiPath:c,appDir:e});if(n===`\0${C}`)return N()},buildStart(){let n=process.cwd(),l=E(e,n);P(R(l,`${e}/api`),n)},configureServer(n){let l=process.cwd(),g=()=>{let a=E(e,l);P(R(a,`${e}/api`),l)};n.watcher.on("add",a=>{a.startsWith(u(l,r))&&h(),a.includes(`${e}/api`)&&(x(),g())}),n.watcher.on("unlink",a=>{a.startsWith(u(l,r))&&h(),a.includes(`${e}/api`)&&(x(),g())}),n.watcher.on("change",a=>{a.includes(`${e}/api`)&&!a.endsWith("middleware.ts")&&g()})}},at={plugins:[Et(),st],ssr:{noExternal:["@devlusoft/devix"]},...t.envPrefix?{envPrefix:t.envPrefix}:{}};return wt(at,t.vite??{})}var $,_,D,T,A,C,K=s(()=>{"use strict";O();I();U();H();j();y();W();Y();v();B();$=$t(Pt(import.meta.url)),_="virtual:devix/entry-client",D="virtual:devix/client-routes",T="virtual:devix/render",A="virtual:devix/api",C="virtual:devix/context"});function Q(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}}var tt=s(()=>{"use strict"});var At={};import{writeFileSync as _t}from"node:fs";import{resolve as Dt}from"node:path";import{build as et}from"vite";var p,rt,Tt,nt=s(async()=>{"use strict";K();tt();p=(await import(`${process.cwd()}/devix.config.ts`)).default,rt=Z(p);await et({...rt,configFile:!1,build:{outDir:"dist/client",manifest:!0,rolldownOptions:{input:"virtual:devix/entry-client"}}});await et({...rt,configFile:!1,build:{ssr:!0,outDir:"dist/server",rolldownOptions:{input:{render:"virtual:devix/render",api:"virtual:devix/api"}}}});Tt={port:p.port??3e3,host:p.host??!1,loaderTimeout:Q(p.loaderTimeout??1e4),output:p.output??"server"};_t(Dt(process.cwd(),"dist/devix.config.json"),JSON.stringify(Tt,null,2),"utf-8")});import{readFileSync as Ct,mkdirSync as St,writeFileSync as bt}from"node:fs";import{resolve as ot,join as S}from"node:path";var Mt=(await import(`${process.cwd()}/devix.config.ts`)).default;Mt.output!=="static"&&console.warn('[devix] Tip: set output: "static" in devix.config.ts to skip the SSR server at runtime.');await nt().then(()=>At);var Ot=Date.now(),it=await import(ot(process.cwd(),"dist/server/render.js")+`?t=${Ot}`),Lt=JSON.parse(Ct(ot(process.cwd(),"dist/client/.vite/manifest.json"),"utf-8")),b=await it.getStaticRoutes();console.log(`[devix] Generating ${b.length} static page${b.length===1?"":"s"}...`);for(let t of b){let e=`http://localhost${t}`,{html:r,statusCode:i}=await it.render(e,new Request(e),{manifest:Lt});if(i!==200){console.warn(`[devix] Skipping ${t} \u2014 status ${i}`);continue}let o=t==="/"?S(process.cwd(),"dist/client/index.html"):S(process.cwd(),"dist/client",t,"index.html");St(S(o,".."),{recursive:!0}),bt(o,`<!DOCTYPE html>${r}`,"utf-8"),console.log(` \u2713 ${t}`)}console.log("[devix] Generation complete.");
|
|
389
147
|
//# sourceMappingURL=generate.js.map
|
package/dist/cli/generate.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/vite/codegen/entry-client.ts", "../../src/vite/codegen/client-routes.ts", "../../src/vite/codegen/render.ts", "../../src/vite/codegen/api.ts", "../../src/utils/patterns.ts", "../../src/server/pages-router.ts", "../../src/server/api-router.ts", "../../src/vite/codegen/context.ts", "../../src/vite/index.ts", "../../src/utils/duration.ts", "../../src/cli/build.ts", "../../src/cli/generate.ts"],
|
|
4
|
-
"sourcesContent": ["interface EntryClientOptions {\n cssUrls: string[]\n}\n\nexport function generateEntryClient({cssUrls}: EntryClientOptions): string {\n const cssImports = cssUrls.map(u => `import '${u}'`).join('\\n')\n\n return `\n${cssImports}\nimport \"@vitejs/plugin-react/preamble\"\nimport React from \"react\"\nimport {hydrateRoot, createRoot} from 'react-dom/client'\nimport {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'\nimport {RouterProvider} from '@devlusoft/devix'\n\nconst root = document.getElementById('devix-root')\n\nif (!window.__DEVIX__) {\n const ErrorPage = getDefaultErrorPage()\n createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))\n} else {\n const {metadata, viewport, clientEntry} = window.__DEVIX__\n const loaderData = window.__LOADER_DATA__\n const layoutsData = window.__LAYOUTS_DATA__ ?? []\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (matched) {\n const [pageMod, ...layoutMods] = await Promise.all([\n matched.load(),\n ...matched.loadLayouts.map(l => l()),\n ])\n hydrateRoot(\n root,\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialMeta: metadata,\n initialViewport: viewport,\n })\n )\n } else {\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialLayouts: [],\n initialLayoutsData: [],\n initialMeta: null,\n initialError: {statusCode: 404, message: 'Not found'},\n initialErrorPage: ErrorPage,\n })\n )\n }\n}\n`\n}", "interface ClientRoutesOptions {\n pagesDir: string\n matcherPath: string\n}\n\nexport function generateClientRoutes({pagesDir, matcherPath}: ClientRoutesOptions) {\n return `\nimport React from 'react'\nimport { createMatcher } from '${matcherPath}'\nconst pageFiles = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst layoutFiles = import.meta.glob('/${pagesDir}/**/layout.tsx')\nconst errorFiles = import.meta.glob('/${pagesDir}/**/error.tsx')\n\nexport const matchClientRoute = createMatcher(pageFiles, layoutFiles)\n\nexport async function loadErrorPage() {\n const key = Object.keys(errorFiles)[0]\n if (!key) return null\n const mod = await errorFiles[key]()\n return mod?.default ?? null\n}\n\nexport function getDefaultErrorPage() {\n return function DefaultError({ statusCode, message }) {\n return React.createElement('main', {\n style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column', \n alignItems: 'center', justifyContent: 'center', gap: '8px',\n fontFamily: 'system-ui, sans-serif' }\n },\n React.createElement('h1', {style: {fontSize: '4rem', fontWeight: 700}}, statusCode),\n React.createElement('p', {style: {color: '#666'}}, message ?? 'An unexpected error occurred'),\n )\n }\n}\n`\n}", "interface RenderOptions {\n pagesDir: string\n renderPath: string\n}\n\nexport function generateRender({pagesDir, renderPath}: RenderOptions): string {\n return `\nimport { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${renderPath}'\n\nconst _pages = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst _layouts = import.meta.glob('/${pagesDir}/**/layout.tsx')\n\nconst _glob = {\n pages: _pages,\n layouts: _layouts,\n pagesDir: '/${pagesDir}',\n}\n\nexport function render(url, request, options) {\n return _render(url, request, _glob, options)\n}\n\nexport function runLoader(url, request, options) {\n return _runLoader(url, request, _glob, options)\n}\n\nexport function getStaticRoutes() {\n return _getStaticRoutes(_glob)\n}\n`\n}\n", "interface ApiOptions {\n apiPath: string\n appDir: string\n}\n\nexport function generateApi({apiPath, appDir}: ApiOptions): string {\n return `\nimport { handleApiRequest as _handleApiRequest } from '${apiPath}'\n\nconst _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])\nconst _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')\n\nconst _glob = {\n routes: _routes,\n middlewares: _middlewares,\n apiDir: '/${appDir}/api',\n}\n\nexport function handleApiRequest(url, request) {\n return _handleApiRequest(url, request, _glob)\n}\n`\n}\n", "export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {routePattern} from \"../utils/patterns\";\n\nexport interface ApiRoute {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface ApiMiddleware {\n dir: string\n key: string\n}\n\nexport interface ApiResult {\n routes: ApiRoute[]\n middlewares: ApiMiddleware[]\n}\n\nfunction keyToRoutePattern(key: string, apiDir: string): string {\n const rel = key.slice(apiDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === '/' ? '/api' : `/api/${pattern}`.replace('/api//', '/api/')\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: ApiResult | null = null\n\nexport function invalidateApiCache() {\n cache = null\n}\n\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\n if (cache) return cache\n\n const routes: ApiRoute[] = []\n const middlewares: ApiMiddleware[] = []\n\n for (const key of middlewareKeys) {\n middlewares.push({dir: keyToDir(key), key})\n }\n\n for (const key of routeKeys) {\n const pattern = keyToRoutePattern(key, apiDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n routes.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n routes.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {routes, middlewares}\n return cache\n}\n\nexport function collectMiddlewareChain(routeKey: string, middlewares: ApiMiddleware[]): ApiMiddleware[] {\n const routeDir = keyToDir(routeKey)\n\n return middlewares\n .filter(mw => routeDir.startsWith(mw.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchRoute(\n pathname: string,\n routes: ApiRoute[]\n): {route: ApiRoute; params: Record<string, string>} | null {\n for (const route of routes) {\n const match = pathname.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {route, params}\n }\n }\n return null\n}\n", "export function generateContext(): string {\n return `\nexport {RouterContext} from '@devlusoft/devix/runtime/context'\n`\n}", "import {UserConfig, Plugin, mergeConfig} from 'vite'\nimport type {DevixConfig} from '../config'\nimport react from '@vitejs/plugin-react'\nimport {fileURLToPath} from 'node:url'\nimport {dirname, resolve} from 'node:path'\nimport {generateEntryClient} from './codegen/entry-client'\nimport {generateClientRoutes} from './codegen/client-routes'\nimport {generateRender} from './codegen/render'\nimport {generateApi} from './codegen/api'\nimport {invalidatePagesCache} from \"../server/pages-router\";\nimport {invalidateApiCache} from \"../server/api-router\";\nimport {generateContext} from \"./codegen/context\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nconst VIRTUAL_ENTRY_CLIENT = 'virtual:devix/entry-client'\nconst VIRTUAL_CLIENT_ROUTES = 'virtual:devix/client-routes'\nconst VIRTUAL_RENDER = 'virtual:devix/render'\nconst VIRTUAL_API = 'virtual:devix/api'\nconst VIRTUAL_CONTEXT = 'virtual:devix/context'\n\nexport function devix(config: DevixConfig): UserConfig {\n const appDir = config.appDir ?? 'app'\n const pagesDir = `${appDir}/pages`\n const cssUrls = (config.css ?? []).map(u => u.startsWith('/') ? u : `/${u.replace(/^\\.\\//, '')}`)\n\n const renderPath = resolve(__dirname, '../server/render.js').replace(/\\\\/g, '/')\n const apiPath = resolve(__dirname, '../server/api.js').replace(/\\\\/g, '/')\n const matcherPath = resolve(__dirname, '../runtime/client-router.js').replace(/\\\\/g, '/')\n\n const virtualPlugin: Plugin = {\n name: 'devix',\n enforce: 'pre',\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_CLIENT) return `\\0${VIRTUAL_ENTRY_CLIENT}`\n if (id === VIRTUAL_CLIENT_ROUTES) return `\\0${VIRTUAL_CLIENT_ROUTES}`\n if (id === VIRTUAL_RENDER) return `\\0${VIRTUAL_RENDER}`\n if (id === VIRTUAL_API) return `\\0${VIRTUAL_API}`\n if (id === VIRTUAL_CONTEXT) return `\\0${VIRTUAL_CONTEXT}`\n },\n\n load(id) {\n if (id === `\\0${VIRTUAL_ENTRY_CLIENT}`)\n return generateEntryClient({cssUrls})\n if (id === `\\0${VIRTUAL_CLIENT_ROUTES}`)\n return generateClientRoutes({pagesDir, matcherPath})\n if (id === `\\0${VIRTUAL_RENDER}`)\n return generateRender({pagesDir, renderPath})\n if (id === `\\0${VIRTUAL_API}`)\n return generateApi({apiPath, appDir})\n if (id === `\\0${VIRTUAL_CONTEXT}`)\n return generateContext()\n },\n\n configureServer(server) {\n server.watcher.on('add', (file) => {\n if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) invalidateApiCache()\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(resolve(process.cwd(), pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) invalidateApiCache()\n })\n },\n }\n\n const base: UserConfig = {\n plugins: [react(), virtualPlugin],\n ssr: {noExternal: ['@devlusoft/devix']},\n ...(config.envPrefix ? {envPrefix: config.envPrefix} : {}),\n }\n\n return mergeConfig(base, config.vite ?? {})\n}", "export function parseDuration(value: number | string): number {\n if (typeof value === 'number') return value\n const match = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)?$/)\n if (!match) throw new Error(`[devix] Invalid duration: \"${value}\". Use a number (ms) or a string like \"5s\", \"2m\", \"500ms\".`)\n const n = parseFloat(match[1])\n switch (match[2]) {\n case 'h': return n * 3_600_000\n case 'm': return n * 60_000\n case 's': return n * 1_000\n case 'ms':\n default: return n\n }\n}\n", "import {writeFileSync} from 'node:fs'\nimport {resolve} from 'node:path'\nimport {build} from 'vite'\nimport type {DevixConfig} from '../config'\nimport {devix} from '../vite'\nimport {parseDuration} from '../utils/duration'\n\nconst config: DevixConfig = (await import(`${process.cwd()}/devix.config.ts`)).default\nconst baseConfig = devix(config)\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n outDir: 'dist/client',\n manifest: true,\n rolldownOptions: {\n input: 'virtual:devix/entry-client',\n },\n },\n})\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n ssr: true,\n outDir: 'dist/server',\n rolldownOptions: {\n input: {\n render: 'virtual:devix/render',\n api: 'virtual:devix/api',\n },\n },\n },\n})\n\nconst runtimeConfig = {\n port: config.port ?? 3000,\n host: config.host ?? false,\n loaderTimeout: parseDuration(config.loaderTimeout ?? 10_000),\n output: config.output ?? 'server',\n}\n\nwriteFileSync(\n resolve(process.cwd(), 'dist/devix.config.json'),\n JSON.stringify(runtimeConfig, null, 2),\n 'utf-8'\n)\n\n\nexport {}", "import {readFileSync, mkdirSync, writeFileSync} from 'node:fs'\nimport {resolve, join} from 'node:path'\nimport type {Manifest} from 'vite'\nimport type {DevixConfig} from '../config'\n\nconst userConfig: DevixConfig = (await import(`${process.cwd()}/devix.config.ts`)).default\nif (userConfig.output !== 'static') {\n console.warn('[devix] Tip: set output: \"static\" in devix.config.ts to skip the SSR server at runtime.')\n}\n\nawait import('./build.js')\n\nconst t = Date.now()\nconst renderModule = await import(resolve(process.cwd(), 'dist/server/render.js') + `?t=${t}`)\n\nconst manifest: Manifest = JSON.parse(\n readFileSync(resolve(process.cwd(), 'dist/client/.vite/manifest.json'), 'utf-8')\n)\n\nconst urls: string[] = await renderModule.getStaticRoutes()\n\nconsole.log(`[devix] Generating ${urls.length} static page${urls.length === 1 ? '' : 's'}...`)\n\nfor (const url of urls) {\n const fullUrl = `http://localhost${url}`\n const {html, statusCode} = await renderModule.render(fullUrl, new Request(fullUrl), {manifest})\n\n if (statusCode !== 200) {\n console.warn(`[devix] Skipping ${url} \u2014 status ${statusCode}`)\n continue\n }\n\n const outPath = url === '/'\n ? join(process.cwd(), 'dist/client/index.html')\n : join(process.cwd(), 'dist/client', url, 'index.html')\n\n mkdirSync(join(outPath, '..'), {recursive: true})\n writeFileSync(outPath, `<!DOCTYPE html>${html}`, 'utf-8')\n console.log(` \u2713 ${url}`)\n}\n\nconsole.log('[devix] Generation complete.')\n\nexport {}\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["cache", "config", "resolve", "writeFileSync", "resolve"]
|
|
3
|
+
"sources": ["../../src/vite/codegen/entry-client.ts", "../../src/vite/codegen/client-routes.ts", "../../src/vite/codegen/render.ts", "../../src/vite/codegen/api.ts", "../../src/utils/patterns.ts", "../../src/server/pages-router.ts", "../../src/server/api-router.ts", "../../src/vite/codegen/context.ts", "../../src/vite/codegen/extract-methods.ts", "../../src/vite/codegen/routes-dts.ts", "../../src/vite/codegen/scan-api.ts", "../../src/vite/codegen/write-routes-dts.ts", "../../src/vite/index.ts", "../../src/utils/duration.ts", "../../src/cli/build.ts", "../../src/cli/generate.ts"],
|
|
4
|
+
"sourcesContent": ["interface EntryClientOptions {\n cssUrls: string[]\n}\n\nexport function generateEntryClient({cssUrls}: EntryClientOptions): string {\n const cssImports = cssUrls.map(u => `import '${u}'`).join('\\n')\n\n return `\n${cssImports}\nimport \"@vitejs/plugin-react/preamble\"\nimport React from \"react\"\nimport {hydrateRoot, createRoot} from 'react-dom/client'\nimport {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'\nimport {RouterProvider} from '@devlusoft/devix'\n\nconst root = document.getElementById('devix-root')\n\nif (!window.__DEVIX__) {\n const ErrorPage = getDefaultErrorPage()\n createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))\n} else {\n const {metadata, viewport, clientEntry} = window.__DEVIX__\n const loaderData = window.__LOADER_DATA__\n const layoutsData = window.__LAYOUTS_DATA__ ?? []\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (matched) {\n const [pageMod, ...layoutMods] = await Promise.all([\n matched.load(),\n ...matched.loadLayouts.map(l => l()),\n ])\n hydrateRoot(\n root,\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialMeta: metadata,\n initialViewport: viewport,\n })\n )\n } else {\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialLayouts: [],\n initialLayoutsData: [],\n initialMeta: null,\n initialError: {statusCode: 404, message: 'Not found'},\n initialErrorPage: ErrorPage,\n })\n )\n }\n}\n`\n}", "interface ClientRoutesOptions {\n pagesDir: string\n matcherPath: string\n}\n\nexport function generateClientRoutes({pagesDir, matcherPath}: ClientRoutesOptions) {\n return `\nimport React from 'react'\nimport { createMatcher } from '${matcherPath}'\nconst pageFiles = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst layoutFiles = import.meta.glob('/${pagesDir}/**/layout.tsx')\nconst errorFiles = import.meta.glob('/${pagesDir}/**/error.tsx')\n\nexport const matchClientRoute = createMatcher(pageFiles, layoutFiles)\n\nexport async function loadErrorPage() {\n const key = Object.keys(errorFiles)[0]\n if (!key) return null\n const mod = await errorFiles[key]()\n return mod?.default ?? null\n}\n\nexport function getDefaultErrorPage() {\n return function DefaultError({ statusCode, message }) {\n return React.createElement('main', {\n style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column', \n alignItems: 'center', justifyContent: 'center', gap: '8px',\n fontFamily: 'system-ui, sans-serif' }\n },\n React.createElement('h1', {style: {fontSize: '4rem', fontWeight: 700}}, statusCode),\n React.createElement('p', {style: {color: '#666'}}, message ?? 'An unexpected error occurred'),\n )\n }\n}\n`\n}", "interface RenderOptions {\n pagesDir: string\n renderPath: string\n}\n\nexport function generateRender({pagesDir, renderPath}: RenderOptions): string {\n return `\nimport { render as _render, runLoader as _runLoader, getStaticRoutes as _getStaticRoutes } from '${renderPath}'\n\nconst _pages = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst _layouts = import.meta.glob('/${pagesDir}/**/layout.tsx')\n\nconst _glob = {\n pages: _pages,\n layouts: _layouts,\n pagesDir: '/${pagesDir}',\n}\n\nexport function render(url, request, options) {\n return _render(url, request, _glob, options)\n}\n\nexport function runLoader(url, request, options) {\n return _runLoader(url, request, _glob, options)\n}\n\nexport function getStaticRoutes() {\n return _getStaticRoutes(_glob)\n}\n`\n}\n", "interface ApiOptions {\n apiPath: string\n appDir: string\n}\n\nexport function generateApi({apiPath, appDir}: ApiOptions): string {\n return `\nimport { handleApiRequest as _handleApiRequest } from '${apiPath}'\n\nconst _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])\nconst _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')\n\nconst _glob = {\n routes: _routes,\n middlewares: _middlewares,\n apiDir: '/${appDir}/api',\n}\n\nexport function handleApiRequest(url, request) {\n return _handleApiRequest(url, request, _glob)\n}\n`\n}\n", "export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {routePattern} from \"../utils/patterns\";\n\nexport interface ApiRoute {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface ApiMiddleware {\n dir: string\n key: string\n}\n\nexport interface ApiResult {\n routes: ApiRoute[]\n middlewares: ApiMiddleware[]\n}\n\nexport function keyToRoutePattern(key: string, apiDir: string): string {\n const rel = key.slice(apiDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === '/' ? '/api' : `/api/${pattern}`.replace('/api//', '/api/')\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: ApiResult | null = null\n\nexport function invalidateApiCache() {\n cache = null\n}\n\nexport function buildRoutes(routeKeys: string[], middlewareKeys: string[], apiDir: string): ApiResult {\n if (cache) return cache\n\n const routes: ApiRoute[] = []\n const middlewares: ApiMiddleware[] = []\n\n for (const key of middlewareKeys) {\n middlewares.push({dir: keyToDir(key), key})\n }\n\n for (const key of routeKeys) {\n const pattern = keyToRoutePattern(key, apiDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n routes.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n routes.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {routes, middlewares}\n return cache\n}\n\nexport function collectMiddlewareChain(routeKey: string, middlewares: ApiMiddleware[]): ApiMiddleware[] {\n const routeDir = keyToDir(routeKey)\n\n return middlewares\n .filter(mw => routeDir.startsWith(mw.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchRoute(\n pathname: string,\n routes: ApiRoute[]\n): {route: ApiRoute; params: Record<string, string>} | null {\n for (const route of routes) {\n const match = pathname.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {route, params}\n }\n }\n return null\n}\n", "export function generateContext(): string {\n return `\nexport {RouterContext} from '@devlusoft/devix/runtime/context'\n`\n}", "const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] as const\nexport type HttpMethod = (typeof HTTP_METHODS)[number]\n\nconst METHOD_EXPORT_RE = /export\\s+(?:const|async\\s+function|function)\\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\\b/g\n\nfunction stripComments(content: string): string {\n return content\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '')\n .replace(/\\/\\/.*$/gm, '')\n}\n\nexport function extractHttpMethods(content: string): HttpMethod[] {\n const found = new Set<HttpMethod>()\n for (const match of stripComments(content).matchAll(METHOD_EXPORT_RE)) {\n found.add(match[1] as HttpMethod)\n }\n return [...found]\n}\n", "import { keyToRoutePattern } from '../../server/api-router'\nimport type { HttpMethod } from './extract-methods'\n\nexport interface RouteEntry {\n filePath: string\n urlPattern: string\n identifier: string\n methods: HttpMethod[]\n}\n\nexport function filePathToIdentifier(filePath: string, apiDir: string): string {\n return '_api_' + filePath\n .slice(`${apiDir}/`.length)\n .replace(/\\.(ts|tsx)$/, '')\n .replace(/[^a-zA-Z0-9]/g, '_')\n}\n\nexport function buildRouteEntry(filePath: string, apiDir: string, methods: HttpMethod[]): RouteEntry {\n return {\n filePath,\n urlPattern: keyToRoutePattern(filePath, apiDir),\n identifier: filePathToIdentifier(filePath, apiDir),\n methods,\n }\n}\n\nexport function generateRoutesDts(entries: RouteEntry[], apiDir: string): string {\n if (entries.length === 0) {\n return `// auto-generado por devix \u2014 no editar\\ndeclare module '@devlusoft/devix' {\\n interface ApiRoutes {}\\n}\\n`\n }\n\n const imports = entries\n .map(e => {\n const importPath = '../' + e.filePath.replace(/\\.(ts|tsx)$/, '')\n return `import type * as ${e.identifier} from '${importPath}'`\n })\n .join('\\n')\n\n const routeLines = entries.flatMap(e =>\n e.methods.map(m =>\n ` '${m} ${e.urlPattern}': InferRoute<(typeof ${e.identifier})['${m}']>`\n )\n ).join('\\n')\n\n return `// auto-generado por devix \u2014 no editar\n${imports}\n\ntype JsonResponse<T> = Response & { readonly __body: T }\ntype InferRoute<T> = T extends (...args: any[]) => any\n ? Awaited<ReturnType<T>> extends JsonResponse<infer U>\n ? U\n : Exclude<Awaited<ReturnType<T>>, Response | null | void>\n : never\n\ndeclare module '@devlusoft/devix' {\n interface ApiRoutes {\n${routeLines}\n }\n}\n`\n}\n", "import {readFileSync, readdirSync, statSync} from 'node:fs'\nimport {join, relative} from 'node:path'\nimport {extractHttpMethods} from './extract-methods'\nimport {buildRouteEntry} from './routes-dts'\nimport type {RouteEntry} from './routes-dts'\n\nfunction walkDir(dir: string, root: string): string[] {\n const entries: string[] = []\n for (const name of readdirSync(dir)) {\n const full = join(dir, name)\n if (statSync(full).isDirectory()) {\n entries.push(...walkDir(full, root))\n } else if (/\\.(ts|tsx)$/.test(name)) {\n entries.push(relative(root, full).replace(/\\\\/g, '/'))\n }\n }\n return entries\n}\n\nexport function scanApiFiles(appDir: string, projectRoot: string): RouteEntry[] {\n const apiDir = join(projectRoot, appDir, 'api')\n\n let files: string[]\n try {\n files = walkDir(apiDir, projectRoot)\n } catch {\n return []\n }\n\n return files\n .filter(f => !f.endsWith('middleware.ts') && !f.endsWith('middleware.tsx'))\n .flatMap(filePath => {\n try {\n const content = readFileSync(join(projectRoot, filePath), 'utf-8')\n const methods = extractHttpMethods(content)\n if (methods.length === 0) return []\n return [buildRouteEntry(filePath, `${appDir}/api`, methods)]\n } catch {\n return []\n }\n })\n}\n", "import {mkdirSync, readFileSync, writeFileSync, existsSync} from 'node:fs'\nimport {join} from 'node:path'\n\nexport function writeRoutesDts(content: string, projectRoot: string): boolean {\n const devixDir = join(projectRoot, '.devix')\n const outPath = join(devixDir, 'routes.d.ts')\n\n mkdirSync(devixDir, {recursive: true})\n\n if (existsSync(outPath) && readFileSync(outPath, 'utf-8') === content) {\n return false\n }\n\n writeFileSync(outPath, content, 'utf-8')\n return true\n}\n", "import {UserConfig, Plugin, mergeConfig} from 'vite'\nimport type {DevixConfig} from '../config'\nimport react from '@vitejs/plugin-react'\nimport {fileURLToPath} from 'node:url'\nimport {dirname, resolve} from 'node:path'\nimport {generateEntryClient} from './codegen/entry-client'\nimport {generateClientRoutes} from './codegen/client-routes'\nimport {generateRender} from './codegen/render'\nimport {generateApi} from './codegen/api'\nimport {invalidatePagesCache} from \"../server/pages-router\";\nimport {invalidateApiCache} from \"../server/api-router\";\nimport {generateContext} from \"./codegen/context\";\nimport {scanApiFiles} from \"./codegen/scan-api\";\nimport {generateRoutesDts} from \"./codegen/routes-dts\";\nimport {writeRoutesDts} from \"./codegen/write-routes-dts\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\n\nconst VIRTUAL_ENTRY_CLIENT = 'virtual:devix/entry-client'\nconst VIRTUAL_CLIENT_ROUTES = 'virtual:devix/client-routes'\nconst VIRTUAL_RENDER = 'virtual:devix/render'\nconst VIRTUAL_API = 'virtual:devix/api'\nconst VIRTUAL_CONTEXT = 'virtual:devix/context'\n\nexport function devix(config: DevixConfig): UserConfig {\n const appDir = config.appDir ?? 'app'\n const pagesDir = `${appDir}/pages`\n const cssUrls = (config.css ?? []).map(u => u.startsWith('/') ? u : `/${u.replace(/^\\.\\//, '')}`)\n\n const renderPath = resolve(__dirname, '../server/render.js').replace(/\\\\/g, '/')\n const apiPath = resolve(__dirname, '../server/api.js').replace(/\\\\/g, '/')\n const matcherPath = resolve(__dirname, '../runtime/client-router.js').replace(/\\\\/g, '/')\n\n const virtualPlugin: Plugin = {\n name: 'devix',\n enforce: 'pre',\n\n resolveId(id) {\n if (id === VIRTUAL_ENTRY_CLIENT) return `\\0${VIRTUAL_ENTRY_CLIENT}`\n if (id === VIRTUAL_CLIENT_ROUTES) return `\\0${VIRTUAL_CLIENT_ROUTES}`\n if (id === VIRTUAL_RENDER) return `\\0${VIRTUAL_RENDER}`\n if (id === VIRTUAL_API) return `\\0${VIRTUAL_API}`\n if (id === VIRTUAL_CONTEXT) return `\\0${VIRTUAL_CONTEXT}`\n },\n\n load(id) {\n if (id === `\\0${VIRTUAL_ENTRY_CLIENT}`)\n return generateEntryClient({cssUrls})\n if (id === `\\0${VIRTUAL_CLIENT_ROUTES}`)\n return generateClientRoutes({pagesDir, matcherPath})\n if (id === `\\0${VIRTUAL_RENDER}`)\n return generateRender({pagesDir, renderPath})\n if (id === `\\0${VIRTUAL_API}`)\n return generateApi({apiPath, appDir})\n if (id === `\\0${VIRTUAL_CONTEXT}`)\n return generateContext()\n },\n\n buildStart() {\n const root = process.cwd()\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n },\n\n configureServer(server) {\n const root = process.cwd()\n\n const regenerateDts = () => {\n const entries = scanApiFiles(appDir, root)\n writeRoutesDts(generateRoutesDts(entries, `${appDir}/api`), root)\n }\n\n server.watcher.on('add', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) { invalidateApiCache(); regenerateDts() }\n })\n server.watcher.on('unlink', (file) => {\n if (file.startsWith(resolve(root, pagesDir))) invalidatePagesCache()\n if (file.includes(`${appDir}/api`)) { invalidateApiCache(); regenerateDts() }\n })\n server.watcher.on('change', (file) => {\n if (file.includes(`${appDir}/api`) && !file.endsWith('middleware.ts')) {\n regenerateDts()\n }\n })\n },\n }\n\n const base: UserConfig = {\n plugins: [react(), virtualPlugin],\n ssr: {noExternal: ['@devlusoft/devix']},\n ...(config.envPrefix ? {envPrefix: config.envPrefix} : {}),\n }\n\n return mergeConfig(base, config.vite ?? {})\n}", "export function parseDuration(value: number | string): number {\n if (typeof value === 'number') return value\n const match = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)?$/)\n if (!match) throw new Error(`[devix] Invalid duration: \"${value}\". Use a number (ms) or a string like \"5s\", \"2m\", \"500ms\".`)\n const n = parseFloat(match[1])\n switch (match[2]) {\n case 'h': return n * 3_600_000\n case 'm': return n * 60_000\n case 's': return n * 1_000\n case 'ms':\n default: return n\n }\n}\n", "import {writeFileSync} from 'node:fs'\nimport {resolve} from 'node:path'\nimport {build} from 'vite'\nimport type {DevixConfig} from '../config'\nimport {devix} from '../vite'\nimport {parseDuration} from '../utils/duration'\n\nconst config: DevixConfig = (await import(`${process.cwd()}/devix.config.ts`)).default\nconst baseConfig = devix(config)\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n outDir: 'dist/client',\n manifest: true,\n rolldownOptions: {\n input: 'virtual:devix/entry-client',\n },\n },\n})\n\nawait build({\n ...baseConfig,\n configFile: false,\n build: {\n ssr: true,\n outDir: 'dist/server',\n rolldownOptions: {\n input: {\n render: 'virtual:devix/render',\n api: 'virtual:devix/api',\n },\n },\n },\n})\n\nconst runtimeConfig = {\n port: config.port ?? 3000,\n host: config.host ?? false,\n loaderTimeout: parseDuration(config.loaderTimeout ?? 10_000),\n output: config.output ?? 'server',\n}\n\nwriteFileSync(\n resolve(process.cwd(), 'dist/devix.config.json'),\n JSON.stringify(runtimeConfig, null, 2),\n 'utf-8'\n)\n\n\nexport {}", "import {readFileSync, mkdirSync, writeFileSync} from 'node:fs'\nimport {resolve, join} from 'node:path'\nimport type {Manifest} from 'vite'\nimport type {DevixConfig} from '../config'\n\nconst userConfig: DevixConfig = (await import(`${process.cwd()}/devix.config.ts`)).default\nif (userConfig.output !== 'static') {\n console.warn('[devix] Tip: set output: \"static\" in devix.config.ts to skip the SSR server at runtime.')\n}\n\nawait import('./build.js')\n\nconst t = Date.now()\nconst renderModule = await import(resolve(process.cwd(), 'dist/server/render.js') + `?t=${t}`)\n\nconst manifest: Manifest = JSON.parse(\n readFileSync(resolve(process.cwd(), 'dist/client/.vite/manifest.json'), 'utf-8')\n)\n\nconst urls: string[] = await renderModule.getStaticRoutes()\n\nconsole.log(`[devix] Generating ${urls.length} static page${urls.length === 1 ? '' : 's'}...`)\n\nfor (const url of urls) {\n const fullUrl = `http://localhost${url}`\n const {html, statusCode} = await renderModule.render(fullUrl, new Request(fullUrl), {manifest})\n\n if (statusCode !== 200) {\n console.warn(`[devix] Skipping ${url} \u2014 status ${statusCode}`)\n continue\n }\n\n const outPath = url === '/'\n ? join(process.cwd(), 'dist/client/index.html')\n : join(process.cwd(), 'dist/client', url, 'index.html')\n\n mkdirSync(join(outPath, '..'), {recursive: true})\n writeFileSync(outPath, `<!DOCTYPE html>${html}`, 'utf-8')\n console.log(` \u2713 ${url}`)\n}\n\nconsole.log('[devix] Generation complete.')\n\nexport {}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["generateEntryClient", "cssUrls", "u", "init_entry_client", "__esmMin", "generateClientRoutes", "pagesDir", "matcherPath", "init_client_routes", "__esmMin", "generateRender", "pagesDir", "renderPath", "init_render", "__esmMin", "generateApi", "apiPath", "appDir", "init_api", "__esmMin", "routePattern", "rel", "init_patterns", "__esmMin", "invalidatePagesCache", "cache", "init_pages_router", "__esmMin", "init_patterns", "keyToRoutePattern", "key", "apiDir", "rel", "pattern", "routePattern", "invalidateApiCache", "cache", "init_api_router", "__esmMin", "init_patterns", "generateContext", "init_context", "__esmMin", "stripComments", "content", "extractHttpMethods", "found", "match", "METHOD_EXPORT_RE", "init_extract_methods", "__esmMin", "filePathToIdentifier", "filePath", "apiDir", "buildRouteEntry", "methods", "keyToRoutePattern", "generateRoutesDts", "entries", "imports", "e", "importPath", "routeLines", "m", "init_routes_dts", "__esmMin", "init_api_router", "readFileSync", "readdirSync", "statSync", "join", "relative", "walkDir", "dir", "root", "entries", "name", "full", "scanApiFiles", "appDir", "projectRoot", "apiDir", "files", "f", "filePath", "content", "methods", "extractHttpMethods", "buildRouteEntry", "init_scan_api", "__esmMin", "init_extract_methods", "init_routes_dts", "mkdirSync", "readFileSync", "writeFileSync", "existsSync", "join", "writeRoutesDts", "content", "projectRoot", "devixDir", "outPath", "init_write_routes_dts", "__esmMin", "mergeConfig", "react", "fileURLToPath", "dirname", "resolve", "devix", "config", "appDir", "pagesDir", "cssUrls", "u", "renderPath", "__dirname", "apiPath", "matcherPath", "virtualPlugin", "id", "VIRTUAL_ENTRY_CLIENT", "VIRTUAL_CLIENT_ROUTES", "VIRTUAL_RENDER", "VIRTUAL_API", "VIRTUAL_CONTEXT", "generateEntryClient", "generateClientRoutes", "generateRender", "generateApi", "generateContext", "root", "entries", "scanApiFiles", "writeRoutesDts", "generateRoutesDts", "server", "regenerateDts", "file", "invalidatePagesCache", "invalidateApiCache", "base", "init_vite", "__esmMin", "init_entry_client", "init_client_routes", "init_render", "init_api", "init_pages_router", "init_api_router", "init_context", "init_scan_api", "init_routes_dts", "init_write_routes_dts", "parseDuration", "value", "match", "n", "init_duration", "__esmMin", "build_exports", "writeFileSync", "resolve", "build", "config", "baseConfig", "runtimeConfig", "init_build", "__esmMin", "init_vite", "init_duration", "devix", "parseDuration", "readFileSync", "mkdirSync", "writeFileSync", "resolve", "join", "userConfig", "t", "renderModule", "manifest", "urls", "url", "fullUrl", "html", "statusCode", "outPath"]
|
|
7
7
|
}
|