@vesk/adapter 0.2.16 → 0.2.18
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/client-bundle.d.ts.map +1 -1
- package/dist/client-bundle.js +243 -35
- package/dist/css.d.ts +6 -11
- package/dist/css.d.ts.map +1 -1
- package/dist/css.js +19 -38
- package/dist/dev-config.d.ts.map +1 -1
- package/dist/dev-config.js +139 -3
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +39 -1
- package/dist/hmr.d.ts.map +1 -1
- package/dist/hmr.js +33 -43
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -33
- package/dist/prod-server.d.ts.map +1 -1
- package/dist/prod-server.js +2 -3
- package/dist/ssr-function.d.ts.map +1 -1
- package/dist/ssr-function.js +43 -32
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAqC,MAAM,yBAAyB,CAAC;AAoCrI;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA8BhE;AAmUD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBxD;AAmCD,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,SAAS,EAAE,EACtB,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,CAuX7B;AAMD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CA+B3D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAUlE;AAYD;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuCrG"}
|
package/dist/client-bundle.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync, existsSync, writeFileSync, unlinkSync, statSync, rmSync } from 'node:fs';
|
|
1
|
+
import { readFileSync, existsSync, writeFileSync, unlinkSync, statSync, rmSync, mkdtempSync } from 'node:fs';
|
|
2
2
|
import { resolve, join, dirname, relative, sep } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { build } from './esbuild-fallback.js';
|
|
@@ -197,18 +197,160 @@ function demoteExports(code) {
|
|
|
197
197
|
code = code.slice(0, e.start) + e.text + code.slice(e.end);
|
|
198
198
|
return code;
|
|
199
199
|
}
|
|
200
|
+
function hasChunkImports(code) {
|
|
201
|
+
try {
|
|
202
|
+
const ast = parse(code);
|
|
203
|
+
return (ast.body ?? []).some((n) => n.type === 'ImportDeclaration');
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
200
209
|
/**
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
|
|
208
|
-
|
|
210
|
+
* Rewrites a compiled file's source specifier so esbuild can resolve it from
|
|
211
|
+
* the temp bundle entry. Bare package specifiers (e.g. `lucide-vesk`) stay
|
|
212
|
+
* as-is; relative specifiers are resolved to absolute filesystem paths with a
|
|
213
|
+
* `.ts` extension appended so esbuild loads the module as TypeScript and
|
|
214
|
+
* inlines its exported values. Offset-based on the parser AST — never a text
|
|
215
|
+
* scan.
|
|
216
|
+
*/
|
|
217
|
+
function resolveImportSource(src, filePath) {
|
|
218
|
+
if (src.startsWith('./') || src.startsWith('../')) {
|
|
219
|
+
return resolve(dirname(filePath), src) + '.ts';
|
|
220
|
+
}
|
|
221
|
+
return src;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Accumulates every import a code-split chunk needs and rebuilds it as a
|
|
225
|
+
* single deduped import block.
|
|
226
|
+
*
|
|
227
|
+
* A chunk is the concatenation of several independently compiled files, and
|
|
228
|
+
* each file's component AND hydrator both keep their imports verbatim. So the
|
|
229
|
+
* same named binding frequently appears multiple times in one chunk — once per
|
|
230
|
+
* (file, comp|hyd) pair, plus once per extra file. acorn's `parse()` rejects
|
|
231
|
+
* that with `Identifier has already been declared`, so `hasChunkImports` used
|
|
232
|
+
* to silently return false and esbuild — which rejects the same duplicates —
|
|
233
|
+
* never ran; the chunk shipped with raw `import` statements inside its
|
|
234
|
+
* classic-script IIFE and hydration died with `SyntaxError: Cannot use import
|
|
235
|
+
* statement outside a module`.
|
|
236
|
+
*
|
|
237
|
+
* Processing each file's contribution in isolation avoids the duplicate
|
|
238
|
+
* bindings entirely (a single compiled file parses cleanly), folds the imports
|
|
239
|
+
* into a per-source map keyed by local binding, strips them from the file
|
|
240
|
+
* body, and later emits one merged import block at the top of the chunk.
|
|
209
241
|
*/
|
|
210
|
-
|
|
211
|
-
|
|
242
|
+
class ChunkImports {
|
|
243
|
+
bySource = new Map();
|
|
244
|
+
aborted = false;
|
|
245
|
+
abortReason = null;
|
|
246
|
+
fail(reason, code) {
|
|
247
|
+
if (!this.aborted) {
|
|
248
|
+
this.aborted = true;
|
|
249
|
+
this.abortReason = reason;
|
|
250
|
+
}
|
|
251
|
+
return code;
|
|
252
|
+
}
|
|
253
|
+
/** Folds one file's imports into the merged set and returns the code with its imports stripped. */
|
|
254
|
+
add(code, filePath) {
|
|
255
|
+
if (!code || this.aborted)
|
|
256
|
+
return code;
|
|
257
|
+
let ast;
|
|
258
|
+
try {
|
|
259
|
+
ast = parse(code);
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// A single compiled file is always valid ESM; if it somehow is not,
|
|
263
|
+
// stop merging so the assembler falls back to the historical path.
|
|
264
|
+
return this.fail(`unparseable contribution from ${filePath}`, code);
|
|
265
|
+
}
|
|
266
|
+
const body = ast.body ?? [];
|
|
267
|
+
const ranges = [];
|
|
268
|
+
for (const raw of body) {
|
|
269
|
+
const node = raw;
|
|
270
|
+
if (node.type !== 'ImportDeclaration' || typeof node.start !== 'number' || typeof node.end !== 'number')
|
|
271
|
+
continue;
|
|
272
|
+
const src = node.source?.value;
|
|
273
|
+
if (typeof src !== 'string')
|
|
274
|
+
continue;
|
|
275
|
+
const resolved = resolveImportSource(src, filePath);
|
|
276
|
+
let group = this.bySource.get(resolved);
|
|
277
|
+
if (!group) {
|
|
278
|
+
group = { named: new Map() };
|
|
279
|
+
this.bySource.set(resolved, group);
|
|
280
|
+
}
|
|
281
|
+
for (const spec of node.specifiers ?? []) {
|
|
282
|
+
const s = spec;
|
|
283
|
+
const local = s.local?.name;
|
|
284
|
+
if (typeof local !== 'string')
|
|
285
|
+
return this.fail(`nameless specifier from '${resolved}' in ${filePath}`, code);
|
|
286
|
+
if (s.type === 'ImportDefaultSpecifier') {
|
|
287
|
+
if (group.default && group.default.local !== local)
|
|
288
|
+
return this.fail(`conflicting default imports from '${resolved}' in ${filePath}`, code);
|
|
289
|
+
group.default = { kind: 'default', local };
|
|
290
|
+
}
|
|
291
|
+
else if (s.type === 'ImportNamespaceSpecifier') {
|
|
292
|
+
if (group.namespace && group.namespace.local !== local)
|
|
293
|
+
return this.fail(`conflicting namespace imports from '${resolved}' in ${filePath}`, code);
|
|
294
|
+
group.namespace = { kind: 'namespace', local };
|
|
295
|
+
}
|
|
296
|
+
else if (s.type === 'ImportSpecifier') {
|
|
297
|
+
const imported = s.imported?.name;
|
|
298
|
+
if (typeof imported !== 'string')
|
|
299
|
+
return this.fail(`nameless named-import from '${resolved}' in ${filePath}`, code);
|
|
300
|
+
const existing = group.named.get(imported);
|
|
301
|
+
if (existing && existing.local !== local)
|
|
302
|
+
return this.fail(`'${imported}' from '${resolved}' bound to both '${existing.local}' and '${local}' in ${filePath}`, code);
|
|
303
|
+
group.named.set(imported, { kind: 'named', local, imported });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
let cut = node.end;
|
|
307
|
+
if (code[cut] === ';')
|
|
308
|
+
cut++;
|
|
309
|
+
ranges.push([node.start, cut]);
|
|
310
|
+
}
|
|
311
|
+
if (ranges.length === 0)
|
|
312
|
+
return code;
|
|
313
|
+
return removeRanges(code, ranges);
|
|
314
|
+
}
|
|
315
|
+
/** True when every file parsed and merged cleanly (no conflict, no parse abort). */
|
|
316
|
+
get ok() {
|
|
317
|
+
return !this.aborted;
|
|
318
|
+
}
|
|
319
|
+
/** Why the merge aborted (null when `ok`). Surfaced by the assembler. */
|
|
320
|
+
get reason() {
|
|
321
|
+
return this.abortReason;
|
|
322
|
+
}
|
|
323
|
+
/** Renders the deduped import block (empty string when there are no imports). */
|
|
324
|
+
render() {
|
|
325
|
+
if (this.aborted || this.bySource.size === 0)
|
|
326
|
+
return '';
|
|
327
|
+
const lines = [];
|
|
328
|
+
const sources = [...this.bySource.keys()].sort();
|
|
329
|
+
for (const src of sources) {
|
|
330
|
+
const g = this.bySource.get(src);
|
|
331
|
+
const parts = [];
|
|
332
|
+
if (g.default)
|
|
333
|
+
parts.push(`import ${g.default.local} from ${JSON.stringify(src)}`);
|
|
334
|
+
if (g.namespace)
|
|
335
|
+
parts.push(`import * as ${g.namespace.local} from ${JSON.stringify(src)}`);
|
|
336
|
+
const named = [...g.named.values()].sort((a, b) => (a.imported < b.imported ? -1 : 1));
|
|
337
|
+
if (named.length > 0) {
|
|
338
|
+
const specs = named.map((sp) => (sp.imported === sp.local ? sp.local : `${sp.imported} as ${sp.local}`)).join(', ');
|
|
339
|
+
parts.push(`import { ${specs} } from ${JSON.stringify(src)}`);
|
|
340
|
+
}
|
|
341
|
+
lines.push(parts.join('\n'));
|
|
342
|
+
}
|
|
343
|
+
return lines.join('\n');
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/** Removes a set of offset ranges from a source string, high-to-low. */
|
|
347
|
+
function removeRanges(code, ranges) {
|
|
348
|
+
const sorted = [...ranges].sort((a, b) => b[0] - a[0]);
|
|
349
|
+
let out = code;
|
|
350
|
+
for (const [start, end] of sorted) {
|
|
351
|
+
out = out.slice(0, start) + out.slice(end);
|
|
352
|
+
}
|
|
353
|
+
return out.trim();
|
|
212
354
|
}
|
|
213
355
|
/**
|
|
214
356
|
* Scopes one file's contribution to the shared chunk: module-level
|
|
@@ -365,7 +507,7 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
365
507
|
function stripExports(code) {
|
|
366
508
|
return removeCompiledNodes(code, isComponentExport);
|
|
367
509
|
}
|
|
368
|
-
function compileFile(filePath, resolvedName, output) {
|
|
510
|
+
function compileFile(filePath, resolvedName, output, imports) {
|
|
369
511
|
if (seen.has(filePath))
|
|
370
512
|
return;
|
|
371
513
|
seen.add(filePath);
|
|
@@ -390,11 +532,17 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
390
532
|
if (cached && cacheUsable) {
|
|
391
533
|
cachedFileHits++;
|
|
392
534
|
for (const dep of cached.imports)
|
|
393
|
-
compileFile(dep, cache?.files.get(dep)?.actualName ?? '', output);
|
|
535
|
+
compileFile(dep, cache?.files.get(dep)?.actualName ?? '', output, imports);
|
|
394
536
|
// Comp and hyd contributions of one file share its top-level bindings
|
|
395
537
|
// (e.g. `const links` used by both the component and its hydrator),
|
|
396
|
-
// so they must be scoped together in a single block.
|
|
397
|
-
|
|
538
|
+
// so they must be scoped together in a single block. Cached codes keep
|
|
539
|
+
// their imports; each side is folded separately because comp+hyd of one
|
|
540
|
+
// file carry the same import twice (joint parse would abort the merge).
|
|
541
|
+
// Mirror the fresh path exactly: strip, rename the hydrator registry,
|
|
542
|
+
// trim — otherwise warm output drifts from cold output.
|
|
543
|
+
const cachedComp = cached.compCode ? imports.add(cached.compCode, filePath).replace(/^\n+/, '').replace(/\n+$/, '') : '';
|
|
544
|
+
const cachedHyd = cached.hydCode ? imports.add(cached.hydCode, filePath).replace(/__components/g, '__hydrators').replace(/^\n+/, '').replace(/\n+$/, '') : '';
|
|
545
|
+
const cachedFileCode = [cachedComp, cachedHyd].filter(Boolean).join('\n');
|
|
398
546
|
if (cachedFileCode.trim())
|
|
399
547
|
output.push(scopeFileContribution(cachedFileCode));
|
|
400
548
|
for (const n of cached.runtimeNames)
|
|
@@ -411,13 +559,17 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
411
559
|
src = inlineMdContentAttrs(src, dirname(filePath), guessProjectRoots(appDir));
|
|
412
560
|
}
|
|
413
561
|
const namesBefore = cache ? new Set(runtimeImportNames) : null;
|
|
414
|
-
const importedPaths = resolveVskImports(filePath, (p, n) => compileFile(p, n
|
|
562
|
+
const importedPaths = resolveVskImports(filePath, (p, n) => compileFile(p, n, output, imports));
|
|
415
563
|
// One parse/IR pass feeds both client modes AND the component-name
|
|
416
564
|
// lookup — the dev hot path pays the acorn+TS parse once per edit
|
|
417
565
|
// instead of three times.
|
|
418
566
|
const { comp: rawComp, hyd: rawHyd, name: actualName } = compileClientBoth(src, null, filePath);
|
|
419
|
-
|
|
420
|
-
|
|
567
|
+
// Cache keeps the import-carrying codes so a warm build can re-fold them
|
|
568
|
+
// into its own fresh accumulator; the emitted codes are import-stripped.
|
|
569
|
+
const compWithImports = rawComp ? stripExports(stripVskImports(stripRuntimeImport(rawComp))) : '';
|
|
570
|
+
const hydWithImports = rawHyd ? stripExports(stripVskImports(stripRuntimeImport(rawHyd))) : '';
|
|
571
|
+
const compCode = compWithImports ? imports.add(compWithImports, filePath).replace(/^\n+/, '').replace(/\n+$/, '') : '';
|
|
572
|
+
const hydCode = hydWithImports ? imports.add(hydWithImports, filePath).replace(/__components/g, '__hydrators').replace(/^\n+/, '').replace(/\n+$/, '') : '';
|
|
421
573
|
if (rawComp)
|
|
422
574
|
collectRuntimeImports(rawComp);
|
|
423
575
|
if (rawHyd)
|
|
@@ -444,8 +596,8 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
444
596
|
cache.files.set(filePath, {
|
|
445
597
|
mtimeMs: st.mtimeMs,
|
|
446
598
|
size: st.size,
|
|
447
|
-
compCode,
|
|
448
|
-
hydCode,
|
|
599
|
+
compCode: compWithImports,
|
|
600
|
+
hydCode: hydWithImports,
|
|
449
601
|
actualName,
|
|
450
602
|
runtimeNames: [...runtimeImportNames].filter((n) => !namesBefore.has(n)),
|
|
451
603
|
imports: importedPaths,
|
|
@@ -479,57 +631,113 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
479
631
|
function walkSplit(nodes, _chain) {
|
|
480
632
|
for (const node of nodes) {
|
|
481
633
|
const chunkCode = [];
|
|
634
|
+
const chunkImports = new ChunkImports();
|
|
482
635
|
const pagePath = resolve(appDir, node.sourceDir, 'page.vsk');
|
|
483
636
|
if (node.page && existsSync(pagePath)) {
|
|
484
|
-
compileFile(pagePath, node.page, chunkCode);
|
|
637
|
+
compileFile(pagePath, node.page, chunkCode, chunkImports);
|
|
485
638
|
}
|
|
486
639
|
const layoutPath = resolve(appDir, node.sourceDir, 'layout.vsk');
|
|
487
640
|
if (node.layout && existsSync(layoutPath)) {
|
|
488
|
-
compileFile(layoutPath, node.layout, chunkCode);
|
|
641
|
+
compileFile(layoutPath, node.layout, chunkCode, chunkImports);
|
|
489
642
|
}
|
|
490
643
|
const errorPath = resolve(appDir, node.sourceDir, 'error.vsk');
|
|
491
644
|
if (node.error && existsSync(errorPath)) {
|
|
492
|
-
compileFile(errorPath, node.error, chunkCode);
|
|
645
|
+
compileFile(errorPath, node.error, chunkCode, chunkImports);
|
|
493
646
|
}
|
|
494
647
|
const notFoundPath = resolve(appDir, node.sourceDir, 'not-found.vsk');
|
|
495
648
|
if (node.notFound && existsSync(notFoundPath)) {
|
|
496
|
-
compileFile(notFoundPath, node.notFound, chunkCode);
|
|
649
|
+
compileFile(notFoundPath, node.notFound, chunkCode, chunkImports);
|
|
497
650
|
}
|
|
498
651
|
const offlinePath = resolve(appDir, node.sourceDir, 'offline.vsk');
|
|
499
652
|
if (node.offline && existsSync(offlinePath)) {
|
|
500
|
-
compileFile(offlinePath, node.offline, chunkCode);
|
|
653
|
+
compileFile(offlinePath, node.offline, chunkCode, chunkImports);
|
|
501
654
|
}
|
|
502
655
|
const networkPath = resolve(appDir, node.sourceDir, 'network.vsk');
|
|
503
656
|
if (node.network && existsSync(networkPath)) {
|
|
504
|
-
compileFile(networkPath, node.network, chunkCode);
|
|
657
|
+
compileFile(networkPath, node.network, chunkCode, chunkImports);
|
|
505
658
|
}
|
|
506
659
|
const loadingPath = resolve(appDir, node.sourceDir, 'loading.vsk');
|
|
507
660
|
if (node.loading && existsSync(loadingPath)) {
|
|
508
|
-
compileFile(loadingPath, node.loading, chunkCode);
|
|
661
|
+
compileFile(loadingPath, node.loading, chunkCode, chunkImports);
|
|
509
662
|
}
|
|
510
663
|
if (chunkCode.length > 0) {
|
|
511
664
|
const chunkName = `page-${buildChunkName(node)}.js`;
|
|
512
|
-
|
|
665
|
+
// Prepend this chunk's deduped imports (one statement per source, no
|
|
666
|
+
// duplicate bindings) so the classic script exposes the bare
|
|
667
|
+
// identifiers its file bodies reference, and esbuild can parse and
|
|
668
|
+
// inline them.
|
|
669
|
+
if (!chunkImports.ok)
|
|
670
|
+
console.error('[vesk] chunk import merge aborted for', chunkName + ':', chunkImports.reason);
|
|
671
|
+
const head = chunkImports.render();
|
|
672
|
+
const code = (head ? head + '\n\n' : '') + chunkCode.join('\n\n');
|
|
673
|
+
chunkEntries.push({ name: chunkName, code, node });
|
|
513
674
|
}
|
|
514
675
|
walkSplit(node.children || [], [..._chain, node]);
|
|
515
676
|
}
|
|
516
677
|
}
|
|
517
678
|
walkSplit(routeTree, []);
|
|
518
679
|
const sharedCode = [];
|
|
680
|
+
const sharedImports = new ChunkImports();
|
|
519
681
|
const compMap = componentMap || new Map();
|
|
520
682
|
for (const [compName, compPath] of compMap) {
|
|
521
|
-
compileFile(compPath, compName, sharedCode);
|
|
683
|
+
compileFile(compPath, compName, sharedCode, sharedImports);
|
|
522
684
|
}
|
|
523
685
|
if (sharedCode.length > 0) {
|
|
524
|
-
|
|
686
|
+
if (!sharedImports.ok)
|
|
687
|
+
console.error('[vesk] chunk import merge aborted for shared.js:', sharedImports.reason);
|
|
688
|
+
const head = sharedImports.render();
|
|
689
|
+
const code = (head ? head + '\n\n' : '') + sharedCode.join('\n\n');
|
|
690
|
+
chunkEntries.push({ name: 'shared.js', code, node: null });
|
|
525
691
|
}
|
|
692
|
+
const chunkIIFE = (body) => `(()=>{\nconst __components = globalThis.__components || (globalThis.__components = {});\nconst __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});\n${body}\n})();\n`;
|
|
526
693
|
for (const entry of chunkEntries) {
|
|
527
|
-
if (entry.code.trim())
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
694
|
+
if (!entry.code.trim())
|
|
695
|
+
continue;
|
|
696
|
+
let finalCode;
|
|
697
|
+
if (hasChunkImports(entry.code)) {
|
|
698
|
+
// Bundle the chunk through esbuild so every remaining import (npm
|
|
699
|
+
// packages like lucide-vesk and rewritten relative `.ts` value
|
|
700
|
+
// modules) is inlined into the IIFE — a classic script cannot carry
|
|
701
|
+
// a live `import`, and a stripped binding referenced by a component
|
|
702
|
+
// would otherwise throw `X is not defined` at hydration. Imports were
|
|
703
|
+
// already deduped per file by `ChunkImports`, so esbuild can parse the
|
|
704
|
+
// bundle entry.
|
|
705
|
+
const tmpBase = mkdtempSync(join(resolve(appDir, '..'), 'tmp-vesk-chunk-'));
|
|
706
|
+
const tmpFile = join(tmpBase, 'entry.js');
|
|
707
|
+
const toBundle = `const __components = globalThis.__components || (globalThis.__components = {});\nconst __hydrators = globalThis.__hydrators || (globalThis.__hydrators = {});\n${entry.code}\n`;
|
|
708
|
+
writeFileSync(tmpFile, toBundle);
|
|
709
|
+
try {
|
|
710
|
+
const result = await build({
|
|
711
|
+
entryPoints: [tmpFile],
|
|
712
|
+
bundle: true,
|
|
713
|
+
format: 'iife',
|
|
714
|
+
platform: 'browser',
|
|
715
|
+
write: false,
|
|
716
|
+
logLevel: 'silent',
|
|
717
|
+
loader: { '.js': 'tsx' },
|
|
718
|
+
});
|
|
719
|
+
finalCode = result.outputFiles[0].text;
|
|
720
|
+
}
|
|
721
|
+
catch (e) {
|
|
722
|
+
const err = e;
|
|
723
|
+
console.error('[vesk] chunk bundle failed', entry.name, err?.errors?.map((x) => x.text).join(' | ') || err?.message || String(e));
|
|
724
|
+
// Fall back to the historical behavior: strip every import so the
|
|
725
|
+
// classic script at least parses (referenced values will surface as
|
|
726
|
+
// ReferenceErrors at runtime — the pre-existing failure mode).
|
|
727
|
+
const stripped = demoteExports(removeCompiledNodes(entry.code, isAnyImport));
|
|
728
|
+
finalCode = chunkIIFE(stripped);
|
|
729
|
+
}
|
|
730
|
+
finally {
|
|
731
|
+
try {
|
|
732
|
+
rmSync(tmpBase, { recursive: true, force: true });
|
|
733
|
+
}
|
|
734
|
+
catch { }
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
finalCode = chunkIIFE(entry.code);
|
|
532
739
|
}
|
|
740
|
+
chunks.push({ name: entry.name, code: finalCode });
|
|
533
741
|
}
|
|
534
742
|
function annotate(nodes) {
|
|
535
743
|
for (const node of nodes) {
|
package/dist/css.d.ts
CHANGED
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
export declare const TAILWIND_CSS_URL = "/_vesk/static/_tailwind.css";
|
|
2
1
|
export declare const GLOBAL_CSS_URL = "/_vesk/static/global.css";
|
|
3
2
|
/** Resolve the project's user stylesheet source (`src/global.css`, then `src/app.css`). */
|
|
4
3
|
export declare function resolveUserCssPath(appDir: string): string | null;
|
|
5
4
|
/** True when the project has a user stylesheet source (`src/global.css` or `src/app.css`). */
|
|
6
5
|
export declare function hasUserCss(appDir: string): boolean;
|
|
7
|
-
/** True when a non-empty `
|
|
8
|
-
export declare function
|
|
6
|
+
/** True when a non-empty `global.css` was produced for the build (prod disk output). */
|
|
7
|
+
export declare function hasBuiltGlobalCss(outDir: string): boolean;
|
|
9
8
|
/** True when the active plugin pipeline includes the tailwind plugin. */
|
|
10
9
|
export declare function isTailwindPlugin(plugins: Array<{
|
|
11
10
|
name?: string;
|
|
12
11
|
}> | undefined | null): boolean;
|
|
13
12
|
/**
|
|
14
13
|
* Single source of truth for the `/_vesk/static/*.css` link list. Callers
|
|
15
|
-
* supply environment facts — `
|
|
16
|
-
* (built-file present + non-empty in prod,
|
|
17
|
-
*
|
|
18
|
-
* paths share one ordering.
|
|
14
|
+
* supply environment facts — `enabled`: a global stylesheet output is
|
|
15
|
+
* available (built-file present + non-empty in prod, user stylesheet present
|
|
16
|
+
* in dev) — so build, request, dev, and prod paths share one ordering.
|
|
19
17
|
*/
|
|
20
18
|
export declare function resolveCssUrls(opts: {
|
|
21
|
-
|
|
22
|
-
userCss?: boolean;
|
|
19
|
+
enabled?: boolean;
|
|
23
20
|
}): string[];
|
|
24
|
-
/** Drop tailwind framework directives from user CSS, keeping hand-written rules. */
|
|
25
|
-
export declare function stripTailwindDirectives(css: string): string;
|
|
26
21
|
//# sourceMappingURL=css.d.ts.map
|
package/dist/css.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,cAAc,6BAA6B,CAAC;AAEzD,2FAA2F;AAC3F,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMhE;AAED,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAE9F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,EAAE,CAGpE"}
|
package/dist/css.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared stylesheet resolution for the adapter build, prod server, generated
|
|
3
3
|
* SSR functions, dev server, and action handler. Each environment feeds its
|
|
4
|
-
* facts (`
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* facts (`enabled`: a built global stylesheet exists) into `resolveCssUrls`,
|
|
5
|
+
* so the `/_vesk/static/global.css` link list comes from one place instead of
|
|
6
|
+
* several ad-hoc copies.
|
|
7
|
+
*
|
|
8
|
+
* Vesk follows the single-file CSS convention used by other frameworks
|
|
9
|
+
* (Next.js/Remix/SvelteKit): a single `src/global.css` is the stylesheet
|
|
10
|
+
* source. When the Tailwind plugin is active the whole file is compiled into
|
|
11
|
+
* one `/_vesk/static/global.css`; otherwise the user CSS is served as-is from
|
|
12
|
+
* the same URL. There is no separate `_tailwind.css` anymore — user rules and
|
|
13
|
+
* the compiled Tailwind output live in the same file, in one `<link>`.
|
|
7
14
|
*/
|
|
8
15
|
import { readFileSync, existsSync } from 'node:fs';
|
|
9
16
|
import { resolve } from 'node:path';
|
|
10
|
-
import { cssBlockEnd } from '@vesk/compiler/src/scan';
|
|
11
|
-
export const TAILWIND_CSS_URL = '/_vesk/static/_tailwind.css';
|
|
12
17
|
export const GLOBAL_CSS_URL = '/_vesk/static/global.css';
|
|
13
18
|
/** Resolve the project's user stylesheet source (`src/global.css`, then `src/app.css`). */
|
|
14
19
|
export function resolveUserCssPath(appDir) {
|
|
@@ -24,9 +29,9 @@ export function resolveUserCssPath(appDir) {
|
|
|
24
29
|
export function hasUserCss(appDir) {
|
|
25
30
|
return resolveUserCssPath(appDir) !== null;
|
|
26
31
|
}
|
|
27
|
-
/** True when a non-empty `
|
|
28
|
-
export function
|
|
29
|
-
const p = resolve(outDir, 'static', '
|
|
32
|
+
/** True when a non-empty `global.css` was produced for the build (prod disk output). */
|
|
33
|
+
export function hasBuiltGlobalCss(outDir) {
|
|
34
|
+
const p = resolve(outDir, 'static', 'global.css');
|
|
30
35
|
return existsSync(p) && readFileSync(p, 'utf-8').trim().length > 0;
|
|
31
36
|
}
|
|
32
37
|
/** True when the active plugin pipeline includes the tailwind plugin. */
|
|
@@ -35,36 +40,12 @@ export function isTailwindPlugin(plugins) {
|
|
|
35
40
|
}
|
|
36
41
|
/**
|
|
37
42
|
* Single source of truth for the `/_vesk/static/*.css` link list. Callers
|
|
38
|
-
* supply environment facts — `
|
|
39
|
-
* (built-file present + non-empty in prod,
|
|
40
|
-
*
|
|
41
|
-
* paths share one ordering.
|
|
43
|
+
* supply environment facts — `enabled`: a global stylesheet output is
|
|
44
|
+
* available (built-file present + non-empty in prod, user stylesheet present
|
|
45
|
+
* in dev) — so build, request, dev, and prod paths share one ordering.
|
|
42
46
|
*/
|
|
43
47
|
export function resolveCssUrls(opts) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (opts.userCss)
|
|
48
|
-
urls.push(GLOBAL_CSS_URL);
|
|
49
|
-
return urls;
|
|
50
|
-
}
|
|
51
|
-
/** Drop tailwind framework directives from user CSS, keeping hand-written rules. */
|
|
52
|
-
export function stripTailwindDirectives(css) {
|
|
53
|
-
const blockStart = /^\s*@(theme\s*\{|layer\s+(components|utilities)\s*\{|utility\s+[\w-]+\s*\{)/;
|
|
54
|
-
let result = css.replace(/^\s*@import\s+['"]tailwindcss['"]\s*;?\s*$/gm, '');
|
|
55
|
-
result = result.replace(/^\s*@source\s+['"][^'"]+['"]\s*;?\s*$/gm, '');
|
|
56
|
-
const output = [];
|
|
57
|
-
let pos = 0;
|
|
58
|
-
while (pos < result.length) {
|
|
59
|
-
const lineEnd = result.indexOf('\n', pos) === -1 ? result.length : result.indexOf('\n', pos) + 1;
|
|
60
|
-
const line = result.slice(pos, lineEnd);
|
|
61
|
-
if (blockStart.test(line.trim())) {
|
|
62
|
-
const end = cssBlockEnd(result, pos);
|
|
63
|
-
pos = end;
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
output.push(line);
|
|
67
|
-
pos = lineEnd;
|
|
68
|
-
}
|
|
69
|
-
return output.join('').trim();
|
|
48
|
+
if (opts.enabled)
|
|
49
|
+
return [GLOBAL_CSS_URL];
|
|
50
|
+
return [];
|
|
70
51
|
}
|
package/dist/dev-config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-config.d.ts","sourceRoot":"","sources":["../src/dev-config.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAMjE;AAQD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmC/G;AAED,oEAAoE;AACpE,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAM9E;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQrG;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAc5F;
|
|
1
|
+
{"version":3,"file":"dev-config.d.ts","sourceRoot":"","sources":["../src/dev-config.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAMjE;AAQD;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAmC/G;AAED,oEAAoE;AACpE,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAM9E;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQrG;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAc5F;AAgOD,wJAAwJ;AACxJ,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAcxD;AAyYD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA2EtF;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqC9F"}
|
package/dist/dev-config.js
CHANGED
|
@@ -208,7 +208,7 @@ function tryParseJsObject(src) {
|
|
|
208
208
|
while (i < src.length && /\s/.test(src[i]))
|
|
209
209
|
i++;
|
|
210
210
|
if (src[i] === '=')
|
|
211
|
-
return null;
|
|
211
|
+
return null;
|
|
212
212
|
if (src[i] !== ':')
|
|
213
213
|
return null;
|
|
214
214
|
i++;
|
|
@@ -222,10 +222,62 @@ function tryParseJsObject(src) {
|
|
|
222
222
|
}
|
|
223
223
|
return out;
|
|
224
224
|
}
|
|
225
|
+
/** Skip a balanced (…) expression starting at `i`, returning the index after the closing ')' (or on failure, `i` unchanged). */
|
|
226
|
+
function skipBalancedParens(src, i) {
|
|
227
|
+
if (src[i] !== '(')
|
|
228
|
+
return i;
|
|
229
|
+
let depth = 0;
|
|
230
|
+
let inStr = null;
|
|
231
|
+
let esc = false;
|
|
232
|
+
for (let j = i; j < src.length; j++) {
|
|
233
|
+
const ch = src[j];
|
|
234
|
+
if (inStr) {
|
|
235
|
+
if (esc) {
|
|
236
|
+
esc = false;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (ch === '\\') {
|
|
240
|
+
esc = true;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (ch === inStr)
|
|
244
|
+
inStr = null;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
248
|
+
inStr = ch;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (ch === '(')
|
|
252
|
+
depth++;
|
|
253
|
+
if (ch === ')') {
|
|
254
|
+
depth--;
|
|
255
|
+
if (depth === 0)
|
|
256
|
+
return j + 1;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return i; // unbalanced — bail
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Return a raw source span (used for function calls, variable refs, spreads
|
|
263
|
+
* that can't be round-tripped as literals). The value is stored as a wrapper
|
|
264
|
+
* object so serializeValue can emit it verbatim.
|
|
265
|
+
*/
|
|
266
|
+
function rawSpan(src, from, to) {
|
|
267
|
+
return { value: { __veskRaw: src.slice(from, to) }, next: to };
|
|
268
|
+
}
|
|
225
269
|
function parseLiteralValue(src, i) {
|
|
226
270
|
const c = src[i];
|
|
227
271
|
if (c === undefined)
|
|
228
272
|
return null;
|
|
273
|
+
// spread: ...expr
|
|
274
|
+
if (c === '.' && src.slice(i, i + 3) === '...') {
|
|
275
|
+
const expr = parseLiteralValue(src, i + 3);
|
|
276
|
+
if (expr === null || expr.__invalid)
|
|
277
|
+
return rawSpan(src, i, skipToEndOfRaw(src, i + 3));
|
|
278
|
+
// preserve spread marker in the serialized output
|
|
279
|
+
return { value: { __veskRaw: '...' + serializeValue(expr.value) }, next: expr.next };
|
|
280
|
+
}
|
|
229
281
|
if (c === '{') {
|
|
230
282
|
const end = findMatchingBrace(src, i);
|
|
231
283
|
if (end === -1)
|
|
@@ -251,8 +303,10 @@ function parseLiteralValue(src, i) {
|
|
|
251
303
|
continue;
|
|
252
304
|
}
|
|
253
305
|
const r = parseLiteralValue(src, j);
|
|
254
|
-
if (r === null || r.__invalid)
|
|
255
|
-
|
|
306
|
+
if (r === null || r.__invalid) {
|
|
307
|
+
// Can't parse this array element — fall back to raw span for the whole array
|
|
308
|
+
return rawSpan(src, i, skipToEndOfArray(src, i));
|
|
309
|
+
}
|
|
256
310
|
vals.push(r.value);
|
|
257
311
|
j = r.next;
|
|
258
312
|
}
|
|
@@ -268,6 +322,7 @@ function parseLiteralValue(src, i) {
|
|
|
268
322
|
}
|
|
269
323
|
return { value: s, next: j + 1 };
|
|
270
324
|
}
|
|
325
|
+
// identifiers, numbers, booleans, null, and tokens followed by '(' (function calls)
|
|
271
326
|
let j = i;
|
|
272
327
|
while (j < src.length && /[\w.\-]/.test(src[j]))
|
|
273
328
|
j++;
|
|
@@ -280,8 +335,86 @@ function parseLiteralValue(src, i) {
|
|
|
280
335
|
return { value: null, next: j };
|
|
281
336
|
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(token))
|
|
282
337
|
return { value: Number(token), next: j };
|
|
338
|
+
// token is an identifier or a function name — check if it's followed by '(' (call)
|
|
339
|
+
if (j < src.length && src[j] === '(') {
|
|
340
|
+
const end = skipBalancedParens(src, j);
|
|
341
|
+
return rawSpan(src, i, end);
|
|
342
|
+
}
|
|
343
|
+
// bare variable reference (e.g. `testPlugin`, `tailwindcss`)
|
|
344
|
+
if (token.length > 0)
|
|
345
|
+
return rawSpan(src, i, j);
|
|
283
346
|
return { value: undefined, next: i, __invalid: true };
|
|
284
347
|
}
|
|
348
|
+
/** Skip forward from `i` to find the end of a raw expression (used for spread fallback). */
|
|
349
|
+
function skipToEndOfRaw(src, i) {
|
|
350
|
+
let depth = 0;
|
|
351
|
+
let inStr = null;
|
|
352
|
+
let esc = false;
|
|
353
|
+
for (let j = i; j < src.length; j++) {
|
|
354
|
+
const ch = src[j];
|
|
355
|
+
if (inStr) {
|
|
356
|
+
if (esc) {
|
|
357
|
+
esc = false;
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
if (ch === '\\') {
|
|
361
|
+
esc = true;
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (ch === inStr)
|
|
365
|
+
inStr = null;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
369
|
+
inStr = ch;
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (ch === '(')
|
|
373
|
+
depth++;
|
|
374
|
+
if (ch === ')') {
|
|
375
|
+
if (depth === 0)
|
|
376
|
+
return j;
|
|
377
|
+
depth--;
|
|
378
|
+
}
|
|
379
|
+
if (depth === 0 && (ch === ',' || ch === '}' || ch === ']'))
|
|
380
|
+
return j;
|
|
381
|
+
}
|
|
382
|
+
return src.length;
|
|
383
|
+
}
|
|
384
|
+
/** Skip to the matching ']' for a raw array span. */
|
|
385
|
+
function skipToEndOfArray(src, i) {
|
|
386
|
+
let depth = 0;
|
|
387
|
+
let inStr = null;
|
|
388
|
+
let esc = false;
|
|
389
|
+
for (let j = i; j < src.length; j++) {
|
|
390
|
+
const ch = src[j];
|
|
391
|
+
if (inStr) {
|
|
392
|
+
if (esc) {
|
|
393
|
+
esc = false;
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
if (ch === '\\') {
|
|
397
|
+
esc = true;
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (ch === inStr)
|
|
401
|
+
inStr = null;
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
405
|
+
inStr = ch;
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
if (ch === '[')
|
|
409
|
+
depth++;
|
|
410
|
+
if (ch === ']') {
|
|
411
|
+
depth--;
|
|
412
|
+
if (depth === 0)
|
|
413
|
+
return j + 1;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return src.length;
|
|
417
|
+
}
|
|
285
418
|
function serializeObject(obj) {
|
|
286
419
|
return Object.keys(obj)
|
|
287
420
|
.map((k) => `${isBareKey(k) ? k : JSON.stringify(k)}: ${serializeValue(obj[k])}`)
|
|
@@ -291,6 +424,9 @@ function isBareKey(k) {
|
|
|
291
424
|
return /^[a-zA-Z_$][\w$]*$/.test(k);
|
|
292
425
|
}
|
|
293
426
|
function serializeValue(v) {
|
|
427
|
+
if (v !== null && typeof v === 'object' && '__veskRaw' in v) {
|
|
428
|
+
return String(v.__veskRaw);
|
|
429
|
+
}
|
|
294
430
|
if (v === null)
|
|
295
431
|
return 'null';
|
|
296
432
|
if (typeof v === 'string')
|
package/dist/dev-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAA6C,MAAM,WAAW,CAAC;AAOjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAI7C,OAAO,KAAK,EAAa,gBAAgB,EAAwB,MAAM,yBAAyB,CAAC;AAgBjG;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,IAAI,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC;IAC9C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB;+EAC2E;IAC3E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,IAAI,WAAW,CAEhD;AAuCD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AAkBD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,mHAAmH;IACnH,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B;;8BAE0B;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,WAAW,CAAC;IAChC,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CAChH,CAUA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAa3C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIrD;AA8CD,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAA6C,MAAM,WAAW,CAAC;AAOjG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAI7C,OAAO,KAAK,EAAa,gBAAgB,EAAwB,MAAM,yBAAyB,CAAC;AAgBjG;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,IAAI,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC;IAC9C,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACxD,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB;+EAC2E;IAC3E,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,IAAI,WAAW,CAEhD;AAuCD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AAkBD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,mHAAmH;IACnH,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC7B;;8BAE0B;IAC1B,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,WAAW,CAAC;IAChC,8EAA8E;IAC9E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,wBAAwB,GAAG;IACvE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CAChH,CAUA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAa3C;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIrD;AA8CD,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAikBvG"}
|
package/dist/dev-server.js
CHANGED
|
@@ -260,7 +260,10 @@ export async function startDevServer(appDir, options) {
|
|
|
260
260
|
async function buildAdapterAgenticProvider(cfg) {
|
|
261
261
|
const providerName = String(cfg.provider || loadAgenticConfig(agenticProjectDir).provider || 'openai');
|
|
262
262
|
const apiKey = cfg.apiKey || getApiKey(agenticProjectDir, providerName) || '';
|
|
263
|
-
const model = cfg.model || loadAgenticConfig(agenticProjectDir).model ||
|
|
263
|
+
const model = cfg.model || loadAgenticConfig(agenticProjectDir).model || '';
|
|
264
|
+
if (!model) {
|
|
265
|
+
throw new Error('no model configured — open Settings → Agentic and pick a model');
|
|
266
|
+
}
|
|
264
267
|
const baseUrl = cfg.baseUrl || loadAgenticConfig(agenticProjectDir).baseUrl || undefined;
|
|
265
268
|
const maxTokens = typeof cfg.maxTokens === 'number' ? cfg.maxTokens : undefined;
|
|
266
269
|
if (providerName === 'anthropic')
|
|
@@ -652,6 +655,41 @@ export async function startDevServer(appDir, options) {
|
|
|
652
655
|
});
|
|
653
656
|
const hmr = createHmrServer(server, appDir, devDir, componentMap);
|
|
654
657
|
hmrSession = hmr;
|
|
658
|
+
// ── Console streaming to devtool ────────────────────────────────────────
|
|
659
|
+
// Read `logs` from vesk.config and wire up server-side console interception
|
|
660
|
+
// so console.log/warn/error/info/debug are forwarded to the devtool Log tab.
|
|
661
|
+
{
|
|
662
|
+
let logsLevels = null;
|
|
663
|
+
try {
|
|
664
|
+
const { readConfig } = await import('@vesk/adapter/src/dev-config');
|
|
665
|
+
const cfgResult = await readConfig(resolve(appDir, '..'));
|
|
666
|
+
const logsCfg = cfgResult.config?.logs;
|
|
667
|
+
if (logsCfg === false) {
|
|
668
|
+
logsLevels = null; // disabled
|
|
669
|
+
}
|
|
670
|
+
else if (typeof logsCfg === 'object' && logsCfg !== null) {
|
|
671
|
+
logsLevels = { log: true, warn: true, error: true, info: true, debug: true, ...logsCfg };
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
logsLevels = { log: true, warn: true, error: true, info: true, debug: true };
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
catch {
|
|
678
|
+
logsLevels = { log: true, warn: true, error: true, info: true, debug: true };
|
|
679
|
+
}
|
|
680
|
+
if (logsLevels) {
|
|
681
|
+
const origFns = {};
|
|
682
|
+
for (const lvl of ['log', 'warn', 'error', 'info', 'debug']) {
|
|
683
|
+
origFns[lvl] = console[lvl].bind(console);
|
|
684
|
+
console[lvl] = (...args) => {
|
|
685
|
+
origFns[lvl](...args);
|
|
686
|
+
if (!logsLevels[lvl])
|
|
687
|
+
return;
|
|
688
|
+
hmr.broadcast('console', { level: lvl, message: args.map(String).join(' ') });
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
655
693
|
const srcDir = resolve(appDir, '..', 'src');
|
|
656
694
|
try {
|
|
657
695
|
if (existsSync(srcDir)) {
|
package/dist/hmr.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAUxC,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEvG,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,yBAAyB,CAAC;AAIzE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAaD,wBAAgB,WAAW,IAAI;IAC7B,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAQA;AAED,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,wBAA6B,GAClC,eAAe,CAsEjB;
|
|
1
|
+
{"version":3,"file":"hmr.d.ts","sourceRoot":"","sources":["../src/hmr.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAUxC,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAEvG,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,yBAAyB,CAAC;AAIzE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAaD,wBAAgB,WAAW,IAAI;IAC7B,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAQA;AAED,MAAM,WAAW,wBAAwB;IACvC,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,wBAA6B,GAClC,eAAe,CAsEjB;AAoRD,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC;IACD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAClE,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvH,WAAW,EAAE,MAAM,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CACnD,CAyJA"}
|
package/dist/hmr.js
CHANGED
|
@@ -6,7 +6,7 @@ import { compileClient } from '@vesk/compiler/src/client-codegen';
|
|
|
6
6
|
import { buildHmrEvalSnippet } from './client-bundle';
|
|
7
7
|
import { resolveComponentName, randomToken } from '@vesk/compiler/src/server-codegen';
|
|
8
8
|
import { resolveErrorFile } from '@vesk/adapter/src/ssr-function';
|
|
9
|
-
import { resolveCssUrls,
|
|
9
|
+
import { resolveCssUrls, hasBuiltGlobalCss } from '@vesk/adapter/src/css';
|
|
10
10
|
import { isAllowedWsUpgrade } from '@vesk/adapter/src/paths';
|
|
11
11
|
import { parseCompilerError, buildCodeframe } from '@vesk/adapter/src/error-codeframe';
|
|
12
12
|
import { suggestFor } from '@vesk/adapter/src/error-tips';
|
|
@@ -243,10 +243,8 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
243
243
|
const ancestorLayouts = options?.ancestorLayouts || [];
|
|
244
244
|
const headExtra = options?.headExtra || null;
|
|
245
245
|
const pagePath = resolve(appDir, routeNode.sourceDir, 'page.vsk');
|
|
246
|
-
const layoutPath = resolve(appDir, routeNode.sourceDir, 'layout.vsk');
|
|
247
246
|
const cssUrls = resolveCssUrls({
|
|
248
|
-
|
|
249
|
-
userCss: hasUserCss(appDir),
|
|
247
|
+
enabled: hasBuiltGlobalCss(outDir),
|
|
250
248
|
});
|
|
251
249
|
const cssOption = cssUrls.length > 0 ? `, cssUrls: ${JSON.stringify(cssUrls)}` : '';
|
|
252
250
|
const headExtraOption = headExtra ? `, headExtra: ${JSON.stringify(headExtra)}` : '';
|
|
@@ -255,10 +253,25 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
255
253
|
const name = routeName(parts);
|
|
256
254
|
const funcDir = resolve(outDir, 'server', 'functions');
|
|
257
255
|
const funcPath = resolve(funcDir, `${name}.js`);
|
|
258
|
-
const hasLayout = !!routeNode.layout;
|
|
259
|
-
const hasAncestorLayout = ancestorLayouts.length > 0;
|
|
260
256
|
const pageSrc = readFileSync(pagePath, 'utf-8');
|
|
261
257
|
const pageComp = extractCompName(pageSrc) || 'Page';
|
|
258
|
+
const layoutStack = [
|
|
259
|
+
...ancestorLayouts.map((a) => ({ sourceDir: a.sourceDir, layoutCompName: a.layoutCompName })),
|
|
260
|
+
...(routeNode.layout ? [{ sourceDir: routeNode.sourceDir, layoutCompName: routeNode.layout }] : []),
|
|
261
|
+
];
|
|
262
|
+
const layoutDecls = [];
|
|
263
|
+
for (const entry of layoutStack) {
|
|
264
|
+
const entryPath = resolve(appDir, entry.sourceDir, 'layout.vsk');
|
|
265
|
+
const entrySrc = readFileSync(entryPath, 'utf-8');
|
|
266
|
+
const entryComp = extractCompName(entrySrc) || 'Layout';
|
|
267
|
+
const escaped = escapeSource(entrySrc);
|
|
268
|
+
layoutDecls.push({
|
|
269
|
+
src: `\`${escaped}\``,
|
|
270
|
+
comp: JSON.stringify(entryComp),
|
|
271
|
+
path: JSON.stringify(entryPath),
|
|
272
|
+
compiled: `(() => { try { setVskHydrate(true); return compileFile(\`${escaped}\`, { sourcePath: ${JSON.stringify(entryPath)} }); } catch { return null; } finally { setVskHydrate(false); } })()`,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
262
275
|
const errorPath = resolveErrorFile(routeNode.sourceDir, appDir);
|
|
263
276
|
const errorSrc = errorPath ? readFileSync(errorPath, 'utf-8') : null;
|
|
264
277
|
const errorComp = errorPath ? (extractCompName(errorSrc) || 'Error') : null;
|
|
@@ -268,28 +281,15 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
268
281
|
const clientScriptOption = ', clientScriptUrl: "/_vesk/static/client.js"';
|
|
269
282
|
const dataScriptOption = ', externalDataScript: storeDataScriptGlobal';
|
|
270
283
|
let src = '';
|
|
271
|
-
if (
|
|
272
|
-
const layoutSrc = readFileSync(layoutPath, 'utf-8');
|
|
273
|
-
const layoutComp = extractCompName(layoutSrc) || 'Layout';
|
|
274
|
-
src = `const _layoutSrc = \`${escapeSource(layoutSrc)}\`;\nconst _pageSrc = \`${escapeSource(pageSrc)}\`;\n`;
|
|
275
|
-
src += `const _layoutComp = ${JSON.stringify(layoutComp)};\nconst _pageComp = ${JSON.stringify(pageComp)};\n`;
|
|
276
|
-
src += `const _layoutPath = ${JSON.stringify(layoutPath)};\nconst _pagePath = ${JSON.stringify(pagePath)};\n`;
|
|
277
|
-
src += `const _layoutCompiled = (() => { try { setVskHydrate(true); return compileFile(_layoutSrc, { sourcePath: _layoutPath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
278
|
-
src += `const _pageCompiled = (() => { try { setVskHydrate(true); return compileFile(_pageSrc, { sourcePath: _pagePath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
279
|
-
src += errorVars;
|
|
280
|
-
}
|
|
281
|
-
else if (hasAncestorLayout) {
|
|
282
|
-
const outerLayout = ancestorLayouts[0];
|
|
283
|
-
const outerLayoutPath = resolve(appDir, outerLayout.sourceDir, 'layout.vsk');
|
|
284
|
-
const outerLayoutSrc = readFileSync(outerLayoutPath, 'utf-8');
|
|
285
|
-
const outerLayoutComp = extractCompName(outerLayoutSrc) || 'Layout';
|
|
284
|
+
if (layoutDecls.length > 0) {
|
|
286
285
|
src = `const _pageSrc = \`${escapeSource(pageSrc)}\`;\n`;
|
|
287
286
|
src += `const _pageComp = ${JSON.stringify(pageComp)};\n`;
|
|
288
|
-
src += `const
|
|
289
|
-
src += `const _layoutComp = ${JSON.stringify(outerLayoutComp)};\n`;
|
|
290
|
-
src += `const _layoutPath = ${JSON.stringify(outerLayoutPath)};\nconst _pagePath = ${JSON.stringify(pagePath)};\n`;
|
|
291
|
-
src += `const _layoutCompiled = (() => { try { setVskHydrate(true); return compileFile(_layoutSrc, { sourcePath: _layoutPath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
287
|
+
src += `const _pagePath = ${JSON.stringify(pagePath)};\n`;
|
|
292
288
|
src += `const _pageCompiled = (() => { try { setVskHydrate(true); return compileFile(_pageSrc, { sourcePath: _pagePath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
289
|
+
src += `const _layoutSrcList = [\n${layoutDecls.map((d) => ' ' + d.src + ',').join('\n')}\n];\n`;
|
|
290
|
+
src += `const _layoutCompList = [${layoutDecls.map((d) => d.comp).join(', ')}];\n`;
|
|
291
|
+
src += `const _layoutPathList = [${layoutDecls.map((d) => d.path).join(', ')}];\n`;
|
|
292
|
+
src += `const _layoutCompiledList = [\n${layoutDecls.map((d) => ' ' + d.compiled + ',').join('\n')}\n];\n`;
|
|
293
293
|
src += errorVars;
|
|
294
294
|
}
|
|
295
295
|
else {
|
|
@@ -316,7 +316,7 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
316
316
|
registryCode = 'const __componentRegistry = new Map();\n';
|
|
317
317
|
}
|
|
318
318
|
let renderCode;
|
|
319
|
-
if (
|
|
319
|
+
if (layoutDecls.length > 0) {
|
|
320
320
|
renderCode = [
|
|
321
321
|
' let page;',
|
|
322
322
|
' let caughtError = null;',
|
|
@@ -329,24 +329,14 @@ function regenerateSsrFunction(routeNode, appDir, outDir, componentMap, options)
|
|
|
329
329
|
" const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
|
|
330
330
|
" page = { body: await __renderErrorBody({ params, statusCode: 500, error: message, stack, url: url.href }), head: '' };",
|
|
331
331
|
' }',
|
|
332
|
-
|
|
333
|
-
"
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
' let page;',
|
|
339
|
-
' let caughtError = null;',
|
|
340
|
-
' try {',
|
|
341
|
-
' page = await renderPage(_pageSrc, _pageComp, { params }, __componentRegistry, { hydrate: true, cached: _pageCompiled, sourcePath: _pagePath });',
|
|
342
|
-
' } catch (err) {',
|
|
343
|
-
" if (err && (err.name === 'NotFoundError' || err.name === 'Redirect')) throw err;",
|
|
344
|
-
' caughtError = err;',
|
|
345
|
-
" const message = err && typeof err === 'object' && 'message' in err ? String(err.message) : String(err);",
|
|
346
|
-
" const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
|
|
347
|
-
" page = { body: await __renderErrorBody({ params, statusCode: 500, error: message, stack, url: url.href }), head: '' };",
|
|
332
|
+
" let _body = (caughtError ? '<!--vesk-ssr-error:' + (caughtError && typeof caughtError === 'object' && 'message' in caughtError ? encodeURIComponent(String(caughtError.message)) : '') + '-->' : '') + page.body;",
|
|
333
|
+
" let _head = page.head || '';",
|
|
334
|
+
" for (let _i = _layoutSrcList.length - 1; _i > 0; _i--) {",
|
|
335
|
+
" const _inner = await renderPage(_layoutSrcList[_i], _layoutCompList[_i], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[_i], sourcePath: _layoutPathList[_i] });",
|
|
336
|
+
' _body = _inner.body;',
|
|
337
|
+
" if (_inner.head) _head = _inner.head + _head;",
|
|
348
338
|
' }',
|
|
349
|
-
|
|
339
|
+
" const html = await renderFullPage(_layoutSrcList[0], _layoutCompList[0], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[0]" + bakedOptions + clientScriptOption + dataScriptOption + ', pageHead: _head, sourcePath: _layoutPathList[0] });',
|
|
350
340
|
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
351
341
|
].join('\n');
|
|
352
342
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACe,YAAY,EAAE,WAAW,EAC7B,UAAU,EAChC,MAAM,yBAAyB,CAAC;AAiBjC;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AACD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,iBAAiB,EAAE,GAAG,IAAI,GAAG,SAAS,GAC9C,UAAU,EAAE,CAQd;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,UAAU,EAAE,EACrB,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GACxC,UAAU,EAAE,CAGd;AA+BD,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACe,YAAY,EAAE,WAAW,EAC7B,UAAU,EAChC,MAAM,yBAAyB,CAAC;AAiBjC;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AACD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,UAAU,EAAE,EACrB,OAAO,EAAE,iBAAiB,EAAE,GAAG,IAAI,GAAG,SAAS,GAC9C,UAAU,EAAE,CAQd;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,UAAU,EAAE,EACrB,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GACxC,UAAU,EAAE,CAGd;AA+BD,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAuTpG;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIhE,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,yBAAyB,EACzB,eAAe,GAChB,MAAM,2BAA2B,CAAC;AACnC,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,2BAA2B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { resolve, dirname, relative, basename } from 'node:path';
|
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { bundleRuntime } from '@vesk/adapter/src/runtime-bundle';
|
|
5
5
|
import { generateSsrFunction } from '@vesk/adapter/src/ssr-function';
|
|
6
|
-
import { resolveUserCssPath,
|
|
6
|
+
import { resolveUserCssPath, isTailwindPlugin, resolveCssUrls, hasBuiltGlobalCss } from '@vesk/adapter/src/css';
|
|
7
7
|
import { collectActionIds } from '@vesk/compiler/src/actions';
|
|
8
8
|
import { generateApiFunction } from '@vesk/adapter/src/api-function';
|
|
9
9
|
import { compileMiddleware, compileMiddlewareCode } from '@vesk/adapter/src/middleware';
|
|
@@ -153,43 +153,25 @@ export async function build(appDir, options) {
|
|
|
153
153
|
const cssSourcePath = resolveUserCssPath(appDir);
|
|
154
154
|
if (cssSourcePath !== null) {
|
|
155
155
|
const cssContent = readFileSync(cssSourcePath, 'utf-8');
|
|
156
|
-
const
|
|
157
|
-
const userCssTarget = resolve(outDir, 'static', 'global.css');
|
|
158
|
-
writeFileSync(userCssTarget, userCss, 'utf-8');
|
|
159
|
-
console.error(`vesk build: css → static/global.css (${userCss.length} bytes)`);
|
|
160
|
-
const twCssTarget = resolve(outDir, 'static', '_tailwind.css');
|
|
156
|
+
const cssTarget = resolve(outDir, 'static', 'global.css');
|
|
161
157
|
const tailwindActive = isTailwindPlugin(pluginsPipelines);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
console.error('vesk build: css → static/_tailwind.css (empty, tailwind plugin inactive)');
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
let twCss = cssContent;
|
|
158
|
+
let finalCss = cssContent;
|
|
159
|
+
if (tailwindActive) {
|
|
168
160
|
for (const plugin of pluginsPipelines) {
|
|
169
161
|
if (typeof plugin.onCSS === 'function') {
|
|
170
|
-
const result = await plugin.onCSS(
|
|
162
|
+
const result = await plugin.onCSS(finalCss, cssSourcePath);
|
|
171
163
|
if (result !== null && typeof result === 'string') {
|
|
172
|
-
|
|
164
|
+
finalCss = result;
|
|
173
165
|
}
|
|
174
166
|
}
|
|
175
167
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
else {
|
|
185
|
-
writeFileSync(twCssTarget, twCss, 'utf-8');
|
|
186
|
-
console.error(`vesk build: css → static/_tailwind.css (${twCss.length} bytes, tailwind partially unresolved)`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
writeFileSync(twCssTarget, twCss, 'utf-8');
|
|
191
|
-
console.error(`vesk build: css → static/_tailwind.css (${twCss.length} bytes)`);
|
|
192
|
-
}
|
|
168
|
+
}
|
|
169
|
+
writeFileSync(cssTarget, finalCss, 'utf-8');
|
|
170
|
+
if (tailwindActive) {
|
|
171
|
+
console.error(`vesk build: css → static/global.css (${finalCss.length} bytes)`);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
console.error(`vesk build: css → static/global.css (${finalCss.length} bytes, tailwind plugin inactive)`);
|
|
193
175
|
}
|
|
194
176
|
}
|
|
195
177
|
const { scanRoutes, scanComponents } = await resolveCompilerApi('router.js');
|
|
@@ -311,8 +293,7 @@ export async function build(appDir, options) {
|
|
|
311
293
|
if (options?.ssg) {
|
|
312
294
|
const { generateSsgRoutes } = await import('./static.js');
|
|
313
295
|
const cssUrls = resolveCssUrls({
|
|
314
|
-
|
|
315
|
-
userCss: hasUserCss(appDir),
|
|
296
|
+
enabled: hasBuiltGlobalCss(outDir),
|
|
316
297
|
});
|
|
317
298
|
prerenderedRoutes = await generateSsgRoutes(routeTree, appDir, outDir, pluginsPipelines, pluginHeadExtra, cssUrls);
|
|
318
299
|
console.error(`vesk build: ssg → prerendered/ (${prerenderedRoutes.length} pages)`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../src/prod-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2D,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AA+CjG,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AA+FD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"prod-server.d.ts","sourceRoot":"","sources":["../src/prod-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2D,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AA+CjG,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIzE;AA+FD,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkcxI"}
|
package/dist/prod-server.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
6
6
|
import { createRateLimiter, resolveComponentName, safeJsonForScript, getClientProtocol, DEFAULT_MAX_BODY_BYTES } from '@vesk/compiler/src/server-codegen';
|
|
7
7
|
import { securityHeaders } from '@vesk/compiler/src/server-utils';
|
|
8
8
|
import { resolveWithin, installMdReadHook } from '@vesk/adapter/src/paths';
|
|
9
|
-
import { resolveCssUrls,
|
|
9
|
+
import { resolveCssUrls, hasBuiltGlobalCss } from '@vesk/adapter/src/css';
|
|
10
10
|
const _require = createRequire(import.meta.url);
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
async function readBody(req, maxBytes = DEFAULT_MAX_BODY_BYTES) {
|
|
@@ -436,8 +436,7 @@ export async function startProdServer(outDir, options) {
|
|
|
436
436
|
}
|
|
437
437
|
const appDir = resolve(projectDir, 'app');
|
|
438
438
|
const pageCssUrls = resolveCssUrls({
|
|
439
|
-
|
|
440
|
-
userCss: hasUserCss(appDir),
|
|
439
|
+
enabled: hasBuiltGlobalCss(outDir),
|
|
441
440
|
});
|
|
442
441
|
const nfPath = resolve(appDir, 'not-found.vsk');
|
|
443
442
|
let notFoundHtml = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-function.d.ts","sourceRoot":"","sources":["../src/ssr-function.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAW7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjF;AAiDD,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,kBAAkB,GAC3B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"ssr-function.d.ts","sourceRoot":"","sources":["../src/ssr-function.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAkB,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAW7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjF;AAiDD,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,OAAO,CAAC,EAAE,kBAAkB,GAC3B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAoYtD"}
|
package/dist/ssr-function.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from 'node:fs';
|
|
2
2
|
import { resolve, relative, join } from 'node:path';
|
|
3
3
|
import { resolveComponentName } from '@vesk/compiler/src/server-codegen';
|
|
4
|
-
import { resolveCssUrls,
|
|
4
|
+
import { resolveCssUrls, hasBuiltGlobalCss } from '@vesk/adapter/src/css';
|
|
5
5
|
function escapeSource(src) {
|
|
6
6
|
return src
|
|
7
7
|
.replace(/\\/g, '\\\\')
|
|
@@ -75,22 +75,35 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
75
75
|
const middlewareCode = options?.middlewareCode || null;
|
|
76
76
|
const headExtra = options?.headExtra || null;
|
|
77
77
|
const pagePath = resolve(appDir, routeNode.sourceDir, 'page.vsk');
|
|
78
|
-
const layoutPath = resolve(appDir, routeNode.sourceDir, 'layout.vsk');
|
|
79
78
|
const parts = routeNode.fullPath.split('/').filter(Boolean);
|
|
80
79
|
const name = routeName(parts);
|
|
81
80
|
const funcDir = resolve(outDir, 'server', 'functions');
|
|
82
81
|
const funcPath = resolve(funcDir, `${name}.js`);
|
|
83
82
|
const cssUrls = resolveCssUrls({
|
|
84
|
-
|
|
85
|
-
userCss: hasUserCss(appDir),
|
|
83
|
+
enabled: hasBuiltGlobalCss(outDir),
|
|
86
84
|
});
|
|
87
85
|
const cssOption = cssUrls.length > 0 ? `, cssUrls: ${JSON.stringify(cssUrls)}` : '';
|
|
88
86
|
// Static head snippet baked from the active onHead plugins — merged into
|
|
89
87
|
// every rendered head at request time (page tags win via mergeHeadHtml).
|
|
90
88
|
const headExtraOption = headExtra ? `, headExtra: ${JSON.stringify(headExtra)}` : '';
|
|
91
89
|
const bakedOptions = cssOption + headExtraOption;
|
|
92
|
-
const
|
|
93
|
-
|
|
90
|
+
const layoutStack = [
|
|
91
|
+
...ancestorLayouts.map((a) => ({ sourceDir: a.sourceDir, layoutCompName: a.layoutCompName })),
|
|
92
|
+
...(routeNode.layout ? [{ sourceDir: routeNode.sourceDir, layoutCompName: routeNode.layout }] : []),
|
|
93
|
+
];
|
|
94
|
+
const layoutDecls = [];
|
|
95
|
+
for (const entry of layoutStack) {
|
|
96
|
+
const entryPath = resolve(appDir, entry.sourceDir, 'layout.vsk');
|
|
97
|
+
const entrySrc = readFileSync(entryPath, 'utf-8');
|
|
98
|
+
const entryComp = extractCompName(entrySrc) || 'Layout';
|
|
99
|
+
const escaped = escapeSource(entrySrc);
|
|
100
|
+
layoutDecls.push({
|
|
101
|
+
src: `\`${escaped}\``,
|
|
102
|
+
comp: JSON.stringify(entryComp),
|
|
103
|
+
path: JSON.stringify(entryPath),
|
|
104
|
+
compiled: `(() => { try { setVskHydrate(true); return compileFile(\`${escaped}\`, { sourcePath: ${JSON.stringify(entryPath)} }); } catch { return null; } finally { setVskHydrate(false); } })()`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
94
107
|
const pageSrc = readFileSync(pagePath, 'utf-8');
|
|
95
108
|
const pageComp = extractCompName(pageSrc) || 'Page';
|
|
96
109
|
const errorPath = resolveErrorFile(routeNode.sourceDir, appDir);
|
|
@@ -100,28 +113,15 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
100
113
|
? `const _errorSrc = \`${escapeSource(errorSrc)}\`;\nconst _errorComp = ${JSON.stringify(errorComp)};\nconst _errorPath = ${JSON.stringify(errorPath)};\nconst _errorCompiled = (() => { try { setVskHydrate(true); return compileFile(_errorSrc, { sourcePath: _errorPath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`
|
|
101
114
|
: 'const _errorSrc = null;\nconst _errorComp = null;\nconst _errorPath = null;\nconst _errorCompiled = null;\n';
|
|
102
115
|
let src = '';
|
|
103
|
-
if (
|
|
104
|
-
const layoutSrc = readFileSync(layoutPath, 'utf-8');
|
|
105
|
-
const layoutComp = extractCompName(layoutSrc) || 'Layout';
|
|
106
|
-
src = `const _layoutSrc = \`${escapeSource(layoutSrc)}\`;\nconst _pageSrc = \`${escapeSource(pageSrc)}\`;\n`;
|
|
107
|
-
src += `const _layoutComp = ${JSON.stringify(layoutComp)};\nconst _pageComp = ${JSON.stringify(pageComp)};\n`;
|
|
108
|
-
src += `const _layoutPath = ${JSON.stringify(layoutPath)};\nconst _pagePath = ${JSON.stringify(pagePath)};\n`;
|
|
109
|
-
src += `const _layoutCompiled = (() => { try { setVskHydrate(true); return compileFile(_layoutSrc, { sourcePath: _layoutPath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
110
|
-
src += `const _pageCompiled = (() => { try { setVskHydrate(true); return compileFile(_pageSrc, { sourcePath: _pagePath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
111
|
-
src += errorVars;
|
|
112
|
-
}
|
|
113
|
-
else if (hasAncestorLayout) {
|
|
114
|
-
const outerLayout = ancestorLayouts[0];
|
|
115
|
-
const outerLayoutPath = resolve(appDir, outerLayout.sourceDir, 'layout.vsk');
|
|
116
|
-
const outerLayoutSrc = readFileSync(outerLayoutPath, 'utf-8');
|
|
117
|
-
const outerLayoutComp = extractCompName(outerLayoutSrc) || 'Layout';
|
|
116
|
+
if (layoutDecls.length > 0) {
|
|
118
117
|
src = `const _pageSrc = \`${escapeSource(pageSrc)}\`;\n`;
|
|
119
118
|
src += `const _pageComp = ${JSON.stringify(pageComp)};\n`;
|
|
120
|
-
src += `const
|
|
121
|
-
src += `const _layoutComp = ${JSON.stringify(outerLayoutComp)};\n`;
|
|
122
|
-
src += `const _layoutPath = ${JSON.stringify(outerLayoutPath)};\nconst _pagePath = ${JSON.stringify(pagePath)};\n`;
|
|
123
|
-
src += `const _layoutCompiled = (() => { try { setVskHydrate(true); return compileFile(_layoutSrc, { sourcePath: _layoutPath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
119
|
+
src += `const _pagePath = ${JSON.stringify(pagePath)};\n`;
|
|
124
120
|
src += `const _pageCompiled = (() => { try { setVskHydrate(true); return compileFile(_pageSrc, { sourcePath: _pagePath }); } catch { return null; } finally { setVskHydrate(false); } })();\n`;
|
|
121
|
+
src += `const _layoutSrcList = [\n${layoutDecls.map((d) => ' ' + d.src + ',').join('\n')}\n];\n`;
|
|
122
|
+
src += `const _layoutCompList = [${layoutDecls.map((d) => d.comp).join(', ')}];\n`;
|
|
123
|
+
src += `const _layoutPathList = [${layoutDecls.map((d) => d.path).join(', ')}];\n`;
|
|
124
|
+
src += `const _layoutCompiledList = [\n${layoutDecls.map((d) => ' ' + d.compiled + ',').join('\n')}\n];\n`;
|
|
125
125
|
src += errorVars;
|
|
126
126
|
}
|
|
127
127
|
else {
|
|
@@ -150,7 +150,7 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
150
150
|
registryCode = 'const __componentRegistry = new Map();\n';
|
|
151
151
|
}
|
|
152
152
|
let htmlFnCode;
|
|
153
|
-
if (
|
|
153
|
+
if (layoutDecls.length > 0) {
|
|
154
154
|
htmlFnCode = [
|
|
155
155
|
'async function __renderErrorBody(props) {',
|
|
156
156
|
' if (!_errorSrc) throw props.error || new Error("Internal Server Error");',
|
|
@@ -176,7 +176,14 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
176
176
|
" const stack = err && typeof err === 'object' && 'stack' in err ? String(err.stack) : '';",
|
|
177
177
|
" page = { body: await __renderErrorBody({ params, statusCode: 500, error: __expose ? message : 'Internal Server Error', stack: __expose ? stack : '', url: requestUrl || '' }), head: '' };",
|
|
178
178
|
' }',
|
|
179
|
-
|
|
179
|
+
' let _body = (caughtError ? \'<!--vesk-ssr-error:\' + (caughtError && typeof caughtError === \'object\' && \'message\' in caughtError ? encodeURIComponent(__expose ? String(caughtError.message) : \'Internal Server Error\') : \'\') + \'-->\' : \'\') + page.body;',
|
|
180
|
+
' let _head = page.head || \'\';',
|
|
181
|
+
' for (let _i = _layoutSrcList.length - 1; _i > 0; _i--) {',
|
|
182
|
+
' const _inner = await renderPage(_layoutSrcList[_i], _layoutCompList[_i], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[_i], sourcePath: _layoutPathList[_i] });',
|
|
183
|
+
' _body = _inner.body;',
|
|
184
|
+
' if (_inner.head) _head = _inner.head + _head;',
|
|
185
|
+
' }',
|
|
186
|
+
' const html = await renderFullPage(_layoutSrcList[0], _layoutCompList[0], { params, children: _body }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[0]' + bakedOptions + clientScriptOption + dataScriptOption + ', pageHead: _head, sourcePath: _layoutPathList[0] });',
|
|
180
187
|
" return new Response(html, { headers: { 'Content-Type': 'text/html' }, status: caughtError ? 500 : 200 });",
|
|
181
188
|
' });',
|
|
182
189
|
'}',
|
|
@@ -228,7 +235,7 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
228
235
|
}
|
|
229
236
|
let dataCode;
|
|
230
237
|
const exposeErr = "process.env.NODE_ENV !== 'production'";
|
|
231
|
-
if (
|
|
238
|
+
if (layoutDecls.length > 0) {
|
|
232
239
|
dataCode = [
|
|
233
240
|
" if (request.headers.get('x-vesk-data') === '1') {",
|
|
234
241
|
' let dataPage;',
|
|
@@ -239,8 +246,12 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
239
246
|
' const message = err && typeof err === \'object\' && \'message\' in err ? String(err.message) : String(err);',
|
|
240
247
|
` return new Response(JSON.stringify({ error: ${exposeErr} ? message : 'Internal Server Error' }), { status: 500, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store', Vary: 'x-vesk-data' } });`,
|
|
241
248
|
' }',
|
|
242
|
-
'
|
|
243
|
-
|
|
249
|
+
' let _dataHead = dataPage.head || \'\';',
|
|
250
|
+
' for (let _i = _layoutSrcList.length - 1; _i >= 0; _i--) {',
|
|
251
|
+
' const _dl = await renderPage(_layoutSrcList[_i], _layoutCompList[_i], { params, children: \'\' }, __componentRegistry, { hydrate: true, cached: _layoutCompiledList[_i], sourcePath: _layoutPathList[_i] });',
|
|
252
|
+
' _dataHead = (_dl.head || \'\') + _dataHead;',
|
|
253
|
+
' }',
|
|
254
|
+
" return new Response(JSON.stringify({ path: url.pathname, params, props: dataPage.props || { params }, head: _dataHead }), {",
|
|
244
255
|
" headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store', Vary: 'x-vesk-data' },",
|
|
245
256
|
' });',
|
|
246
257
|
' }',
|
|
@@ -308,12 +319,12 @@ export function generateSsrFunction(routeNode, appDir, outDir, componentMap, opt
|
|
|
308
319
|
].join('\n');
|
|
309
320
|
}
|
|
310
321
|
let registerActionsCode;
|
|
311
|
-
if (
|
|
322
|
+
if (layoutDecls.length > 0) {
|
|
312
323
|
registerActionsCode = [
|
|
313
324
|
'async function __registerActions() {',
|
|
314
325
|
' if (__actionsRegistered) return;',
|
|
315
326
|
' __actionsRegistered = true;',
|
|
316
|
-
' compileFile(
|
|
327
|
+
' for (let _i = 0; _i < _layoutSrcList.length; _i++) compileFile(_layoutSrcList[_i], { sourcePath: _layoutPathList[_i] });',
|
|
317
328
|
' compileFile(_pageSrc, { sourcePath: _pagePath });',
|
|
318
329
|
'}',
|
|
319
330
|
'',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/adapter",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vesk adapter — builds deployable .vesk/ output for Deno and Node serverless",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"sharp": "^0.35.3"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@vesk/compiler": "^0.2.
|
|
27
|
-
"@vesk/runtime": "^0.2.
|
|
28
|
-
"@vesk/types": "^0.2.
|
|
26
|
+
"@vesk/compiler": "^0.2.18",
|
|
27
|
+
"@vesk/runtime": "^0.2.18",
|
|
28
|
+
"@vesk/types": "^0.2.18"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/ws": "^8.18.1",
|