veryfront 0.1.88 → 0.1.89
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/index.js +2 -2
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/cache/index.js +6 -7
- package/esm/src/transforms/mdx/esm-module-loader/cache-format.d.ts +10 -0
- package/esm/src/transforms/mdx/esm-module-loader/cache-format.d.ts.map +1 -0
- package/esm/src/transforms/mdx/esm-module-loader/cache-format.js +61 -0
- package/esm/src/transforms/mdx/esm-module-loader/import-transformer.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/import-transformer.js +2 -3
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/cache-keys.js +3 -3
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.js +2 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/module-cache.d.ts.map +1 -1
- package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/module-cache.js +5 -5
- package/esm/src/transforms/pipeline/stages/ssr-vf-modules/transform.d.ts +2 -2
- 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 +4 -4
- package/esm/src/utils/cache-namespace.d.ts +11 -0
- package/esm/src/utils/cache-namespace.d.ts.map +1 -0
- package/esm/src/utils/cache-namespace.js +24 -0
- package/esm/src/utils/version.d.ts +1 -1
- package/esm/src/utils/version.js +1 -1
- package/package.json +1 -1
- package/src/deno.js +1 -1
- package/src/src/rendering/orchestrator/module-loader/index.ts +2 -2
- package/src/src/transforms/mdx/esm-module-loader/cache/index.ts +6 -8
- package/src/src/transforms/mdx/esm-module-loader/cache-format.ts +121 -0
- package/src/src/transforms/mdx/esm-module-loader/import-transformer.ts +2 -3
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/cache-keys.ts +3 -3
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.ts +2 -1
- package/src/src/transforms/mdx/esm-module-loader/module-fetcher/module-cache.ts +5 -5
- package/src/src/transforms/pipeline/stages/ssr-vf-modules/transform.ts +4 -4
- package/src/src/utils/cache-namespace.ts +42 -0
- package/src/src/utils/version.ts +1 -1
package/esm/deno.js
CHANGED
|
@@ -18,8 +18,8 @@ import { validateCachedBundlesByManifestOrCode } from "../../../transforms/esm/c
|
|
|
18
18
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
|
|
19
19
|
import { dirname, join, normalize } from "../../../platform/compat/path/index.js";
|
|
20
20
|
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
21
|
-
import { VERSION } from "../../../utils/version.js";
|
|
22
21
|
import { getModulePathCache, lookupMdxEsmCache, saveModulePathCache, } from "../../../transforms/mdx/esm-module-loader/cache/index.js";
|
|
22
|
+
import { buildMdxEsmPathCacheKey } from "../../../transforms/mdx/esm-module-loader/cache-format.js";
|
|
23
23
|
const logger = rendererLogger.component("module-loader");
|
|
24
24
|
// Re-export utilities
|
|
25
25
|
export { createEsmCache, createModuleCache, generateHash } from "./cache.js";
|
|
@@ -327,7 +327,7 @@ export async function transformModuleWithDeps(filePath, tmpDir, localAdapter, co
|
|
|
327
327
|
}
|
|
328
328
|
if (contentSourceId) {
|
|
329
329
|
const normalizedPath = `_vf_modules/${relativePath.replace(/\.(tsx?|jsx|mdx)$/, ".js")}`;
|
|
330
|
-
const mdxCacheKey =
|
|
330
|
+
const mdxCacheKey = buildMdxEsmPathCacheKey(normalizedPath);
|
|
331
331
|
const cache = await getModulePathCache(tmpDir);
|
|
332
332
|
cache.set(mdxCacheKey, tempFilePath);
|
|
333
333
|
saveModulePathCache(tmpDir).catch((err) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/cache/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAG5D,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAI9D,eAAO,MAAM,kBAAkB,wBAE7B,CAAC;AA0GH,wBAAgB,UAAU,IAAI,UAAU,CAGvC;AAKD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsBvF;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAezE;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAQD,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CA0ElE;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAevD;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAc1D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIzD;AAeD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAyG5B"}
|
|
@@ -9,14 +9,13 @@ import { join } from "../../../../platform/compat/path/index.js";
|
|
|
9
9
|
import { rendererLogger as logger } from "../../../../utils/index.js";
|
|
10
10
|
import { getCacheBaseDir, getHttpBundleCacheDir, getMdxEsmCacheDir, } from "../../../../utils/cache-dir.js";
|
|
11
11
|
import { createFileSystem, isNotFoundError, } from "../../../../platform/compat/fs.js";
|
|
12
|
-
import { VERSION } from "../../../../utils/version.js";
|
|
13
12
|
import { LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
14
13
|
import { LRUCache } from "../../../../utils/lru-wrapper.js";
|
|
14
|
+
import { buildMdxEsmPathCacheKey, MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE } from "../cache-format.js";
|
|
15
15
|
const MAX_VERIFIED_MODULE_DEPS = 2_000;
|
|
16
16
|
export const verifiedModuleDeps = new LRUCache({
|
|
17
17
|
maxEntries: MAX_VERIFIED_MODULE_DEPS,
|
|
18
18
|
});
|
|
19
|
-
const FILE_PATH_PATTERN = /file:\/\/([^"'\s]+)/gi;
|
|
20
19
|
/**
|
|
21
20
|
* Check if cached code has file:// paths from a different environment.
|
|
22
21
|
* Checks both HTTP bundle paths and MDX ESM cache paths.
|
|
@@ -25,7 +24,7 @@ function hasIncompatibleCachePaths(code) {
|
|
|
25
24
|
const localCacheBaseDir = getCacheBaseDir();
|
|
26
25
|
const localHttpCacheDir = getHttpBundleCacheDir();
|
|
27
26
|
const localMdxCacheDir = getMdxEsmCacheDir();
|
|
28
|
-
const pattern = new RegExp(
|
|
27
|
+
const pattern = new RegExp(MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE, "gi");
|
|
29
28
|
let match;
|
|
30
29
|
while ((match = pattern.exec(code)) !== null) {
|
|
31
30
|
const path = match[1];
|
|
@@ -64,7 +63,7 @@ function hasIncompatibleCachePaths(code) {
|
|
|
64
63
|
*/
|
|
65
64
|
async function findMissingFileDependencies(code) {
|
|
66
65
|
const localFs = getLocalFs();
|
|
67
|
-
const pattern = new RegExp(
|
|
66
|
+
const pattern = new RegExp(MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE, "gi");
|
|
68
67
|
const missing = [];
|
|
69
68
|
let match;
|
|
70
69
|
while ((match = pattern.exec(code)) !== null) {
|
|
@@ -284,7 +283,7 @@ function toMdxEsmCacheKey(filePath, projectDir) {
|
|
|
284
283
|
}
|
|
285
284
|
relativePath = relativePath.replace(/^\/+/, "");
|
|
286
285
|
const jsPath = relativePath.replace(/\.(tsx?|jsx|mdx)$/, ".js");
|
|
287
|
-
return `
|
|
286
|
+
return buildMdxEsmPathCacheKey(`_vf_modules/${jsPath}`);
|
|
288
287
|
}
|
|
289
288
|
export async function lookupMdxEsmCache(filePath, cacheDir, projectDir, _contentHash) {
|
|
290
289
|
const cache = await getModulePathCache(cacheDir);
|
|
@@ -356,9 +355,9 @@ export async function lookupMdxEsmCache(filePath, cacheDir, projectDir, _content
|
|
|
356
355
|
};
|
|
357
356
|
}
|
|
358
357
|
// Note: We intentionally skip contentHash validation for MDX-ESM cached files.
|
|
359
|
-
// The MDX-ESM cache uses transformed-code hashes in filenames
|
|
358
|
+
// The MDX-ESM cache uses transformed-code hashes in namespaced filenames,
|
|
360
359
|
// while the SSR loader provides source-code hashes. These will never match.
|
|
361
|
-
// The cache
|
|
360
|
+
// The cache namespace in the key provides sufficient staleness protection,
|
|
362
361
|
// and the file's existence confirms it's a valid transform for this codebase.
|
|
363
362
|
// This allows both loaders to share the same module instance, preventing
|
|
364
363
|
// duplicate React contexts which break hooks like useContext.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE: string;
|
|
2
|
+
export declare const MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE: string;
|
|
3
|
+
export declare const MDX_ESM_CACHE_NAMESPACE: string;
|
|
4
|
+
export declare const FRAMEWORK_VF_MODULE_CACHE_NAMESPACE: string;
|
|
5
|
+
export declare function buildMdxEsmTransformCacheKey(projectId: string, normalizedPath: string, contentHash: string): string;
|
|
6
|
+
export declare function buildMdxEsmPathCacheKey(normalizedPath: string): string;
|
|
7
|
+
export declare function buildMdxEsmModuleFileName(contentHash: string): string;
|
|
8
|
+
export declare function buildMdxJsxCacheFileName(filePath: string): string;
|
|
9
|
+
export declare function buildFrameworkVfModuleCacheFileName(pathHash: string, envKey: string, contentHash: string): string;
|
|
10
|
+
//# sourceMappingURL=cache-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-format.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/mdx/esm-module-loader/cache-format.ts"],"names":[],"mappings":"AAuEA,eAAO,MAAM,mCAAmC,QAA8B,CAAC;AAC/E,eAAO,MAAM,mCAAmC,QAA8B,CAAC;AAE/E,eAAO,MAAM,uBAAuB,QAGnC,CAAC;AAEF,eAAO,MAAM,mCAAmC,QAG/C,CAAC;AAEF,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,GAClB,MAAM,CAOR;AAED,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,mCAAmC,CACjD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,MAAM,CAOR"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
2
|
+
import { createCacheNamespace } from "../../../utils/cache-namespace.js";
|
|
3
|
+
import { UNRESOLVED_VF_MODULES_PATTERN } from "./constants.js";
|
|
4
|
+
import { hashString } from "./utils/hash.js";
|
|
5
|
+
const ALL_FILE_URL_PATTERN_SOURCE = /file:\/\/([^"'\s]+)/.source;
|
|
6
|
+
const MJS_FILE_URL_PATTERN_SOURCE = /file:\/\/([^"'\s]+\.mjs)/.source;
|
|
7
|
+
const CACHE_NAMESPACE_SENTINEL = "__vf_cache_namespace__";
|
|
8
|
+
function formatMdxEsmTransformCacheKey(namespace, projectId, normalizedPath, contentHash) {
|
|
9
|
+
return `${namespace}:${projectId}:${normalizedPath}:${contentHash}:ssr`;
|
|
10
|
+
}
|
|
11
|
+
function formatMdxEsmPathCacheKey(namespace, normalizedPath) {
|
|
12
|
+
return `${namespace}:${normalizedPath}`;
|
|
13
|
+
}
|
|
14
|
+
function formatMdxEsmModuleFileName(namespace, contentHash) {
|
|
15
|
+
return `vfmod-${namespace}-${contentHash}.mjs`;
|
|
16
|
+
}
|
|
17
|
+
function formatMdxJsxCacheFileName(namespace, filePath) {
|
|
18
|
+
return `jsx-${namespace}-${hashString(filePath)}.mjs`;
|
|
19
|
+
}
|
|
20
|
+
function formatFrameworkVfModuleCacheFileName(namespace, pathHash, envKey, contentHash) {
|
|
21
|
+
return `vfmod-${namespace}-${pathHash}-${envKey}-${contentHash}.mjs`;
|
|
22
|
+
}
|
|
23
|
+
function buildMdxEsmCacheSchemaSample() {
|
|
24
|
+
return {
|
|
25
|
+
transformKey: formatMdxEsmTransformCacheKey(CACHE_NAMESPACE_SENTINEL, "__vf_project__", "_vf_modules/pages/index.js", "deadbeef"),
|
|
26
|
+
pathKey: formatMdxEsmPathCacheKey(CACHE_NAMESPACE_SENTINEL, "_vf_modules/pages/index.js"),
|
|
27
|
+
moduleFile: formatMdxEsmModuleFileName(CACHE_NAMESPACE_SENTINEL, "deadbeef"),
|
|
28
|
+
jsxFile: formatMdxJsxCacheFileName(CACHE_NAMESPACE_SENTINEL, "/tmp/project/Button.tsx"),
|
|
29
|
+
unresolvedVfModulesPattern: UNRESOLVED_VF_MODULES_PATTERN.source,
|
|
30
|
+
allFileUrlPattern: ALL_FILE_URL_PATTERN_SOURCE,
|
|
31
|
+
mjsFileUrlPattern: MJS_FILE_URL_PATTERN_SOURCE,
|
|
32
|
+
sourceHashing: [
|
|
33
|
+
hashString("_vf_modules/pages/index.jsexport default 1;"),
|
|
34
|
+
hashString("/tmp/project/Button.tsx"),
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function buildFrameworkVfModuleCacheSchemaSample() {
|
|
39
|
+
return {
|
|
40
|
+
moduleFile: formatFrameworkVfModuleCacheFileName(CACHE_NAMESPACE_SENTINEL, hashCodeHex("_vf_modules/_veryfront/react/components/Head.js"), hashCodeHex("/app/.cache/veryfront-mdx-esm").slice(0, 8), hashCodeHex("export default function Head() {}")),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export const MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE = ALL_FILE_URL_PATTERN_SOURCE;
|
|
44
|
+
export const MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE = MJS_FILE_URL_PATTERN_SOURCE;
|
|
45
|
+
export const MDX_ESM_CACHE_NAMESPACE = createCacheNamespace("mdx-esm", buildMdxEsmCacheSchemaSample());
|
|
46
|
+
export const FRAMEWORK_VF_MODULE_CACHE_NAMESPACE = createCacheNamespace("vf-framework", buildFrameworkVfModuleCacheSchemaSample());
|
|
47
|
+
export function buildMdxEsmTransformCacheKey(projectId, normalizedPath, contentHash) {
|
|
48
|
+
return formatMdxEsmTransformCacheKey(MDX_ESM_CACHE_NAMESPACE, projectId, normalizedPath, contentHash);
|
|
49
|
+
}
|
|
50
|
+
export function buildMdxEsmPathCacheKey(normalizedPath) {
|
|
51
|
+
return formatMdxEsmPathCacheKey(MDX_ESM_CACHE_NAMESPACE, normalizedPath);
|
|
52
|
+
}
|
|
53
|
+
export function buildMdxEsmModuleFileName(contentHash) {
|
|
54
|
+
return formatMdxEsmModuleFileName(MDX_ESM_CACHE_NAMESPACE, contentHash);
|
|
55
|
+
}
|
|
56
|
+
export function buildMdxJsxCacheFileName(filePath) {
|
|
57
|
+
return formatMdxJsxCacheFileName(MDX_ESM_CACHE_NAMESPACE, filePath);
|
|
58
|
+
}
|
|
59
|
+
export function buildFrameworkVfModuleCacheFileName(pathHash, envKey, contentHash) {
|
|
60
|
+
return formatFrameworkVfModuleCacheFileName(FRAMEWORK_VF_MODULE_CACHE_NAMESPACE, pathHash, envKey, contentHash);
|
|
61
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-transformer.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/mdx/esm-module-loader/import-transformer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"import-transformer.d.ts","sourceRoot":"","sources":["../../../../../src/src/transforms/mdx/esm-module-loader/import-transformer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAe5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/D;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK9E;AAyBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,eAAe,GAAG,MAAM,CAIjF;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,EACpC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CA0HjB"}
|
|
@@ -9,12 +9,11 @@
|
|
|
9
9
|
import { join } from "../../../platform/compat/path/index.js";
|
|
10
10
|
import { rendererLogger as logger } from "../../../utils/index.js";
|
|
11
11
|
import { transformImportsWithMap } from "../../../modules/import-map/index.js";
|
|
12
|
-
import { VERSION } from "../../../utils/version.js";
|
|
13
12
|
import { replaceSpecifiers } from "../../esm/lexer.js";
|
|
14
13
|
import { getLocalReactPaths, isReactSpecifier } from "../../../platform/compat/react-paths.js";
|
|
15
14
|
import { ESBUILD_JSX_FACTORY, ESBUILD_JSX_FRAGMENT, FRAMEWORK_ROOT, JSX_IMPORT_PATTERN, LOG_PREFIX_MDX_LOADER, REACT_IMPORT_PATTERN, } from "./constants.js";
|
|
16
15
|
import { getLocalFs } from "./cache/index.js";
|
|
17
|
-
import {
|
|
16
|
+
import { buildMdxJsxCacheFileName } from "./cache-format.js";
|
|
18
17
|
import { rewriteDntImports } from "./module-fetcher/index.js";
|
|
19
18
|
import { ensureCachedJsxModulePatched } from "./jsx-cache.js";
|
|
20
19
|
/**
|
|
@@ -93,7 +92,7 @@ export async function transformJsxImports(code, adapter, esmCacheDir) {
|
|
|
93
92
|
logger.debug(`${LOG_PREFIX_MDX_LOADER} Transforming ${importsToProcess.length} JSX imports in parallel`);
|
|
94
93
|
const transformResults = await Promise.all(importsToProcess.map(async ({ fullMatch, importClause, filePath, ext }) => {
|
|
95
94
|
try {
|
|
96
|
-
const transformedFileName =
|
|
95
|
+
const transformedFileName = buildMdxJsxCacheFileName(filePath);
|
|
97
96
|
const transformedPath = join(esmCacheDir, transformedFileName);
|
|
98
97
|
try {
|
|
99
98
|
const stat = await getLocalFs().stat(transformedPath);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module transforms/mdx/esm-module-loader/module-fetcher/cache-keys
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { buildMdxEsmPathCacheKey, buildMdxEsmTransformCacheKey } from "../cache-format.js";
|
|
7
7
|
/**
|
|
8
8
|
* Build cache key for transformed module.
|
|
9
9
|
* Includes content hash so cache invalidates when source changes.
|
|
@@ -12,8 +12,8 @@ import { VERSION } from "../../../../utils/version.js";
|
|
|
12
12
|
* that use relative paths (../lib/utils.js) instead of absolute paths (/_vf_modules/lib/utils.js).
|
|
13
13
|
*/
|
|
14
14
|
export function getTransformCacheKey(projectId, normalizedPath, contentHash) {
|
|
15
|
-
return
|
|
15
|
+
return buildMdxEsmTransformCacheKey(projectId, normalizedPath, contentHash);
|
|
16
16
|
}
|
|
17
17
|
export function getVersionedPathCacheKey(normalizedPath) {
|
|
18
|
-
return
|
|
18
|
+
return buildMdxEsmPathCacheKey(normalizedPath);
|
|
19
19
|
}
|
package/esm/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework-validator.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"framework-validator.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/framework-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAQjE;;;;;;;;;;;;GAYG;AACH,wBAAsB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAqE/F;AAED;;;;;;GAMG;AACH,wBAAsB,iCAAiC,CACrD,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB;AAYD,wBAAsB,oBAAoB,CACxC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAkDlB"}
|
|
@@ -11,6 +11,7 @@ import { FRAMEWORK_ROOT, LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
|
11
11
|
import { getLocalFs } from "../cache/index.js";
|
|
12
12
|
import { extractHttpBundlePaths } from "../../../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
|
|
13
13
|
import { ensureHttpBundlesExist } from "../../../esm/http-cache.js";
|
|
14
|
+
import { MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE } from "../cache-format.js";
|
|
14
15
|
/**
|
|
15
16
|
* Check if cached code has file:// paths that are incompatible with this environment.
|
|
16
17
|
* Returns true if the cached code should be invalidated (has paths from a different environment).
|
|
@@ -97,7 +98,7 @@ export async function hasIncompatibleFrameworkPaths(code, log) {
|
|
|
97
98
|
*/
|
|
98
99
|
export async function findMissingFileDependenciesInCode(code, log) {
|
|
99
100
|
const localFs = getLocalFs();
|
|
100
|
-
const pattern =
|
|
101
|
+
const pattern = new RegExp(MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE, "gi");
|
|
101
102
|
const missing = [];
|
|
102
103
|
const checked = new Set();
|
|
103
104
|
let match;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module-cache.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/module-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"module-cache.d.ts","sourceRoot":"","sources":["../../../../../../src/src/transforms/mdx/esm-module-loader/module-fetcher/module-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAC;AAQjE;;GAEG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,MAAM,CAanF;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAmCxB"}
|
|
@@ -8,11 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { join } from "../../../../platform/compat/path/index.js";
|
|
10
10
|
import * as posix from "../../../../../deps/jsr.io/@std/path/1.1.4/posix/mod.js";
|
|
11
|
-
import { VERSION } from "../../../../utils/version.js";
|
|
12
11
|
import { LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
13
12
|
import { getLocalFs, saveModulePathCache } from "../cache/index.js";
|
|
14
13
|
import { hashString } from "../utils/hash.js";
|
|
15
|
-
import {
|
|
14
|
+
import { buildMdxEsmModuleFileName, buildMdxEsmPathCacheKey } from "../cache-format.js";
|
|
16
15
|
import { hasUnresolvedImports } from "./nested-imports.js";
|
|
17
16
|
import { recordModuleToSession } from "./render-sessions.js";
|
|
18
17
|
/**
|
|
@@ -46,12 +45,13 @@ export async function cacheModule(normalizedPath, moduleCode, esmCacheDir, pathC
|
|
|
46
45
|
return null;
|
|
47
46
|
}
|
|
48
47
|
const contentHash = hashString(normalizedPath + moduleCode);
|
|
49
|
-
const cachePath = join(esmCacheDir,
|
|
48
|
+
const cachePath = join(esmCacheDir, buildMdxEsmModuleFileName(contentHash));
|
|
49
|
+
const pathCacheKey = buildMdxEsmPathCacheKey(normalizedPath);
|
|
50
50
|
const localFs = getLocalFs();
|
|
51
51
|
try {
|
|
52
52
|
const stat = await localFs.stat(cachePath);
|
|
53
53
|
if (stat?.isFile) {
|
|
54
|
-
pathCache.set(
|
|
54
|
+
pathCache.set(pathCacheKey, cachePath);
|
|
55
55
|
log.debug(`${LOG_PREFIX_MDX_LOADER} Content cache hit: ${normalizedPath}`);
|
|
56
56
|
recordModuleToSession(normalizedPath);
|
|
57
57
|
return cachePath;
|
|
@@ -62,7 +62,7 @@ export async function cacheModule(normalizedPath, moduleCode, esmCacheDir, pathC
|
|
|
62
62
|
}
|
|
63
63
|
await localFs.mkdir(esmCacheDir, { recursive: true });
|
|
64
64
|
await localFs.writeTextFile(cachePath, moduleCode);
|
|
65
|
-
pathCache.set(
|
|
65
|
+
pathCache.set(pathCacheKey, cachePath);
|
|
66
66
|
await saveModulePathCache(esmCacheDir);
|
|
67
67
|
log.debug(`${LOG_PREFIX_MDX_LOADER} Cached vf_module: ${normalizedPath} -> ${cachePath}`);
|
|
68
68
|
recordModuleToSession(normalizedPath);
|
|
@@ -16,10 +16,10 @@ export declare function isCyclePlaceholder(code: string): boolean;
|
|
|
16
16
|
/**
|
|
17
17
|
* Cache transformed framework code and return the file:// path.
|
|
18
18
|
*
|
|
19
|
-
* Cache key format: vfmod-{
|
|
19
|
+
* Cache key format: vfmod-{namespace}-{pathHash}-{envKey}-{contentHash}.mjs
|
|
20
20
|
*
|
|
21
21
|
* Cache invalidation is handled by:
|
|
22
|
-
* -
|
|
22
|
+
* - namespace prefix: Auto-rolls when the framework vfmod cache shape changes
|
|
23
23
|
* - envKey (FRAMEWORK_ROOT hash): Prevents cross-environment contamination
|
|
24
24
|
* (compiled binary vs source have different FRAMEWORK_ROOT values)
|
|
25
25
|
* - contentHash: Content-based invalidation
|
|
@@ -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;AAarE,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;AAED;;;;;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,CAyQjB;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"}
|
|
@@ -13,11 +13,11 @@ import { hashCodeHex } from "../../../../utils/hash-utils.js";
|
|
|
13
13
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../../utils/cache-dir.js";
|
|
14
14
|
import { cacheHttpImportsToLocal } from "../../../esm/http-cache.js";
|
|
15
15
|
import { loadImportMap } from "../../../../modules/import-map/index.js";
|
|
16
|
-
import { VERSION } from "../../../../utils/version.js";
|
|
17
16
|
import { buildReactUrl, getReactImportMap } from "../../../import-rewriter/url-builder.js";
|
|
18
17
|
import { findRelativeImports } from "./import-finder.js";
|
|
19
18
|
import { resolveRelativeFrameworkImport, resolveVeryfrontSourcePath } from "./path-resolver.js";
|
|
20
19
|
import { EMBEDDED_SRC_DIR, FRAMEWORK_ROOT, frameworkFileCache, frameworkWriteFlight, LOG_PREFIX, MAX_RELATIVE_IMPORT_DEPTH, transformingFiles, veryfrontTransformCache, } from "./constants.js";
|
|
20
|
+
import { buildFrameworkVfModuleCacheFileName } from "../../../mdx/esm-module-loader/cache-format.js";
|
|
21
21
|
const DENO_CONFIG_STUB_CODE = `export default ${JSON.stringify(denoConfig)};`;
|
|
22
22
|
/**
|
|
23
23
|
* Check if a transformed code string is a cycle placeholder.
|
|
@@ -31,10 +31,10 @@ export function isCyclePlaceholder(code) {
|
|
|
31
31
|
/**
|
|
32
32
|
* Cache transformed framework code and return the file:// path.
|
|
33
33
|
*
|
|
34
|
-
* Cache key format: vfmod-{
|
|
34
|
+
* Cache key format: vfmod-{namespace}-{pathHash}-{envKey}-{contentHash}.mjs
|
|
35
35
|
*
|
|
36
36
|
* Cache invalidation is handled by:
|
|
37
|
-
* -
|
|
37
|
+
* - namespace prefix: Auto-rolls when the framework vfmod cache shape changes
|
|
38
38
|
* - envKey (FRAMEWORK_ROOT hash): Prevents cross-environment contamination
|
|
39
39
|
* (compiled binary vs source have different FRAMEWORK_ROOT values)
|
|
40
40
|
* - contentHash: Content-based invalidation
|
|
@@ -47,7 +47,7 @@ export async function cacheTransformedCode(transformed, vfModulePath, fs) {
|
|
|
47
47
|
const envKey = hashCodeHex(FRAMEWORK_ROOT).slice(0, 8);
|
|
48
48
|
const contentHash = hashCodeHex(transformed);
|
|
49
49
|
const pathHash = hashCodeHex(vfModulePath);
|
|
50
|
-
const fileName =
|
|
50
|
+
const fileName = buildFrameworkVfModuleCacheFileName(pathHash, envKey, contentHash);
|
|
51
51
|
const frameworkCacheDir = join(cacheDir, "framework");
|
|
52
52
|
const cachePath = join(frameworkCacheDir, fileName);
|
|
53
53
|
// Use Singleflight to prevent concurrent writes to the same file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type CacheNamespaceValue = string | number | boolean | null | readonly CacheNamespaceValue[] | {
|
|
2
|
+
readonly [key: string]: CacheNamespaceValue;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* Build a deterministic cache namespace from a declarative schema description.
|
|
6
|
+
* Keep the schema close to the cache builders so format changes roll the
|
|
7
|
+
* namespace automatically instead of relying on a manually bumped constant.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createCacheNamespace(scope: string, schema: CacheNamespaceValue, length?: number): string;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=cache-namespace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-namespace.d.ts","sourceRoot":"","sources":["../../../src/src/utils/cache-namespace.ts"],"names":[],"mappings":"AAEA,KAAK,mBAAmB,GACpB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,mBAAmB,EAAE,GAC9B;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,mBAAmB,CAAA;CAAE,CAAC;AAqBpD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,mBAAmB,EAC3B,MAAM,SAAK,GACV,MAAM,CAGR"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { fnv1aHash } from "./hash-utils.js";
|
|
2
|
+
function serializeCacheNamespaceValue(value) {
|
|
3
|
+
if (value === null)
|
|
4
|
+
return "null";
|
|
5
|
+
if (Array.isArray(value)) {
|
|
6
|
+
return `[${value.map((entry) => serializeCacheNamespaceValue(entry)).join(",")}]`;
|
|
7
|
+
}
|
|
8
|
+
if (typeof value === "object") {
|
|
9
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
10
|
+
return `{${entries
|
|
11
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${serializeCacheNamespaceValue(entry)}`)
|
|
12
|
+
.join(",")}}`;
|
|
13
|
+
}
|
|
14
|
+
return JSON.stringify(value);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build a deterministic cache namespace from a declarative schema description.
|
|
18
|
+
* Keep the schema close to the cache builders so format changes roll the
|
|
19
|
+
* namespace automatically instead of relying on a manually bumped constant.
|
|
20
|
+
*/
|
|
21
|
+
export function createCacheNamespace(scope, schema, length = 10) {
|
|
22
|
+
const serialized = serializeCacheNamespaceValue(schema);
|
|
23
|
+
return `${scope}-${fnv1aHash(serialized).slice(0, length)}`;
|
|
24
|
+
}
|
package/esm/src/utils/version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Keep in sync with deno.json version.
|
|
2
2
|
// scripts/release.ts updates this constant during releases.
|
|
3
|
-
export const VERSION = "0.1.
|
|
3
|
+
export const VERSION = "0.1.89";
|
|
4
4
|
export const SERVER_START_TIME = Date.now();
|
|
5
5
|
export function createBuildVersion(projectUpdatedAt) {
|
|
6
6
|
return {
|
package/package.json
CHANGED
package/src/deno.js
CHANGED
|
@@ -25,12 +25,12 @@ import { validateCachedBundlesByManifestOrCode } from "../../../transforms/esm/c
|
|
|
25
25
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../utils/cache-dir.js";
|
|
26
26
|
import { dirname, join, normalize } from "../../../platform/compat/path/index.js";
|
|
27
27
|
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
28
|
-
import { VERSION } from "../../../utils/version.js";
|
|
29
28
|
import {
|
|
30
29
|
getModulePathCache,
|
|
31
30
|
lookupMdxEsmCache,
|
|
32
31
|
saveModulePathCache,
|
|
33
32
|
} from "../../../transforms/mdx/esm-module-loader/cache/index.js";
|
|
33
|
+
import { buildMdxEsmPathCacheKey } from "../../../transforms/mdx/esm-module-loader/cache-format.js";
|
|
34
34
|
|
|
35
35
|
const logger = rendererLogger.component("module-loader");
|
|
36
36
|
|
|
@@ -455,7 +455,7 @@ export async function transformModuleWithDeps(
|
|
|
455
455
|
|
|
456
456
|
if (contentSourceId) {
|
|
457
457
|
const normalizedPath = `_vf_modules/${relativePath.replace(/\.(tsx?|jsx|mdx)$/, ".js")}`;
|
|
458
|
-
const mdxCacheKey =
|
|
458
|
+
const mdxCacheKey = buildMdxEsmPathCacheKey(normalizedPath);
|
|
459
459
|
const cache = await getModulePathCache(tmpDir);
|
|
460
460
|
cache.set(mdxCacheKey, tempFilePath);
|
|
461
461
|
|
|
@@ -18,9 +18,9 @@ import {
|
|
|
18
18
|
type FileSystem,
|
|
19
19
|
isNotFoundError,
|
|
20
20
|
} from "../../../../platform/compat/fs.js";
|
|
21
|
-
import { VERSION } from "../../../../utils/version.js";
|
|
22
21
|
import { LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
23
22
|
import { LRUCache } from "../../../../utils/lru-wrapper.js";
|
|
23
|
+
import { buildMdxEsmPathCacheKey, MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE } from "../cache-format.js";
|
|
24
24
|
|
|
25
25
|
export type CacheLookupResult =
|
|
26
26
|
| { status: "hit"; path: string }
|
|
@@ -33,8 +33,6 @@ export const verifiedModuleDeps = new LRUCache<string, true>({
|
|
|
33
33
|
maxEntries: MAX_VERIFIED_MODULE_DEPS,
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
const FILE_PATH_PATTERN = /file:\/\/([^"'\s]+)/gi;
|
|
37
|
-
|
|
38
36
|
/**
|
|
39
37
|
* Check if cached code has file:// paths from a different environment.
|
|
40
38
|
* Checks both HTTP bundle paths and MDX ESM cache paths.
|
|
@@ -43,7 +41,7 @@ function hasIncompatibleCachePaths(code: string): boolean {
|
|
|
43
41
|
const localCacheBaseDir = getCacheBaseDir();
|
|
44
42
|
const localHttpCacheDir = getHttpBundleCacheDir();
|
|
45
43
|
const localMdxCacheDir = getMdxEsmCacheDir();
|
|
46
|
-
const pattern = new RegExp(
|
|
44
|
+
const pattern = new RegExp(MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE, "gi");
|
|
47
45
|
|
|
48
46
|
let match: RegExpExecArray | null;
|
|
49
47
|
while ((match = pattern.exec(code)) !== null) {
|
|
@@ -87,7 +85,7 @@ function hasIncompatibleCachePaths(code: string): boolean {
|
|
|
87
85
|
*/
|
|
88
86
|
async function findMissingFileDependencies(code: string): Promise<string[]> {
|
|
89
87
|
const localFs = getLocalFs();
|
|
90
|
-
const pattern = new RegExp(
|
|
88
|
+
const pattern = new RegExp(MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE, "gi");
|
|
91
89
|
const missing: string[] = [];
|
|
92
90
|
let match;
|
|
93
91
|
while ((match = pattern.exec(code)) !== null) {
|
|
@@ -335,7 +333,7 @@ function toMdxEsmCacheKey(filePath: string, projectDir?: string): string {
|
|
|
335
333
|
relativePath = relativePath.replace(/^\/+/, "");
|
|
336
334
|
const jsPath = relativePath.replace(/\.(tsx?|jsx|mdx)$/, ".js");
|
|
337
335
|
|
|
338
|
-
return `
|
|
336
|
+
return buildMdxEsmPathCacheKey(`_vf_modules/${jsPath}`);
|
|
339
337
|
}
|
|
340
338
|
|
|
341
339
|
export async function lookupMdxEsmCache(
|
|
@@ -429,9 +427,9 @@ export async function lookupMdxEsmCache(
|
|
|
429
427
|
}
|
|
430
428
|
|
|
431
429
|
// Note: We intentionally skip contentHash validation for MDX-ESM cached files.
|
|
432
|
-
// The MDX-ESM cache uses transformed-code hashes in filenames
|
|
430
|
+
// The MDX-ESM cache uses transformed-code hashes in namespaced filenames,
|
|
433
431
|
// while the SSR loader provides source-code hashes. These will never match.
|
|
434
|
-
// The cache
|
|
432
|
+
// The cache namespace in the key provides sufficient staleness protection,
|
|
435
433
|
// and the file's existence confirms it's a valid transform for this codebase.
|
|
436
434
|
// This allows both loaders to share the same module instance, preventing
|
|
437
435
|
// duplicate React contexts which break hooks like useContext.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { hashCodeHex } from "../../../utils/hash-utils.js";
|
|
2
|
+
import { createCacheNamespace } from "../../../utils/cache-namespace.js";
|
|
3
|
+
import { UNRESOLVED_VF_MODULES_PATTERN } from "./constants.js";
|
|
4
|
+
import { hashString } from "./utils/hash.js";
|
|
5
|
+
|
|
6
|
+
const ALL_FILE_URL_PATTERN_SOURCE = /file:\/\/([^"'\s]+)/.source;
|
|
7
|
+
const MJS_FILE_URL_PATTERN_SOURCE = /file:\/\/([^"'\s]+\.mjs)/.source;
|
|
8
|
+
const CACHE_NAMESPACE_SENTINEL = "__vf_cache_namespace__";
|
|
9
|
+
|
|
10
|
+
function formatMdxEsmTransformCacheKey(
|
|
11
|
+
namespace: string,
|
|
12
|
+
projectId: string,
|
|
13
|
+
normalizedPath: string,
|
|
14
|
+
contentHash: string,
|
|
15
|
+
): string {
|
|
16
|
+
return `${namespace}:${projectId}:${normalizedPath}:${contentHash}:ssr`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function formatMdxEsmPathCacheKey(namespace: string, normalizedPath: string): string {
|
|
20
|
+
return `${namespace}:${normalizedPath}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function formatMdxEsmModuleFileName(namespace: string, contentHash: string): string {
|
|
24
|
+
return `vfmod-${namespace}-${contentHash}.mjs`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function formatMdxJsxCacheFileName(namespace: string, filePath: string): string {
|
|
28
|
+
return `jsx-${namespace}-${hashString(filePath)}.mjs`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function formatFrameworkVfModuleCacheFileName(
|
|
32
|
+
namespace: string,
|
|
33
|
+
pathHash: string,
|
|
34
|
+
envKey: string,
|
|
35
|
+
contentHash: string,
|
|
36
|
+
): string {
|
|
37
|
+
return `vfmod-${namespace}-${pathHash}-${envKey}-${contentHash}.mjs`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildMdxEsmCacheSchemaSample() {
|
|
41
|
+
return {
|
|
42
|
+
transformKey: formatMdxEsmTransformCacheKey(
|
|
43
|
+
CACHE_NAMESPACE_SENTINEL,
|
|
44
|
+
"__vf_project__",
|
|
45
|
+
"_vf_modules/pages/index.js",
|
|
46
|
+
"deadbeef",
|
|
47
|
+
),
|
|
48
|
+
pathKey: formatMdxEsmPathCacheKey(CACHE_NAMESPACE_SENTINEL, "_vf_modules/pages/index.js"),
|
|
49
|
+
moduleFile: formatMdxEsmModuleFileName(CACHE_NAMESPACE_SENTINEL, "deadbeef"),
|
|
50
|
+
jsxFile: formatMdxJsxCacheFileName(CACHE_NAMESPACE_SENTINEL, "/tmp/project/Button.tsx"),
|
|
51
|
+
unresolvedVfModulesPattern: UNRESOLVED_VF_MODULES_PATTERN.source,
|
|
52
|
+
allFileUrlPattern: ALL_FILE_URL_PATTERN_SOURCE,
|
|
53
|
+
mjsFileUrlPattern: MJS_FILE_URL_PATTERN_SOURCE,
|
|
54
|
+
sourceHashing: [
|
|
55
|
+
hashString("_vf_modules/pages/index.jsexport default 1;"),
|
|
56
|
+
hashString("/tmp/project/Button.tsx"),
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function buildFrameworkVfModuleCacheSchemaSample() {
|
|
62
|
+
return {
|
|
63
|
+
moduleFile: formatFrameworkVfModuleCacheFileName(
|
|
64
|
+
CACHE_NAMESPACE_SENTINEL,
|
|
65
|
+
hashCodeHex("_vf_modules/_veryfront/react/components/Head.js"),
|
|
66
|
+
hashCodeHex("/app/.cache/veryfront-mdx-esm").slice(0, 8),
|
|
67
|
+
hashCodeHex("export default function Head() {}"),
|
|
68
|
+
),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const MDX_ESM_ALL_FILE_URL_PATTERN_SOURCE = ALL_FILE_URL_PATTERN_SOURCE;
|
|
73
|
+
export const MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE = MJS_FILE_URL_PATTERN_SOURCE;
|
|
74
|
+
|
|
75
|
+
export const MDX_ESM_CACHE_NAMESPACE = createCacheNamespace(
|
|
76
|
+
"mdx-esm",
|
|
77
|
+
buildMdxEsmCacheSchemaSample(),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
export const FRAMEWORK_VF_MODULE_CACHE_NAMESPACE = createCacheNamespace(
|
|
81
|
+
"vf-framework",
|
|
82
|
+
buildFrameworkVfModuleCacheSchemaSample(),
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
export function buildMdxEsmTransformCacheKey(
|
|
86
|
+
projectId: string,
|
|
87
|
+
normalizedPath: string,
|
|
88
|
+
contentHash: string,
|
|
89
|
+
): string {
|
|
90
|
+
return formatMdxEsmTransformCacheKey(
|
|
91
|
+
MDX_ESM_CACHE_NAMESPACE,
|
|
92
|
+
projectId,
|
|
93
|
+
normalizedPath,
|
|
94
|
+
contentHash,
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function buildMdxEsmPathCacheKey(normalizedPath: string): string {
|
|
99
|
+
return formatMdxEsmPathCacheKey(MDX_ESM_CACHE_NAMESPACE, normalizedPath);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function buildMdxEsmModuleFileName(contentHash: string): string {
|
|
103
|
+
return formatMdxEsmModuleFileName(MDX_ESM_CACHE_NAMESPACE, contentHash);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function buildMdxJsxCacheFileName(filePath: string): string {
|
|
107
|
+
return formatMdxJsxCacheFileName(MDX_ESM_CACHE_NAMESPACE, filePath);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function buildFrameworkVfModuleCacheFileName(
|
|
111
|
+
pathHash: string,
|
|
112
|
+
envKey: string,
|
|
113
|
+
contentHash: string,
|
|
114
|
+
): string {
|
|
115
|
+
return formatFrameworkVfModuleCacheFileName(
|
|
116
|
+
FRAMEWORK_VF_MODULE_CACHE_NAMESPACE,
|
|
117
|
+
pathHash,
|
|
118
|
+
envKey,
|
|
119
|
+
contentHash,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
@@ -11,7 +11,6 @@ import { join } from "../../../platform/compat/path/index.js";
|
|
|
11
11
|
import { rendererLogger as logger } from "../../../utils/index.js";
|
|
12
12
|
import { transformImportsWithMap } from "../../../modules/import-map/index.js";
|
|
13
13
|
import type { ImportMapConfig } from "../../../modules/import-map/index.js";
|
|
14
|
-
import { VERSION } from "../../../utils/version.js";
|
|
15
14
|
import { replaceSpecifiers } from "../../esm/lexer.js";
|
|
16
15
|
import { getLocalReactPaths, isReactSpecifier } from "../../../platform/compat/react-paths.js";
|
|
17
16
|
import {
|
|
@@ -23,7 +22,7 @@ import {
|
|
|
23
22
|
REACT_IMPORT_PATTERN,
|
|
24
23
|
} from "./constants.js";
|
|
25
24
|
import { getLocalFs } from "./cache/index.js";
|
|
26
|
-
import {
|
|
25
|
+
import { buildMdxJsxCacheFileName } from "./cache-format.js";
|
|
27
26
|
import { rewriteDntImports } from "./module-fetcher/index.js";
|
|
28
27
|
import { ensureCachedJsxModulePatched } from "./jsx-cache.js";
|
|
29
28
|
import type { ESMLoaderContext } from "./types.js";
|
|
@@ -128,7 +127,7 @@ export async function transformJsxImports(
|
|
|
128
127
|
const transformResults = await Promise.all(
|
|
129
128
|
importsToProcess.map(async ({ fullMatch, importClause, filePath, ext }) => {
|
|
130
129
|
try {
|
|
131
|
-
const transformedFileName =
|
|
130
|
+
const transformedFileName = buildMdxJsxCacheFileName(filePath);
|
|
132
131
|
const transformedPath = join(esmCacheDir, transformedFileName);
|
|
133
132
|
|
|
134
133
|
try {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module transforms/mdx/esm-module-loader/module-fetcher/cache-keys
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { buildMdxEsmPathCacheKey, buildMdxEsmTransformCacheKey } from "../cache-format.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Build cache key for transformed module.
|
|
@@ -18,9 +18,9 @@ export function getTransformCacheKey(
|
|
|
18
18
|
normalizedPath: string,
|
|
19
19
|
contentHash: string,
|
|
20
20
|
): string {
|
|
21
|
-
return
|
|
21
|
+
return buildMdxEsmTransformCacheKey(projectId, normalizedPath, contentHash);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function getVersionedPathCacheKey(normalizedPath: string): string {
|
|
25
|
-
return
|
|
25
|
+
return buildMdxEsmPathCacheKey(normalizedPath);
|
|
26
26
|
}
|
|
@@ -13,6 +13,7 @@ import { FRAMEWORK_ROOT, LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
|
13
13
|
import { getLocalFs } from "../cache/index.js";
|
|
14
14
|
import { extractHttpBundlePaths } from "../../../../modules/react-loader/ssr-module-loader/http-bundle-helpers.js";
|
|
15
15
|
import { ensureHttpBundlesExist } from "../../../esm/http-cache.js";
|
|
16
|
+
import { MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE } from "../cache-format.js";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Check if cached code has file:// paths that are incompatible with this environment.
|
|
@@ -110,7 +111,7 @@ export async function findMissingFileDependenciesInCode(
|
|
|
110
111
|
log: Logger,
|
|
111
112
|
): Promise<string[]> {
|
|
112
113
|
const localFs = getLocalFs();
|
|
113
|
-
const pattern =
|
|
114
|
+
const pattern = new RegExp(MDX_ESM_MJS_FILE_URL_PATTERN_SOURCE, "gi");
|
|
114
115
|
const missing: string[] = [];
|
|
115
116
|
const checked = new Set<string>();
|
|
116
117
|
|
|
@@ -10,11 +10,10 @@
|
|
|
10
10
|
import { join } from "../../../../platform/compat/path/index.js";
|
|
11
11
|
import * as posix from "../../../../../deps/jsr.io/@std/path/1.1.4/posix/mod.js";
|
|
12
12
|
import type { Logger } from "../../../../utils/logger/logger.js";
|
|
13
|
-
import { VERSION } from "../../../../utils/version.js";
|
|
14
13
|
import { LOG_PREFIX_MDX_LOADER } from "../constants.js";
|
|
15
14
|
import { getLocalFs, saveModulePathCache } from "../cache/index.js";
|
|
16
15
|
import { hashString } from "../utils/hash.js";
|
|
17
|
-
import {
|
|
16
|
+
import { buildMdxEsmModuleFileName, buildMdxEsmPathCacheKey } from "../cache-format.js";
|
|
18
17
|
import { hasUnresolvedImports } from "./nested-imports.js";
|
|
19
18
|
import { recordModuleToSession } from "./render-sessions.js";
|
|
20
19
|
|
|
@@ -60,13 +59,14 @@ export async function cacheModule(
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
const contentHash = hashString(normalizedPath + moduleCode);
|
|
63
|
-
const cachePath = join(esmCacheDir,
|
|
62
|
+
const cachePath = join(esmCacheDir, buildMdxEsmModuleFileName(contentHash));
|
|
63
|
+
const pathCacheKey = buildMdxEsmPathCacheKey(normalizedPath);
|
|
64
64
|
|
|
65
65
|
const localFs = getLocalFs();
|
|
66
66
|
try {
|
|
67
67
|
const stat = await localFs.stat(cachePath);
|
|
68
68
|
if (stat?.isFile) {
|
|
69
|
-
pathCache.set(
|
|
69
|
+
pathCache.set(pathCacheKey, cachePath);
|
|
70
70
|
log.debug(`${LOG_PREFIX_MDX_LOADER} Content cache hit: ${normalizedPath}`);
|
|
71
71
|
recordModuleToSession(normalizedPath);
|
|
72
72
|
return cachePath;
|
|
@@ -77,7 +77,7 @@ export async function cacheModule(
|
|
|
77
77
|
|
|
78
78
|
await localFs.mkdir(esmCacheDir, { recursive: true });
|
|
79
79
|
await localFs.writeTextFile(cachePath, moduleCode);
|
|
80
|
-
pathCache.set(
|
|
80
|
+
pathCache.set(pathCacheKey, cachePath);
|
|
81
81
|
await saveModulePathCache(esmCacheDir);
|
|
82
82
|
log.debug(`${LOG_PREFIX_MDX_LOADER} Cached vf_module: ${normalizedPath} -> ${cachePath}`);
|
|
83
83
|
|
|
@@ -15,7 +15,6 @@ import { hashCodeHex } from "../../../../utils/hash-utils.js";
|
|
|
15
15
|
import { getHttpBundleCacheDir, getMdxEsmCacheDir } from "../../../../utils/cache-dir.js";
|
|
16
16
|
import { cacheHttpImportsToLocal } from "../../../esm/http-cache.js";
|
|
17
17
|
import { loadImportMap } from "../../../../modules/import-map/index.js";
|
|
18
|
-
import { VERSION } from "../../../../utils/version.js";
|
|
19
18
|
import { buildReactUrl, getReactImportMap } from "../../../import-rewriter/url-builder.js";
|
|
20
19
|
import { findRelativeImports } from "./import-finder.js";
|
|
21
20
|
import { resolveRelativeFrameworkImport, resolveVeryfrontSourcePath } from "./path-resolver.js";
|
|
@@ -30,6 +29,7 @@ import {
|
|
|
30
29
|
transformingFiles,
|
|
31
30
|
veryfrontTransformCache,
|
|
32
31
|
} from "./constants.js";
|
|
32
|
+
import { buildFrameworkVfModuleCacheFileName } from "../../../mdx/esm-module-loader/cache-format.js";
|
|
33
33
|
|
|
34
34
|
const DENO_CONFIG_STUB_CODE = `export default ${JSON.stringify(denoConfig)};`;
|
|
35
35
|
|
|
@@ -46,10 +46,10 @@ export function isCyclePlaceholder(code: string): boolean {
|
|
|
46
46
|
/**
|
|
47
47
|
* Cache transformed framework code and return the file:// path.
|
|
48
48
|
*
|
|
49
|
-
* Cache key format: vfmod-{
|
|
49
|
+
* Cache key format: vfmod-{namespace}-{pathHash}-{envKey}-{contentHash}.mjs
|
|
50
50
|
*
|
|
51
51
|
* Cache invalidation is handled by:
|
|
52
|
-
* -
|
|
52
|
+
* - namespace prefix: Auto-rolls when the framework vfmod cache shape changes
|
|
53
53
|
* - envKey (FRAMEWORK_ROOT hash): Prevents cross-environment contamination
|
|
54
54
|
* (compiled binary vs source have different FRAMEWORK_ROOT values)
|
|
55
55
|
* - contentHash: Content-based invalidation
|
|
@@ -66,7 +66,7 @@ export async function cacheTransformedCode(
|
|
|
66
66
|
const envKey = hashCodeHex(FRAMEWORK_ROOT).slice(0, 8);
|
|
67
67
|
const contentHash = hashCodeHex(transformed);
|
|
68
68
|
const pathHash = hashCodeHex(vfModulePath);
|
|
69
|
-
const fileName =
|
|
69
|
+
const fileName = buildFrameworkVfModuleCacheFileName(pathHash, envKey, contentHash);
|
|
70
70
|
const frameworkCacheDir = join(cacheDir, "framework");
|
|
71
71
|
const cachePath = join(frameworkCacheDir, fileName);
|
|
72
72
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { fnv1aHash } from "./hash-utils.js";
|
|
2
|
+
|
|
3
|
+
type CacheNamespaceValue =
|
|
4
|
+
| string
|
|
5
|
+
| number
|
|
6
|
+
| boolean
|
|
7
|
+
| null
|
|
8
|
+
| readonly CacheNamespaceValue[]
|
|
9
|
+
| { readonly [key: string]: CacheNamespaceValue };
|
|
10
|
+
|
|
11
|
+
function serializeCacheNamespaceValue(value: CacheNamespaceValue): string {
|
|
12
|
+
if (value === null) return "null";
|
|
13
|
+
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return `[${value.map((entry) => serializeCacheNamespaceValue(entry)).join(",")}]`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (typeof value === "object") {
|
|
19
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
20
|
+
return `{${
|
|
21
|
+
entries
|
|
22
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${serializeCacheNamespaceValue(entry)}`)
|
|
23
|
+
.join(",")
|
|
24
|
+
}}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return JSON.stringify(value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Build a deterministic cache namespace from a declarative schema description.
|
|
32
|
+
* Keep the schema close to the cache builders so format changes roll the
|
|
33
|
+
* namespace automatically instead of relying on a manually bumped constant.
|
|
34
|
+
*/
|
|
35
|
+
export function createCacheNamespace(
|
|
36
|
+
scope: string,
|
|
37
|
+
schema: CacheNamespaceValue,
|
|
38
|
+
length = 10,
|
|
39
|
+
): string {
|
|
40
|
+
const serialized = serializeCacheNamespaceValue(schema);
|
|
41
|
+
return `${scope}-${fnv1aHash(serialized).slice(0, length)}`;
|
|
42
|
+
}
|
package/src/src/utils/version.ts
CHANGED