veryfront 0.1.733 → 0.1.735
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/esm/deno.js +1 -1
- package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts +25 -0
- package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.d.ts.map +1 -0
- package/esm/src/rendering/orchestrator/module-loader/dependency-resolver.js +87 -0
- package/esm/src/rendering/orchestrator/module-loader/index.d.ts.map +1 -1
- package/esm/src/rendering/orchestrator/module-loader/index.js +10 -79
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/specifier-resolver.d.ts +29 -0
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/specifier-resolver.d.ts.map +1 -0
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/specifier-resolver.js +70 -0
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts +1 -6
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts.map +1 -1
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.js +10 -80
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
package/esm/deno.js
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RuntimeAdapter } from "../../../platform/adapters/base.js";
|
|
2
|
+
/** Resolved local module dependency discovered in a source module. */
|
|
3
|
+
export type ResolvedModuleDependency = {
|
|
4
|
+
full: string;
|
|
5
|
+
path: string;
|
|
6
|
+
relativePath: string;
|
|
7
|
+
depFilePath: string | null;
|
|
8
|
+
isLocalLib: boolean;
|
|
9
|
+
};
|
|
10
|
+
/** Resolved dependency after its source module has been transformed to a temp file. */
|
|
11
|
+
export type TransformedModuleDependency = ResolvedModuleDependency & {
|
|
12
|
+
depTempPath: string;
|
|
13
|
+
};
|
|
14
|
+
/** Input for resolving local module dependencies from source code. */
|
|
15
|
+
export interface ResolveModuleDependenciesInput {
|
|
16
|
+
fileContent: string;
|
|
17
|
+
filePath: string;
|
|
18
|
+
projectDir: string;
|
|
19
|
+
adapter: RuntimeAdapter;
|
|
20
|
+
}
|
|
21
|
+
/** Resolves @/ alias and relative local imports from a source module. */
|
|
22
|
+
export declare function resolveModuleDependencies(input: ResolveModuleDependenciesInput): Promise<ResolvedModuleDependency[]>;
|
|
23
|
+
/** Rewrites resolved local imports to their transformed temp file URLs. */
|
|
24
|
+
export declare function rewriteResolvedDependencyImports(fileContent: string, transformedDeps: TransformedModuleDependency[]): string;
|
|
25
|
+
//# sourceMappingURL=dependency-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-resolver.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/dependency-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AASzE,sEAAsE;AACtE,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,uFAAuF;AACvF,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,GAAG;IACnE,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,sEAAsE;AACtE,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,cAAc,CAAC;CACzB;AAgFD,yEAAyE;AACzE,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAuBrC;AAED,2EAA2E;AAC3E,wBAAgB,gCAAgC,CAC9C,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,2BAA2B,EAAE,GAC7C,MAAM,CAMR"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { dirname, join, normalize } from "../../../platform/compat/path/index.js";
|
|
2
|
+
import { parallelMap, rendererLogger } from "../../../utils/index.js";
|
|
3
|
+
import { findSourceFile } from "../file-resolver/index.js";
|
|
4
|
+
const logger = rendererLogger.component("module-loader");
|
|
5
|
+
function collectAliasImports(fileContent) {
|
|
6
|
+
return [...fileContent.matchAll(/from\s+["'](@\/[^"']+)["']/g)].map((m) => ({
|
|
7
|
+
full: m[0],
|
|
8
|
+
path: m[1] ?? "",
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
function collectRelativeImports(fileContent, fileDir) {
|
|
12
|
+
return [...fileContent.matchAll(/from\s+["'](\.\.?\/[^"']+)["']/g)]
|
|
13
|
+
.map((m) => ({ full: m[0], path: m[1] ?? "", fromDir: fileDir }))
|
|
14
|
+
// Ignore already-transformed file:// imports.
|
|
15
|
+
.filter((imp) => !imp.path.includes("file://"));
|
|
16
|
+
}
|
|
17
|
+
async function resolveAliasImport(imp, projectDir, adapter) {
|
|
18
|
+
const relativePath = imp.path.substring(2); // Remove @/ prefix.
|
|
19
|
+
const depFilePath = (await findSourceFile(relativePath, projectDir, adapter)) ??
|
|
20
|
+
(await findSourceFile(`components/${relativePath}`, projectDir, adapter));
|
|
21
|
+
return { ...imp, relativePath, depFilePath, isLocalLib: false };
|
|
22
|
+
}
|
|
23
|
+
async function resolveRelativeImport(imp, adapter) {
|
|
24
|
+
const basePath = normalize(join(imp.fromDir, imp.path));
|
|
25
|
+
logger.debug("Resolving relative import:", {
|
|
26
|
+
path: imp.path,
|
|
27
|
+
fromDir: imp.fromDir,
|
|
28
|
+
basePath,
|
|
29
|
+
});
|
|
30
|
+
const extensions = [".tsx", ".ts", ".jsx", ".js", ".mdx"];
|
|
31
|
+
let depFilePath = null;
|
|
32
|
+
if (await adapter.fs.exists(basePath)) {
|
|
33
|
+
const stat = await adapter.fs.stat(basePath);
|
|
34
|
+
if (!stat.isDirectory) {
|
|
35
|
+
depFilePath = basePath;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!depFilePath) {
|
|
39
|
+
for (const ext of extensions) {
|
|
40
|
+
const pathWithExt = basePath + ext;
|
|
41
|
+
if (await adapter.fs.exists(pathWithExt)) {
|
|
42
|
+
depFilePath = pathWithExt;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!depFilePath) {
|
|
48
|
+
for (const ext of extensions) {
|
|
49
|
+
const indexPath = join(basePath, `index${ext}`);
|
|
50
|
+
if (await adapter.fs.exists(indexPath)) {
|
|
51
|
+
depFilePath = indexPath;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
full: imp.full,
|
|
58
|
+
path: imp.path,
|
|
59
|
+
relativePath: imp.path,
|
|
60
|
+
depFilePath,
|
|
61
|
+
isLocalLib: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Resolves @/ alias and relative local imports from a source module. */
|
|
65
|
+
export async function resolveModuleDependencies(input) {
|
|
66
|
+
const fileDir = dirname(input.filePath);
|
|
67
|
+
const aliasImports = collectAliasImports(input.fileContent);
|
|
68
|
+
const relativeImports = collectRelativeImports(input.fileContent, fileDir);
|
|
69
|
+
logger.debug("Processing file:", {
|
|
70
|
+
filePath: input.filePath,
|
|
71
|
+
aliasImportsCount: aliasImports.length,
|
|
72
|
+
relativeImportsCount: relativeImports.length,
|
|
73
|
+
aliasImports: aliasImports.map((i) => i.path),
|
|
74
|
+
relativeImports: relativeImports.map((i) => i.path),
|
|
75
|
+
});
|
|
76
|
+
const resolvedAliasDeps = await parallelMap(aliasImports, (imp) => resolveAliasImport(imp, input.projectDir, input.adapter));
|
|
77
|
+
const resolvedRelativeDeps = await parallelMap(relativeImports, (imp) => resolveRelativeImport(imp, input.adapter));
|
|
78
|
+
return [...resolvedAliasDeps, ...resolvedRelativeDeps];
|
|
79
|
+
}
|
|
80
|
+
/** Rewrites resolved local imports to their transformed temp file URLs. */
|
|
81
|
+
export function rewriteResolvedDependencyImports(fileContent, transformedDeps) {
|
|
82
|
+
let rewritten = fileContent;
|
|
83
|
+
for (const dep of transformedDeps) {
|
|
84
|
+
rewritten = rewritten.replace(dep.full, `from "file://${dep.depTempPath}"`);
|
|
85
|
+
}
|
|
86
|
+
return rewritten;
|
|
87
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/src/rendering/orchestrator/module-loader/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AA+BzE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAmEpE,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,cAAc,EAC5B,MAAM,EAAE,kBAAkB,EAC1B,eAAe,UAAQ,GACtB,OAAO,CAAC,MAAM,CAAC,CAsQjB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,aAAa,GAAG,YAAY,CAAC;IACnC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAyBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAI5D;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA6DlC"}
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module rendering/orchestrator/module-loader
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { rendererLogger } from "../../../utils/index.js";
|
|
10
10
|
import { getLocalAdapter } from "../../../platform/adapters/registry.js";
|
|
11
|
-
import { findSourceFile } from "../file-resolver/index.js";
|
|
12
11
|
import { transformToESM } from "../../../transforms/esm-transform.js";
|
|
13
12
|
import { createFileSystem } from "../../../platform/compat/fs.js";
|
|
14
13
|
import { getProjectTmpDir } from "../../../modules/react-loader/index.js";
|
|
@@ -16,10 +15,11 @@ import { generateCacheKey as generateTransformCacheKey, getOrComputeTransform, i
|
|
|
16
15
|
import { TRANSFORM_DISTRIBUTED_TTL_SEC } from "../../../utils/constants/cache.js";
|
|
17
16
|
import { validateCachedBundlesByManifestOrCode } from "../../../transforms/esm/cached-bundle-validation.js";
|
|
18
17
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
|
|
19
|
-
import {
|
|
18
|
+
import { join } from "../../../platform/compat/path/index.js";
|
|
20
19
|
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
21
20
|
import { getModulePathCache, invalidateMdxEsmModule, lookupMdxEsmCache, saveModulePathCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
|
|
22
21
|
import { buildMdxEsmPathCacheKey } from "../../../transforms/mdx/esm-module-loader/cache-format.js";
|
|
22
|
+
import { resolveModuleDependencies, rewriteResolvedDependencyImports, } from "./dependency-resolver.js";
|
|
23
23
|
const logger = rendererLogger.component("module-loader");
|
|
24
24
|
// Re-export utilities
|
|
25
25
|
export { createEsmCache, createModuleCache, generateHash } from "./cache.js";
|
|
@@ -67,58 +67,6 @@ async function ensureDir(adapter, dir) {
|
|
|
67
67
|
pruneCreatedDirs();
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
async function resolveAliasImport(imp, projectDir, adapter) {
|
|
71
|
-
const relativePath = imp.path.substring(2); // Remove @/ prefix
|
|
72
|
-
const depFilePath = (await findSourceFile(relativePath, projectDir, adapter)) ??
|
|
73
|
-
(await findSourceFile(`components/${relativePath}`, projectDir, adapter));
|
|
74
|
-
return { ...imp, relativePath, depFilePath, isLocalLib: false };
|
|
75
|
-
}
|
|
76
|
-
async function resolveRelativeImport(imp, adapter) {
|
|
77
|
-
// Resolve the path relative to the file's directory and normalize to resolve ..
|
|
78
|
-
const basePath = normalize(join(imp.fromDir, imp.path));
|
|
79
|
-
logger.debug("Resolving relative import:", {
|
|
80
|
-
path: imp.path,
|
|
81
|
-
fromDir: imp.fromDir,
|
|
82
|
-
basePath,
|
|
83
|
-
});
|
|
84
|
-
// Try to find the source file with various extensions
|
|
85
|
-
const extensions = [".tsx", ".ts", ".jsx", ".js", ".mdx"];
|
|
86
|
-
let depFilePath = null;
|
|
87
|
-
// First try the exact path (in case it already has an extension)
|
|
88
|
-
if (await adapter.fs.exists(basePath)) {
|
|
89
|
-
const stat = await adapter.fs.stat(basePath);
|
|
90
|
-
if (!stat.isDirectory) {
|
|
91
|
-
depFilePath = basePath;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
// Try with extensions
|
|
95
|
-
if (!depFilePath) {
|
|
96
|
-
for (const ext of extensions) {
|
|
97
|
-
const pathWithExt = basePath + ext;
|
|
98
|
-
if (await adapter.fs.exists(pathWithExt)) {
|
|
99
|
-
depFilePath = pathWithExt;
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// Try index files if path is a directory
|
|
105
|
-
if (!depFilePath) {
|
|
106
|
-
for (const ext of extensions) {
|
|
107
|
-
const indexPath = join(basePath, `index${ext}`);
|
|
108
|
-
if (await adapter.fs.exists(indexPath)) {
|
|
109
|
-
depFilePath = indexPath;
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
full: imp.full,
|
|
116
|
-
path: imp.path,
|
|
117
|
-
relativePath: imp.path,
|
|
118
|
-
depFilePath,
|
|
119
|
-
isLocalLib: false,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
70
|
/**
|
|
123
71
|
* Transform a module and all its local dependencies (@/ alias and relative imports).
|
|
124
72
|
*
|
|
@@ -179,30 +127,13 @@ export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, co
|
|
|
179
127
|
}
|
|
180
128
|
const readAdapter = useLocalAdapter ? localAdapter : adapter;
|
|
181
129
|
let fileContent = decodeFileContent(await readAdapter.fs.readFile(filePath));
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// Match relative imports (./ and ../) - exclude npm:, http://, https://, file://
|
|
186
|
-
const relativeImports = [
|
|
187
|
-
...fileContent.matchAll(/from\s+["'](\.\.?\/[^"']+)["']/g),
|
|
188
|
-
]
|
|
189
|
-
.map((m) => ({ full: m[0], path: m[1] ?? "", fromDir: fileDir }))
|
|
190
|
-
// Filter out already-transformed file:// imports
|
|
191
|
-
.filter((imp) => !imp.path.includes("file://"));
|
|
192
|
-
logger.debug("Processing file:", {
|
|
130
|
+
const resolvedDeps = await resolveModuleDependencies({
|
|
131
|
+
adapter,
|
|
132
|
+
fileContent,
|
|
193
133
|
filePath,
|
|
194
|
-
|
|
195
|
-
relativeImportsCount: relativeImports.length,
|
|
196
|
-
aliasImports: aliasImports.map((i) => i.path),
|
|
197
|
-
relativeImports: relativeImports.map((i) => i.path),
|
|
134
|
+
projectDir,
|
|
198
135
|
});
|
|
199
|
-
|
|
200
|
-
const resolvedAliasDeps = await parallelMap(aliasImports, (imp) => resolveAliasImport(imp, projectDir, adapter));
|
|
201
|
-
// Resolve relative imports
|
|
202
|
-
const resolvedRelativeDeps = await parallelMap(relativeImports, (imp) => resolveRelativeImport(imp, adapter));
|
|
203
|
-
// Combine all resolved dependencies
|
|
204
|
-
const resolvedDeps = [...resolvedAliasDeps, ...resolvedRelativeDeps];
|
|
205
|
-
const transformedDeps = await parallelMap(resolvedDeps.filter((d) => d.depFilePath), async (dep) => {
|
|
136
|
+
const transformedDeps = await Promise.all(resolvedDeps.filter((d) => d.depFilePath).map(async (dep) => {
|
|
206
137
|
logger.debug("Found dependency:", {
|
|
207
138
|
path: dep.path,
|
|
208
139
|
depFilePath: dep.depFilePath,
|
|
@@ -210,9 +141,9 @@ export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, co
|
|
|
210
141
|
});
|
|
211
142
|
const depTempPath = await transformModuleWithDeps(dep.depFilePath, tmpDir, localAdapter, config, dep.isLocalLib);
|
|
212
143
|
return { ...dep, depTempPath };
|
|
213
|
-
});
|
|
144
|
+
}));
|
|
145
|
+
fileContent = rewriteResolvedDependencyImports(fileContent, transformedDeps);
|
|
214
146
|
for (const dep of transformedDeps) {
|
|
215
|
-
fileContent = fileContent.replace(dep.full, `from "file://${dep.depTempPath}"`);
|
|
216
147
|
logger.debug("Replaced import:", {
|
|
217
148
|
path: dep.path,
|
|
218
149
|
depTempPath: dep.depTempPath,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specifier resolution helpers for the SSR VF Modules stage.
|
|
3
|
+
*
|
|
4
|
+
* @module transforms/pipeline/stages/ssr-vf-modules/specifier-resolver
|
|
5
|
+
*/
|
|
6
|
+
export interface FrameworkSpecifierResolverInput {
|
|
7
|
+
denoConfigStubUrl: string | null;
|
|
8
|
+
veryfrontReplacements: ReadonlyMap<string, string>;
|
|
9
|
+
relativeReplacements: ReadonlyMap<string, string>;
|
|
10
|
+
reactVersion: string;
|
|
11
|
+
reactImportMap?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a bare `react` / `react-dom` (or subpath) specifier to its esm.sh
|
|
15
|
+
* URL for the given React version. Returns `null` for anything that is not a
|
|
16
|
+
* React specifier.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveReactSpecifier(specifier: string, reactVersion: string, reactImportMap?: Record<string, string>): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* If `resolvedPath` is one of veryfront's React re-export modules
|
|
21
|
+
* (`FRAMEWORK_ROOT/react/*.js`), return the esm.sh URL it should be rewritten
|
|
22
|
+
* to for the given React version. Returns `null` for anything else.
|
|
23
|
+
*/
|
|
24
|
+
export declare function reactReExportToEsmUrl(resolvedPath: string, reactVersion: string, reactImportMap?: Record<string, string>): string | null;
|
|
25
|
+
/**
|
|
26
|
+
* Build the final specifier resolver for transformed framework code.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createFrameworkSpecifierResolver(input: FrameworkSpecifierResolverInput): (specifier: string) => string | null;
|
|
29
|
+
//# sourceMappingURL=specifier-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specifier-resolver.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/specifier-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,+BAA+B;IAC9C,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,qBAAqB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,oBAAoB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAmC,GACvE,MAAM,GAAG,IAAI,CAef;AAkBD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,MAAM,GAAG,IAAI,CAKf;AAED;;GAEG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,+BAA+B,GACrC,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAkBtC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specifier resolution helpers for the SSR VF Modules stage.
|
|
3
|
+
*
|
|
4
|
+
* @module transforms/pipeline/stages/ssr-vf-modules/specifier-resolver
|
|
5
|
+
*/
|
|
6
|
+
import { join } from "../../../../platform/compat/path/index.js";
|
|
7
|
+
import { buildReactUrl, getReactImportMap } from "../../../import-rewriter/url-builder.js";
|
|
8
|
+
import { FRAMEWORK_ROOT } from "./constants.js";
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a bare `react` / `react-dom` (or subpath) specifier to its esm.sh
|
|
11
|
+
* URL for the given React version. Returns `null` for anything that is not a
|
|
12
|
+
* React specifier.
|
|
13
|
+
*/
|
|
14
|
+
export function resolveReactSpecifier(specifier, reactVersion, reactImportMap = getReactImportMap(reactVersion)) {
|
|
15
|
+
const mapped = reactImportMap[specifier];
|
|
16
|
+
if (mapped)
|
|
17
|
+
return mapped;
|
|
18
|
+
if (specifier.startsWith("react/")) {
|
|
19
|
+
return buildReactUrl("react", reactVersion, "/" + specifier.slice("react/".length), true);
|
|
20
|
+
}
|
|
21
|
+
if (specifier.startsWith("react-dom/")) {
|
|
22
|
+
return buildReactUrl("react-dom", reactVersion, "/" + specifier.slice("react-dom/".length), true);
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* veryfront's own React re-export modules under `FRAMEWORK_ROOT/react/`
|
|
28
|
+
* mapped to the bare specifier they stand in for.
|
|
29
|
+
*/
|
|
30
|
+
const REACT_REEXPORT_SPECIFIERS = {
|
|
31
|
+
"react.js": "react",
|
|
32
|
+
"react-dom.js": "react-dom",
|
|
33
|
+
"react-dom-client.js": "react-dom/client",
|
|
34
|
+
"react-dom-server.js": "react-dom/server",
|
|
35
|
+
"jsx-runtime.js": "react/jsx-runtime",
|
|
36
|
+
"jsx-dev-runtime.js": "react/jsx-dev-runtime",
|
|
37
|
+
};
|
|
38
|
+
/** `FRAMEWORK_ROOT/react/` prefix, precomputed (invariant per process). */
|
|
39
|
+
const REACT_REEXPORT_DIR = join(FRAMEWORK_ROOT, "react") + "/";
|
|
40
|
+
/**
|
|
41
|
+
* If `resolvedPath` is one of veryfront's React re-export modules
|
|
42
|
+
* (`FRAMEWORK_ROOT/react/*.js`), return the esm.sh URL it should be rewritten
|
|
43
|
+
* to for the given React version. Returns `null` for anything else.
|
|
44
|
+
*/
|
|
45
|
+
export function reactReExportToEsmUrl(resolvedPath, reactVersion, reactImportMap) {
|
|
46
|
+
if (!resolvedPath.startsWith(REACT_REEXPORT_DIR))
|
|
47
|
+
return null;
|
|
48
|
+
const specifier = REACT_REEXPORT_SPECIFIERS[resolvedPath.slice(REACT_REEXPORT_DIR.length)];
|
|
49
|
+
if (!specifier)
|
|
50
|
+
return null;
|
|
51
|
+
return resolveReactSpecifier(specifier, reactVersion, reactImportMap);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build the final specifier resolver for transformed framework code.
|
|
55
|
+
*/
|
|
56
|
+
export function createFrameworkSpecifierResolver(input) {
|
|
57
|
+
const reactImportMap = input.reactImportMap ?? getReactImportMap(input.reactVersion);
|
|
58
|
+
return (specifier) => {
|
|
59
|
+
if (specifier === "#deno-config") {
|
|
60
|
+
return input.denoConfigStubUrl;
|
|
61
|
+
}
|
|
62
|
+
if (specifier.startsWith("#veryfront/")) {
|
|
63
|
+
return input.veryfrontReplacements.get(specifier) ?? null;
|
|
64
|
+
}
|
|
65
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
66
|
+
return input.relativeReplacements.get(specifier) ?? null;
|
|
67
|
+
}
|
|
68
|
+
return resolveReactSpecifier(specifier, input.reactVersion, reactImportMap);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -25,12 +25,7 @@ export declare function isCyclePlaceholder(code: string): boolean;
|
|
|
25
25
|
* - contentHash: Content-based invalidation
|
|
26
26
|
*/
|
|
27
27
|
export declare function cacheTransformedCode(transformed: string, vfModulePath: string, fs: ReturnType<typeof createFileSystem>): Promise<string>;
|
|
28
|
-
|
|
29
|
-
* If `resolvedPath` is one of veryfront's React re-export modules
|
|
30
|
-
* (`FRAMEWORK_ROOT/react/*.js`), return the esm.sh URL it should be rewritten
|
|
31
|
-
* to for the given React version. Returns `null` for anything else.
|
|
32
|
-
*/
|
|
33
|
-
export declare function reactReExportToEsmUrl(resolvedPath: string, reactVersion: string, reactImportMap?: Record<string, string>): string | null;
|
|
28
|
+
export { reactReExportToEsmUrl } from "./specifier-resolver.js";
|
|
34
29
|
/**
|
|
35
30
|
* Core transformation logic for framework TypeScript/TSX files.
|
|
36
31
|
* Compiles to JavaScript and recursively resolves all imports:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAmBrE,OAAO,EAOL,KAAK,gBAAgB,EAGtB,MAAM,gBAAgB,CAAC;AAKxB;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAgBD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAwMhE;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,gBAAgB,EACrB,oBAAoB,UAAQ,EAC5B,KAAK,SAAI,GACR,OAAO,CAAC,MAAM,CAAC,CA8OjB;AAED;;;GAGG;AACH,wBAAsB,kCAAkC,CACtD,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,gBAAgB,GACpB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4CxB;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,GACtC,OAAO,CAAC,MAAM,CAAC,CAEjB"}
|
|
@@ -14,9 +14,10 @@ import { LRUCache } from "../../../../utils/lru-wrapper.js";
|
|
|
14
14
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../../utils/cache-dir.js";
|
|
15
15
|
import { cacheHttpImportsToLocal } from "../../../esm/http-cache.js";
|
|
16
16
|
import { loadImportMap } from "../../../../modules/import-map/index.js";
|
|
17
|
-
import {
|
|
17
|
+
import { getReactImportMap } from "../../../import-rewriter/url-builder.js";
|
|
18
18
|
import { findRelativeImports } from "./import-finder.js";
|
|
19
19
|
import { resolveRelativeFrameworkImport, resolveVeryfrontSourcePath } from "./path-resolver.js";
|
|
20
|
+
import { createFrameworkSpecifierResolver, reactReExportToEsmUrl, resolveReactSpecifier, } from "./specifier-resolver.js";
|
|
20
21
|
import { EMBEDDED_SRC_DIR, FRAMEWORK_ROOT, frameworkFileCache, frameworkWriteFlight, LOG_PREFIX, MAX_RELATIVE_IMPORT_DEPTH, transformingFiles, veryfrontTransformCache, } from "./constants.js";
|
|
21
22
|
import { buildFrameworkVfModuleCacheFileName } from "../../../mdx/esm-module-loader/cache-format.js";
|
|
22
23
|
const DENO_CONFIG_STUB_CODE = `export default ${JSON.stringify(denoConfig)};`;
|
|
@@ -77,70 +78,7 @@ const FALLBACK_TRANSFORM_CACHE_MAX_ENTRIES = 2000;
|
|
|
77
78
|
const fallbackTransformCache = new LRUCache({
|
|
78
79
|
maxEntries: FALLBACK_TRANSFORM_CACHE_MAX_ENTRIES,
|
|
79
80
|
});
|
|
80
|
-
|
|
81
|
-
* Resolve a bare `react` / `react-dom` (or subpath) specifier to its esm.sh
|
|
82
|
-
* URL for the given React version. Returns `null` for anything that is not a
|
|
83
|
-
* React specifier.
|
|
84
|
-
*
|
|
85
|
-
* Both the main transform path and the depth-limit fallback use this so a
|
|
86
|
-
* framework module always links against the single esm.sh React bundle used
|
|
87
|
-
* during SSR. Leaving `react` bare would resolve it to the project's own
|
|
88
|
-
* React copy — a second React instance whose dispatcher is null, which makes
|
|
89
|
-
* the first hook throw "Cannot read properties of null (reading 'useEffect')".
|
|
90
|
-
*/
|
|
91
|
-
function resolveReactSpecifier(specifier, reactVersion, reactImportMap = getReactImportMap(reactVersion)) {
|
|
92
|
-
const mapped = reactImportMap[specifier];
|
|
93
|
-
if (mapped)
|
|
94
|
-
return mapped;
|
|
95
|
-
if (specifier.startsWith("react/")) {
|
|
96
|
-
return buildReactUrl("react", reactVersion, "/" + specifier.slice("react/".length), true);
|
|
97
|
-
}
|
|
98
|
-
if (specifier.startsWith("react-dom/")) {
|
|
99
|
-
return buildReactUrl("react-dom", reactVersion, "/" + specifier.slice("react-dom/".length), true);
|
|
100
|
-
}
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* veryfront's own React re-export modules under `FRAMEWORK_ROOT/react/`
|
|
105
|
-
* mapped to the bare specifier they stand in for. Each re-export bridges to
|
|
106
|
-
* project React via `export * from "react"` (etc.), which during SSR resolves
|
|
107
|
-
* to the project's `node_modules` copy — a *different* React instance than
|
|
108
|
-
* the esm.sh react-dom bundle uses. The dnt build rewrites framework
|
|
109
|
-
* `import ... from "react"` to a relative import of these files, so a
|
|
110
|
-
* framework module that does `useEffect` ends up reading a null dispatcher.
|
|
111
|
-
* Rewriting these imports straight to the esm.sh bundle keeps every SSR
|
|
112
|
-
* module on a single React instance.
|
|
113
|
-
*
|
|
114
|
-
* Keys must match the compiled re-export filenames under
|
|
115
|
-
* `FRAMEWORK_ROOT/react/`, which the build emits from the `react/*.ts` source
|
|
116
|
-
* modules (`react.ts`, `react-dom.ts`, `react-dom-client.ts`,
|
|
117
|
-
* `react-dom-server.ts`, `jsx-runtime.ts`, `jsx-dev-runtime.ts`). If one is
|
|
118
|
-
* renamed or added, update this map too: a stale key silently reintroduces
|
|
119
|
-
* the dual-React-instance bug.
|
|
120
|
-
*/
|
|
121
|
-
const REACT_REEXPORT_SPECIFIERS = {
|
|
122
|
-
"react.js": "react",
|
|
123
|
-
"react-dom.js": "react-dom",
|
|
124
|
-
"react-dom-client.js": "react-dom/client",
|
|
125
|
-
"react-dom-server.js": "react-dom/server",
|
|
126
|
-
"jsx-runtime.js": "react/jsx-runtime",
|
|
127
|
-
"jsx-dev-runtime.js": "react/jsx-dev-runtime",
|
|
128
|
-
};
|
|
129
|
-
/** `FRAMEWORK_ROOT/react/` prefix, precomputed (invariant per process). */
|
|
130
|
-
const REACT_REEXPORT_DIR = join(FRAMEWORK_ROOT, "react") + "/";
|
|
131
|
-
/**
|
|
132
|
-
* If `resolvedPath` is one of veryfront's React re-export modules
|
|
133
|
-
* (`FRAMEWORK_ROOT/react/*.js`), return the esm.sh URL it should be rewritten
|
|
134
|
-
* to for the given React version. Returns `null` for anything else.
|
|
135
|
-
*/
|
|
136
|
-
export function reactReExportToEsmUrl(resolvedPath, reactVersion, reactImportMap) {
|
|
137
|
-
if (!resolvedPath.startsWith(REACT_REEXPORT_DIR))
|
|
138
|
-
return null;
|
|
139
|
-
const specifier = REACT_REEXPORT_SPECIFIERS[resolvedPath.slice(REACT_REEXPORT_DIR.length)];
|
|
140
|
-
if (!specifier)
|
|
141
|
-
return null;
|
|
142
|
-
return resolveReactSpecifier(specifier, reactVersion, reactImportMap);
|
|
143
|
-
}
|
|
81
|
+
export { reactReExportToEsmUrl } from "./specifier-resolver.js";
|
|
144
82
|
/**
|
|
145
83
|
* Pick an esbuild loader for a file path, honoring the embedded `.src`
|
|
146
84
|
* suffix used in compiled binaries (`foo.ts.src` → `ts`). Recognizes
|
|
@@ -490,21 +428,13 @@ export async function transformFrameworkCode(content, sourcePath, ctx, throwOnMi
|
|
|
490
428
|
const stubPath = await cacheTransformedCode(DENO_CONFIG_STUB_CODE, "#deno-config-stub", ctx.fs);
|
|
491
429
|
denoConfigStubUrl = `file://${stubPath}`;
|
|
492
430
|
}
|
|
493
|
-
transformed = await replaceSpecifiers(transformed, (
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
return veryfrontReplacements.get(specifier) ?? null;
|
|
501
|
-
}
|
|
502
|
-
// Handle relative imports
|
|
503
|
-
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
504
|
-
return relativeReplacements.get(specifier) ?? null;
|
|
505
|
-
}
|
|
506
|
-
return resolveReactSpecifier(specifier, ctx.reactVersion, reactImportMap);
|
|
507
|
-
});
|
|
431
|
+
transformed = await replaceSpecifiers(transformed, createFrameworkSpecifierResolver({
|
|
432
|
+
denoConfigStubUrl,
|
|
433
|
+
veryfrontReplacements,
|
|
434
|
+
relativeReplacements,
|
|
435
|
+
reactVersion: ctx.reactVersion,
|
|
436
|
+
reactImportMap,
|
|
437
|
+
}));
|
|
508
438
|
// Cache HTTP imports to local filesystem
|
|
509
439
|
const importMap = await loadImportMap(ctx.projectDir);
|
|
510
440
|
const cacheResult = await cacheHttpImportsToLocal(transformed, {
|