@vesk/adapter 0.2.45 → 0.2.47
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 +0 -7
- package/dist/client-bundle.d.ts.map +1 -1
- package/dist/client-bundle.js +56 -27
- package/dist/image-pipeline.d.ts.map +1 -1
- package/dist/image-pipeline.js +99 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -4
- package/package.json +4 -4
package/dist/client-bundle.d.ts
CHANGED
|
@@ -117,13 +117,6 @@ export declare function stripAndDemoteInOnePass(code: string): string;
|
|
|
117
117
|
* second full acorn parse on every file save.
|
|
118
118
|
*/
|
|
119
119
|
export declare function buildHmrEvalSnippet(code: string): string;
|
|
120
|
-
/**
|
|
121
|
-
* Removes matched top-level statements from a compiled client module using the
|
|
122
|
-
* parser's exact `start`/`end` offsets — never a text scan, so a doc sample
|
|
123
|
-
* stored inside a template literal can never be mistaken for a real statement.
|
|
124
|
-
* If the module cannot be parsed it is returned untouched (the compiler's own
|
|
125
|
-
* output is always valid ESM, so that branch is unreachable in practice).
|
|
126
|
-
*/
|
|
127
120
|
export declare function removeCompiledNodes(code: string, isTarget: (node: CompiledNode) => boolean): string;
|
|
128
121
|
export declare function generateClientBundle(routeTree: RouteNode[], appDir: string, componentMap?: Map<string, string>, options?: ClientBundleOptions): Promise<ClientBundleResult>;
|
|
129
122
|
export declare function buildRuntimeCode(runtimeDir: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAmF,MAAM,yBAAyB,CAAC;AAoCnL;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"client-bundle.d.ts","sourceRoot":"","sources":["../src/client-bundle.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAmF,MAAM,yBAAyB,CAAC;AAoCnL;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA4BhE;AAED;;;;;GAKG;AACH,UAAU,YAAY;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7B,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IACtH,WAAW,CAAC,EAAE;QACZ,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC1C,YAAY,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,CAAC,EAAE;gBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE;oBAAE,IAAI,CAAC,EAAE,MAAM,CAAC;oBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;iBAAE,CAAA;aAAE,CAAA;SAAE,CAAC,CAAC;KAC/F,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAmDD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAKzD;AAkCD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+B7D;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBlD;AA4MD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+B5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASxD;AA4CD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,GAAG,MAAM,CAoBnG;AAED,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,CAoc7B;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;AAoCD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAI/F"}
|
package/dist/client-bundle.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { build } from './esbuild-fallback.js';
|
|
6
6
|
import { stripCodeTypes } from '@vesk/compiler/src/strip-ts';
|
|
7
|
-
import { parse } from '@vesk/compiler/src/parser';
|
|
7
|
+
import { parse, parseGeneratedJs } from '@vesk/compiler/src/parser';
|
|
8
8
|
import { compileClient, compileClientBoth, nameAllocFor, vskComponentNames } from '@vesk/compiler/src/client-codegen';
|
|
9
9
|
import { VskComponentOwners } from '@vesk/compiler/src/vsk-collision';
|
|
10
10
|
import { resolveComponentName } from '@vesk/compiler/src/server-codegen';
|
|
@@ -59,13 +59,11 @@ function findRuntimeSrc(appDir) {
|
|
|
59
59
|
*/
|
|
60
60
|
export function extractRuntimeImportNames(code) {
|
|
61
61
|
const names = [];
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
catch {
|
|
62
|
+
// Shares the parse with the strip passes (same generated string, read-only
|
|
63
|
+
// AST) — see parseForStrip.
|
|
64
|
+
const ast = parseForStrip(code);
|
|
65
|
+
if (!ast)
|
|
67
66
|
return names;
|
|
68
|
-
}
|
|
69
67
|
const body = ast.body ?? [];
|
|
70
68
|
for (const raw of body) {
|
|
71
69
|
const node = raw;
|
|
@@ -482,13 +480,9 @@ function scopeFileContribution(code) {
|
|
|
482
480
|
* hot path used to run on every edit.
|
|
483
481
|
*/
|
|
484
482
|
export function stripAndDemoteInOnePass(code) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
ast = parse(code);
|
|
488
|
-
}
|
|
489
|
-
catch {
|
|
483
|
+
const ast = parseForStrip(code);
|
|
484
|
+
if (!ast)
|
|
490
485
|
return code;
|
|
491
|
-
}
|
|
492
486
|
const body = ast.body ?? [];
|
|
493
487
|
const edits = [];
|
|
494
488
|
for (const raw of body) {
|
|
@@ -548,14 +542,10 @@ export function buildHmrEvalSnippet(code) {
|
|
|
548
542
|
return '';
|
|
549
543
|
const scoped = `{\n${body}\n}`;
|
|
550
544
|
// Never trade a potential duplicate-binding error for a certain syntax
|
|
551
|
-
// error: if the scoped form does not parse, keep the unscoped body.
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
}
|
|
556
|
-
catch {
|
|
557
|
-
return body;
|
|
558
|
-
}
|
|
545
|
+
// error: if the scoped form does not parse, keep the unscoped body. The body
|
|
546
|
+
// is generated JS, so plain acorn is the right tool (parseGeneratedJs) and
|
|
547
|
+
// it must not go through the cache: this string is unique per call.
|
|
548
|
+
return parseGeneratedJs(scoped) !== null ? scoped : body;
|
|
559
549
|
}
|
|
560
550
|
/**
|
|
561
551
|
* Removes matched top-level statements from a compiled client module using the
|
|
@@ -564,14 +554,46 @@ export function buildHmrEvalSnippet(code) {
|
|
|
564
554
|
* If the module cannot be parsed it is returned untouched (the compiler's own
|
|
565
555
|
* output is always valid ESM, so that branch is unreachable in practice).
|
|
566
556
|
*/
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
557
|
+
/**
|
|
558
|
+
* Parsed-AST cache for the strip passes over GENERATED code.
|
|
559
|
+
*
|
|
560
|
+
* Every compiled file goes through several `removeCompiledNodes` passes with
|
|
561
|
+
* different predicates (`isVskImport`, `isRuntimeImport`, `isComponentExport`,
|
|
562
|
+
* ...) and each one used to re-parse the same string with the full `.vsk`
|
|
563
|
+
* pipeline. On a CPU profile of a 28-route build, parsing was ~70% of the
|
|
564
|
+
* whole build and the generated-code strips were the bulk of it. The ASTs are
|
|
565
|
+
* only read here (node.start/end plus the caller's predicate), so one parse can
|
|
566
|
+
* serve every pass over the same string.
|
|
567
|
+
*
|
|
568
|
+
* Bounded: cleared wholesale past the cap, because a watch session keeps
|
|
569
|
+
* calling this with new strings forever.
|
|
570
|
+
*/
|
|
571
|
+
const stripAstCache = new Map();
|
|
572
|
+
const STRIP_AST_CACHE_MAX = 512;
|
|
573
|
+
function parseForStrip(code) {
|
|
574
|
+
const hit = stripAstCache.get(code);
|
|
575
|
+
if (hit !== undefined)
|
|
576
|
+
return hit;
|
|
577
|
+
// Plain acorn for generated JS (see parseGeneratedJs); the `.vsk` pipeline
|
|
578
|
+
// only for the rare module it cannot read.
|
|
579
|
+
let ast = parseGeneratedJs(code);
|
|
580
|
+
if (!ast) {
|
|
581
|
+
try {
|
|
582
|
+
ast = parse(code);
|
|
583
|
+
}
|
|
584
|
+
catch {
|
|
585
|
+
ast = null;
|
|
586
|
+
}
|
|
571
587
|
}
|
|
572
|
-
|
|
588
|
+
if (stripAstCache.size >= STRIP_AST_CACHE_MAX)
|
|
589
|
+
stripAstCache.clear();
|
|
590
|
+
stripAstCache.set(code, ast);
|
|
591
|
+
return ast;
|
|
592
|
+
}
|
|
593
|
+
export function removeCompiledNodes(code, isTarget) {
|
|
594
|
+
const ast = parseForStrip(code);
|
|
595
|
+
if (!ast)
|
|
573
596
|
return code;
|
|
574
|
-
}
|
|
575
597
|
const ranges = [];
|
|
576
598
|
for (const raw of ast.body ?? []) {
|
|
577
599
|
const node = raw;
|
|
@@ -597,6 +619,7 @@ export function removeCompiledNodes(code, isTarget) {
|
|
|
597
619
|
export async function generateClientBundle(routeTree, appDir, componentMap, options) {
|
|
598
620
|
const runtimeDir = findRuntimeSrc(appDir);
|
|
599
621
|
let seen = new Set();
|
|
622
|
+
const __stats = { chunks: 0, compiled: 0, distinct: new Set(), parseMs: 0 };
|
|
600
623
|
const chunks = [];
|
|
601
624
|
const runtimeImportNames = new Set();
|
|
602
625
|
const cache = options?.cache;
|
|
@@ -720,6 +743,8 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
720
743
|
return;
|
|
721
744
|
}
|
|
722
745
|
compiledFiles++;
|
|
746
|
+
__stats.compiled++;
|
|
747
|
+
__stats.distinct.add(filePath);
|
|
723
748
|
let src = readFileSync(filePath, 'utf-8');
|
|
724
749
|
if (/content=["'][^"']*\.md["']/i.test(src)) {
|
|
725
750
|
src = inlineMdContentAttrs(src, dirname(filePath), guessProjectRoots(appDir));
|
|
@@ -729,7 +754,9 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
729
754
|
// One parse/IR pass feeds both client modes AND the component-name
|
|
730
755
|
// lookup — the dev hot path pays the acorn+TS parse once per edit
|
|
731
756
|
// instead of three times.
|
|
757
|
+
const __p0 = performance.now();
|
|
732
758
|
const { comp: rawComp, hyd: rawHyd, name: actualName, aliases, reexportPaths, componentNames } = compileClientBoth(src, null, filePath);
|
|
759
|
+
__stats.parseMs += performance.now() - __p0;
|
|
733
760
|
for (const cn of componentNames || [])
|
|
734
761
|
componentOwners.claim(cn, filePath);
|
|
735
762
|
// Cache keeps the import-carrying codes so a warm build can re-fold them
|
|
@@ -978,6 +1005,8 @@ export async function generateClientBundle(routeTree, appDir, componentMap, opti
|
|
|
978
1005
|
transformedChunks.push({ ...chunk, code: await applyTransformPlugins(chunk.code, chunk.name) });
|
|
979
1006
|
}
|
|
980
1007
|
componentOwners.report('client bundle');
|
|
1008
|
+
if (process.env.VESK_BUILD_PROFILE)
|
|
1009
|
+
console.error(` [client] chunks=${chunks.length} compiled=${__stats.compiled} distinct=${__stats.distinct.size} parseMs=${__stats.parseMs.toFixed(0)}`);
|
|
981
1010
|
return { main: await applyTransformPlugins(main, 'client.js'), chunks: transformedChunks, cachedFileHits, compiledFiles, mainFromCache, editedSources, editedNames };
|
|
982
1011
|
}
|
|
983
1012
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-pipeline.d.ts","sourceRoot":"","sources":["../src/image-pipeline.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"image-pipeline.d.ts","sourceRoot":"","sources":["../src/image-pipeline.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAY,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAyKrE,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAwD3F"}
|
package/dist/image-pipeline.js
CHANGED
|
@@ -1,29 +1,100 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync, readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import { resolve, extname, dirname } from 'node:path';
|
|
3
|
+
import { resolve, extname, dirname, join } from 'node:path';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
4
6
|
const SUPPORTED = new Set(['.jpg', '.jpeg', '.png', '.webp', '.avif', '.tiff']);
|
|
5
7
|
const OUTPUT_WIDTHS = [640, 768, 1024, 1280, 1536];
|
|
6
8
|
const FORMATS = ['webp', 'avif'];
|
|
7
9
|
let sharpFn = null;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
let sharpProbed = false;
|
|
11
|
+
/**
|
|
12
|
+
* Remember a failed probe on disk.
|
|
13
|
+
*
|
|
14
|
+
* The probe's answer is a property of the MACHINE (CPU instruction set, the
|
|
15
|
+
* installed sharp binary) and not of the project, but it costs a child process
|
|
16
|
+
* that dies with SIGILL — and the kernel writes a core dump on the way out, so
|
|
17
|
+
* the "no" case is the expensive one: measured at 25-100s per build on a
|
|
18
|
+
* loaded 2-core box. Without this, every build of an app that has images pays
|
|
19
|
+
* it again. The key folds in the resolved sharp entry's mtime, so installing or
|
|
20
|
+
* upgrading sharp invalidates the memo and the next build probes for real.
|
|
21
|
+
*/
|
|
22
|
+
function probeMemoPath() {
|
|
23
|
+
try {
|
|
24
|
+
const req = createRequire(import.meta.url);
|
|
25
|
+
// `sharp/package.json` is NOT an exported subpath (sharp's exports map
|
|
26
|
+
// rejects it with ERR_PACKAGE_PATH_NOT_EXPORTED), so key on the resolved
|
|
27
|
+
// ENTRY file: its mtime changes on install/upgrade, which is exactly when
|
|
28
|
+
// the answer has to be re-measured.
|
|
29
|
+
const entry = req.resolve('sharp');
|
|
30
|
+
const stamp = Math.round(statSync(entry).mtimeMs);
|
|
31
|
+
return join(tmpdir(), `vesk-sharp-probe-${process.platform}-${process.arch}-${stamp}.json`);
|
|
20
32
|
}
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
catch {
|
|
34
|
+
// sharp not installed: the answer is "unavailable" and cannot change
|
|
35
|
+
// without an install.
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function readProbeMemo() {
|
|
40
|
+
const path = probeMemoPath();
|
|
41
|
+
if (path === null)
|
|
42
|
+
return null;
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(readFileSync(path, 'utf-8'))?.usable === true;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function writeProbeMemo(usable) {
|
|
51
|
+
const path = probeMemoPath();
|
|
52
|
+
if (path === null)
|
|
53
|
+
return;
|
|
54
|
+
try {
|
|
55
|
+
writeFileSync(path, JSON.stringify({ usable, at: Date.now() }), 'utf-8');
|
|
23
56
|
}
|
|
57
|
+
catch { /* a read-only tmpdir just means we probe again next build */ }
|
|
24
58
|
}
|
|
25
|
-
|
|
26
|
-
|
|
59
|
+
/**
|
|
60
|
+
* Load sharp, or decide we cannot. LAZY on purpose: the probe spawns a child
|
|
61
|
+
* Node that imports the native module, and on a CPU without the instructions
|
|
62
|
+
* sharp's binary needs that child dies with SIGILL after tens of seconds. Doing
|
|
63
|
+
* it at module scope charged every build — including builds of apps with no
|
|
64
|
+
* `<Image>` at all — for a capability the build may never use. Callers reach
|
|
65
|
+
* this only after finding image refs, and the answer is memoized per machine.
|
|
66
|
+
*/
|
|
67
|
+
async function ensureSharp() {
|
|
68
|
+
if (sharpProbed)
|
|
69
|
+
return;
|
|
70
|
+
sharpProbed = true;
|
|
71
|
+
const memo = readProbeMemo();
|
|
72
|
+
if (memo === false) {
|
|
73
|
+
console.warn('vesk images: sharp unusable on this machine (cached); using copy-only image pipeline');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
// Probe in a child before importing sharp in this process. On older CPUs,
|
|
78
|
+
// importing the native module itself can terminate Node with SIGILL; an
|
|
79
|
+
// in-process try/catch cannot catch that signal.
|
|
80
|
+
const probe = spawnSync(process.execPath, [
|
|
81
|
+
'--input-type=module',
|
|
82
|
+
'-e',
|
|
83
|
+
"import sharp from 'sharp'; await sharp({ create: { width: 2, height: 2, channels: 3, background: 'red' } }).png().toBuffer();",
|
|
84
|
+
], { stdio: 'ignore' });
|
|
85
|
+
if (probe.status === 0) {
|
|
86
|
+
const mod = await import('sharp');
|
|
87
|
+
sharpFn = mod.default;
|
|
88
|
+
writeProbeMemo(true);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
console.warn('vesk images: sharp native probe failed; using copy-only image pipeline');
|
|
92
|
+
writeProbeMemo(false);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// sharp not available — fall through to copy-only
|
|
97
|
+
}
|
|
27
98
|
}
|
|
28
99
|
async function processImage(srcPath, outDir, baseName) {
|
|
29
100
|
const image = sharpFn ? sharpFn(srcPath) : null;
|
|
@@ -95,13 +166,20 @@ export async function optimizeImages(appDir, outDir) {
|
|
|
95
166
|
console.error('vesk images: no <Image> refs found');
|
|
96
167
|
return [];
|
|
97
168
|
}
|
|
169
|
+
await ensureSharp();
|
|
98
170
|
const results = [];
|
|
99
171
|
for (const ref of refs) {
|
|
172
|
+
// `src` is site-root-relative in every documented form (`<Image
|
|
173
|
+
// src="/hero.png" />`), and `path.resolve` treats a leading-slash argument
|
|
174
|
+
// as an ABSOLUTE path — so `resolve(appDir, '/hero.png')` asks the filesystem
|
|
175
|
+
// for `/hero.png` and every image reference in the app is reported missing.
|
|
176
|
+
// Strip the leading slash for every candidate base.
|
|
177
|
+
const rel = ref.src.replace(/^\//, '');
|
|
100
178
|
const possiblePaths = [
|
|
101
|
-
resolve(appDir,
|
|
102
|
-
resolve(appDir, '..', 'public',
|
|
103
|
-
resolve(appDir, '..', 'src',
|
|
104
|
-
resolve(outDir, 'static', 'public',
|
|
179
|
+
resolve(appDir, rel),
|
|
180
|
+
resolve(appDir, '..', 'public', rel),
|
|
181
|
+
resolve(appDir, '..', 'src', rel),
|
|
182
|
+
resolve(outDir, 'static', 'public', rel),
|
|
105
183
|
];
|
|
106
184
|
let srcPath = null;
|
|
107
185
|
for (const p of possiblePaths) {
|
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;
|
|
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;AAkDD,wBAAsB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CA6UpG;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
|
@@ -84,7 +84,32 @@ async function collectPluginHeadExtra(pluginsPipelines) {
|
|
|
84
84
|
}
|
|
85
85
|
return parts.join('\n');
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* `VESK_BUILD_PROFILE=1 vesk build` prints a per-phase millisecond breakdown.
|
|
89
|
+
*
|
|
90
|
+
* Builds are parse-bound and used to be hard to reason about: a 28-route app
|
|
91
|
+
* spent its time in a sharp capability probe, in per-route recompiles of the
|
|
92
|
+
* same shared files, and in re-parsing generated JS through the `.vsk` parser,
|
|
93
|
+
* and none of that is visible in the phase log lines. This makes it visible.
|
|
94
|
+
*/
|
|
95
|
+
const profileEnabled = () => process.env.VESK_BUILD_PROFILE === '1';
|
|
96
|
+
let phaseMarks = [];
|
|
97
|
+
let phaseStarted = 0;
|
|
98
|
+
let buildStarted = 0;
|
|
99
|
+
function markPhase(name) {
|
|
100
|
+
if (!profileEnabled())
|
|
101
|
+
return;
|
|
102
|
+
const now = performance.now();
|
|
103
|
+
if (phaseStarted > 0)
|
|
104
|
+
phaseMarks.push([name, now - phaseStarted]);
|
|
105
|
+
phaseStarted = now;
|
|
106
|
+
}
|
|
87
107
|
export async function build(appDir, options) {
|
|
108
|
+
if (profileEnabled()) {
|
|
109
|
+
buildStarted = Date.now();
|
|
110
|
+
phaseMarks = [];
|
|
111
|
+
phaseStarted = performance.now();
|
|
112
|
+
}
|
|
88
113
|
appDir = resolve(appDir);
|
|
89
114
|
const outDir = resolve(options?.outDir || resolve(appDir, '..', '.vesk'));
|
|
90
115
|
const publicDir = options?.publicDir || resolve(appDir, '..', 'public');
|
|
@@ -150,6 +175,7 @@ export async function build(appDir, options) {
|
|
|
150
175
|
];
|
|
151
176
|
for (const d of dirs)
|
|
152
177
|
mkdirSync(d, { recursive: true });
|
|
178
|
+
markPhase('config+dirs');
|
|
153
179
|
const cssSourcePath = resolveUserCssPath(appDir);
|
|
154
180
|
if (cssSourcePath !== null) {
|
|
155
181
|
const cssContent = readFileSync(cssSourcePath, 'utf-8');
|
|
@@ -174,6 +200,7 @@ export async function build(appDir, options) {
|
|
|
174
200
|
console.error(`vesk build: css → static/global.css (${finalCss.length} bytes, tailwind plugin inactive)`);
|
|
175
201
|
}
|
|
176
202
|
}
|
|
203
|
+
markPhase('css/tailwind');
|
|
177
204
|
const { scanRoutes, scanComponents } = await resolveCompilerApi('router.js');
|
|
178
205
|
const { scanApiRoutes } = await resolveCompilerApi('api-routes.js');
|
|
179
206
|
const { collectMiddlewareChain } = await resolveCompilerApi('middleware.js');
|
|
@@ -191,6 +218,7 @@ export async function build(appDir, options) {
|
|
|
191
218
|
const apiDir = resolve(appDir, 'api');
|
|
192
219
|
const apiTree = existsSync(apiDir) ? scanApiRoutes(apiDir) : [];
|
|
193
220
|
console.error(`vesk build: ${routeTree.length} root routes, ${apiTree.length} API routes`);
|
|
221
|
+
markPhase('scan routes');
|
|
194
222
|
console.error('vesk build: bundling server runtime...');
|
|
195
223
|
await bundleRuntime(appDir, outDir);
|
|
196
224
|
const ssrRoutes = [];
|
|
@@ -247,6 +275,7 @@ export async function build(appDir, options) {
|
|
|
247
275
|
}
|
|
248
276
|
}
|
|
249
277
|
walk(routeTree);
|
|
278
|
+
markPhase('server runtime + ssr functions');
|
|
250
279
|
const apiRoutes = [];
|
|
251
280
|
function walkApi(nodes) {
|
|
252
281
|
for (const node of nodes) {
|
|
@@ -273,6 +302,7 @@ export async function build(appDir, options) {
|
|
|
273
302
|
const hasEvents = await compileEvents(appDir, outDir);
|
|
274
303
|
if (hasEvents)
|
|
275
304
|
console.error('vesk build: evt → server/events.js (onStart/onRequest/onStop)');
|
|
305
|
+
markPhase('api functions');
|
|
276
306
|
console.error('vesk build: bundling client runtime...');
|
|
277
307
|
const bundleOpts = {};
|
|
278
308
|
if (options?.codeSplit)
|
|
@@ -295,6 +325,7 @@ export async function build(appDir, options) {
|
|
|
295
325
|
}
|
|
296
326
|
}
|
|
297
327
|
copyStaticAssets(publicDir, outDir);
|
|
328
|
+
markPhase('client runtime + chunks');
|
|
298
329
|
console.error('vesk build: static → static/public/');
|
|
299
330
|
let prerenderedRoutes = [];
|
|
300
331
|
if (options?.ssg) {
|
|
@@ -316,10 +347,6 @@ export async function build(appDir, options) {
|
|
|
316
347
|
throw new Error(`SEO audit failed with ${audit.errors} error(s) — fix them before deploying`);
|
|
317
348
|
}
|
|
318
349
|
}
|
|
319
|
-
{
|
|
320
|
-
const { optimizeImages } = await import('./image-pipeline.js');
|
|
321
|
-
await optimizeImages(appDir, outDir);
|
|
322
|
-
}
|
|
323
350
|
{
|
|
324
351
|
const { generateSitemap, generateRobotsTxt } = await import('./static.js');
|
|
325
352
|
const publicDirResolved = resolve(outDir, 'static', 'public');
|
|
@@ -337,6 +364,7 @@ export async function build(appDir, options) {
|
|
|
337
364
|
console.error(`vesk build: seo → static/public/robots.txt (${robots.length} bytes)`);
|
|
338
365
|
}
|
|
339
366
|
}
|
|
367
|
+
markPhase('ssg+images+seo');
|
|
340
368
|
const manifest = generateManifest(routeTree, ssrRoutes, apiRoutes, prerenderedRoutes, middlewareEnabled, actionMap, pluginHeadExtra, hasEvents);
|
|
341
369
|
writeFileSync(resolve(outDir, 'config.json'), JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
342
370
|
console.error('vesk build: config → config.json');
|
|
@@ -369,6 +397,14 @@ export async function build(appDir, options) {
|
|
|
369
397
|
await plugin.onBuildEnd();
|
|
370
398
|
}
|
|
371
399
|
}
|
|
400
|
+
markPhase('manifest+platform');
|
|
401
|
+
markPhase('tail');
|
|
402
|
+
if (profileEnabled()) {
|
|
403
|
+
for (const [name, ms] of phaseMarks) {
|
|
404
|
+
console.error(` phase ${name.padEnd(30)} ${ms.toFixed(0).padStart(6)}ms`);
|
|
405
|
+
}
|
|
406
|
+
console.error(` TOTAL ${(Date.now() - buildStarted).toFixed(0)}ms`);
|
|
407
|
+
}
|
|
372
408
|
console.error(`\nvesk build: done (${outDir})`);
|
|
373
409
|
return { routeTree, apiTree, ssrRoutes, apiRoutes, manifest };
|
|
374
410
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/adapter",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.47",
|
|
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.47",
|
|
27
|
+
"@vesk/runtime": "^0.2.47",
|
|
28
|
+
"@vesk/types": "^0.2.47"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/ws": "^8.18.1",
|