@reckona/mreact-router 0.0.120 → 0.0.121
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/build.d.ts +1 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +64 -45
- package/dist/build.js.map +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +15 -1
- package/dist/client.js.map +1 -1
- package/dist/module-runner.js +14 -6
- package/dist/module-runner.js.map +1 -1
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +19 -2
- package/dist/render.js.map +1 -1
- package/package.json +11 -11
- package/src/build.ts +478 -370
- package/src/client.ts +34 -11
- package/src/module-runner.ts +26 -11
- package/src/render.ts +20 -2
package/src/build.ts
CHANGED
|
@@ -39,9 +39,7 @@ import {
|
|
|
39
39
|
} from "./module-runner.js";
|
|
40
40
|
import { scanAppRoutes } from "./routes.js";
|
|
41
41
|
import type { AppRoute } from "./routes.js";
|
|
42
|
-
import {
|
|
43
|
-
appFileConventionForRootFilename,
|
|
44
|
-
} from "./file-conventions.js";
|
|
42
|
+
import { appFileConventionForRootFilename } from "./file-conventions.js";
|
|
45
43
|
import {
|
|
46
44
|
resolveAppRouterProjectOptions,
|
|
47
45
|
resolveBuildTargets,
|
|
@@ -210,6 +208,7 @@ export interface BuiltRouteSourceAnalysisSummary {
|
|
|
210
208
|
authIncludesClaims: boolean;
|
|
211
209
|
cachePolicy?: RouteCachePolicy | undefined;
|
|
212
210
|
clientBoundaryImports: readonly string[];
|
|
211
|
+
clientBoundaryFallbackImports: readonly string[];
|
|
213
212
|
clientRoute: boolean;
|
|
214
213
|
hasLoader: boolean;
|
|
215
214
|
routeCode: string;
|
|
@@ -233,6 +232,7 @@ interface BuildSourceAnalysis {
|
|
|
233
232
|
|
|
234
233
|
interface BuildRouteSourceAnalysis extends BuildSourceAnalysis {
|
|
235
234
|
clientBoundaryImports: readonly string[];
|
|
235
|
+
clientBoundaryFallbackImports: readonly string[];
|
|
236
236
|
clientRoute: boolean;
|
|
237
237
|
file: string;
|
|
238
238
|
route: AppRoute & { kind: "page" };
|
|
@@ -428,7 +428,11 @@ export async function buildApp(options: BuildAppOptions): Promise<BuildAppResult
|
|
|
428
428
|
}));
|
|
429
429
|
const [serverModuleArtifacts, clientBundle] = await Promise.all([
|
|
430
430
|
timingSink === undefined
|
|
431
|
-
? writeServerModuleArtifactFiles(
|
|
431
|
+
? writeServerModuleArtifactFiles(
|
|
432
|
+
serverDir,
|
|
433
|
+
serverModules,
|
|
434
|
+
generatedImportPolicy.runtimePackages,
|
|
435
|
+
)
|
|
432
436
|
: timeBuildPhase(timingSink, "serverModuleArtifacts", () =>
|
|
433
437
|
writeServerModuleArtifactFiles(
|
|
434
438
|
serverDir,
|
|
@@ -743,6 +747,7 @@ async function analyzeBuildRouteSources(options: {
|
|
|
743
747
|
{
|
|
744
748
|
...analyzeBuildSource(source, route.file),
|
|
745
749
|
clientBoundaryImports: clientInference.clientBoundaryImports,
|
|
750
|
+
clientBoundaryFallbackImports: clientInference.clientBoundaryFallbackImports,
|
|
746
751
|
clientRoute: clientInference.client,
|
|
747
752
|
file,
|
|
748
753
|
route,
|
|
@@ -1204,7 +1209,11 @@ async function collectRuntimeOptionalPackages(options: {
|
|
|
1204
1209
|
{ packageName: options.packageName, optional: false, startDir: options.projectRoot },
|
|
1205
1210
|
];
|
|
1206
1211
|
|
|
1207
|
-
for (
|
|
1212
|
+
for (
|
|
1213
|
+
let index = 0;
|
|
1214
|
+
index < queue.length && seenPackageJson.size < maxRuntimePackageManifestReads;
|
|
1215
|
+
index += 1
|
|
1216
|
+
) {
|
|
1208
1217
|
const item = queue[index];
|
|
1209
1218
|
if (item === undefined || !isValidRuntimePackageName(item.packageName)) {
|
|
1210
1219
|
continue;
|
|
@@ -1300,7 +1309,11 @@ async function findRuntimePackageJson(
|
|
|
1300
1309
|
}
|
|
1301
1310
|
|
|
1302
1311
|
function isRuntimePackageSpecifier(specifier: string): boolean {
|
|
1303
|
-
if (
|
|
1312
|
+
if (
|
|
1313
|
+
specifier.startsWith(".") ||
|
|
1314
|
+
specifier.startsWith("/") ||
|
|
1315
|
+
/^[A-Za-z][A-Za-z0-9+.-]*:/.test(specifier)
|
|
1316
|
+
) {
|
|
1304
1317
|
return false;
|
|
1305
1318
|
}
|
|
1306
1319
|
|
|
@@ -1428,7 +1441,11 @@ function isSourceModuleFile(file: string): boolean {
|
|
|
1428
1441
|
}
|
|
1429
1442
|
|
|
1430
1443
|
function isAppRelativeFile(file: string, relativeRoutesDir: string): boolean {
|
|
1431
|
-
return
|
|
1444
|
+
return (
|
|
1445
|
+
relativeRoutesDir === "" ||
|
|
1446
|
+
file === relativeRoutesDir ||
|
|
1447
|
+
file.startsWith(`${relativeRoutesDir}/`)
|
|
1448
|
+
);
|
|
1432
1449
|
}
|
|
1433
1450
|
|
|
1434
1451
|
function moduleIdForBuildFile(file: string, relativeRoutesDir: string): string {
|
|
@@ -1468,10 +1485,7 @@ async function collectPublicAssetPaths(publicDir: string): Promise<string[]> {
|
|
|
1468
1485
|
return paths.sort();
|
|
1469
1486
|
}
|
|
1470
1487
|
|
|
1471
|
-
async function copyAppFileConventionAssets(
|
|
1472
|
-
appDir: string,
|
|
1473
|
-
outDir: string,
|
|
1474
|
-
): Promise<string[]> {
|
|
1488
|
+
async function copyAppFileConventionAssets(appDir: string, outDir: string): Promise<string[]> {
|
|
1475
1489
|
let entries: Dirent[];
|
|
1476
1490
|
try {
|
|
1477
1491
|
entries = await readdir(appDir, { withFileTypes: true });
|
|
@@ -1496,9 +1510,7 @@ async function copyAppFileConventionAssets(
|
|
|
1496
1510
|
continue;
|
|
1497
1511
|
}
|
|
1498
1512
|
|
|
1499
|
-
const outputPath = convention.path.startsWith("/")
|
|
1500
|
-
? convention.path.slice(1)
|
|
1501
|
-
: convention.path;
|
|
1513
|
+
const outputPath = convention.path.startsWith("/") ? convention.path.slice(1) : convention.path;
|
|
1502
1514
|
await copyFile(join(appDir, entry.name), join(outDir, outputPath));
|
|
1503
1515
|
paths.push(convention.path);
|
|
1504
1516
|
}
|
|
@@ -1748,205 +1760,219 @@ async function buildServerModuleArtifacts(options: {
|
|
|
1748
1760
|
}
|
|
1749
1761
|
}
|
|
1750
1762
|
|
|
1751
|
-
const requestBatchOutputs =
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
const artifactEntries = await mapWithBuildConcurrency(Object.entries(options.files), async ([file, source]) => {
|
|
1763
|
-
const absoluteFile = join(options.projectRoot, file);
|
|
1764
|
-
const route = routeByFile.get(file);
|
|
1765
|
-
const routeAnalysis = options.sourceAnalysis.byRouteFile.get(file);
|
|
1766
|
-
const artifact: BuiltServerModuleArtifact = {};
|
|
1763
|
+
const requestBatchOutputs =
|
|
1764
|
+
requestBatchEntries.length >= 3
|
|
1765
|
+
? await bundleRouteRequestModuleBatchCode({
|
|
1766
|
+
appDir: options.project.routesDir,
|
|
1767
|
+
bundleCache: options.bundleCache,
|
|
1768
|
+
cacheDir: options.cacheDir,
|
|
1769
|
+
entries: requestBatchEntries,
|
|
1770
|
+
importPolicy: requestModuleImportPolicy,
|
|
1771
|
+
vitePlugins: options.vitePlugins,
|
|
1772
|
+
})
|
|
1773
|
+
: new Map<string, string>();
|
|
1767
1774
|
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
await bundleRouteLoaderModuleCode({
|
|
1776
|
-
appDir: options.project.routesDir,
|
|
1777
|
-
bundleCache: options.bundleCache,
|
|
1778
|
-
cacheDir: options.cacheDir,
|
|
1779
|
-
code: stripRouteLoaderOnlyExports(source, absoluteFile),
|
|
1780
|
-
filename: absoluteFile,
|
|
1781
|
-
importPolicy: requestModuleImportPolicy,
|
|
1782
|
-
vitePlugins: options.vitePlugins,
|
|
1783
|
-
});
|
|
1784
|
-
artifact.loader = {
|
|
1785
|
-
code,
|
|
1786
|
-
sourceHash: hashText(source),
|
|
1787
|
-
};
|
|
1788
|
-
}
|
|
1775
|
+
const artifactEntries = await mapWithBuildConcurrency(
|
|
1776
|
+
Object.entries(options.files),
|
|
1777
|
+
async ([file, source]) => {
|
|
1778
|
+
const absoluteFile = join(options.projectRoot, file);
|
|
1779
|
+
const route = routeByFile.get(file);
|
|
1780
|
+
const routeAnalysis = options.sourceAnalysis.byRouteFile.get(file);
|
|
1781
|
+
const artifact: BuiltServerModuleArtifact = {};
|
|
1789
1782
|
|
|
1790
|
-
if (
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1783
|
+
if (
|
|
1784
|
+
requestArtifactFiles.has(file) ||
|
|
1785
|
+
loaderArtifactFiles.has(file) ||
|
|
1786
|
+
metadataArtifactFiles.has(file)
|
|
1787
|
+
) {
|
|
1788
|
+
if (loaderArtifactFiles.has(file)) {
|
|
1789
|
+
const code =
|
|
1790
|
+
requestBatchOutputs.get(routeRequestArtifactBatchKey(file, "loader")) ??
|
|
1791
|
+
(await bundleRouteLoaderModuleCode({
|
|
1792
|
+
appDir: options.project.routesDir,
|
|
1793
|
+
bundleCache: options.bundleCache,
|
|
1794
|
+
cacheDir: options.cacheDir,
|
|
1795
|
+
code: stripRouteLoaderOnlyExports(source, absoluteFile),
|
|
1796
|
+
filename: absoluteFile,
|
|
1797
|
+
importPolicy: requestModuleImportPolicy,
|
|
1798
|
+
vitePlugins: options.vitePlugins,
|
|
1799
|
+
}));
|
|
1800
|
+
artifact.loader = {
|
|
1801
|
+
code,
|
|
1802
|
+
sourceHash: hashText(source),
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1807
1805
|
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
artifact.request = {
|
|
1813
|
-
code: batchedRequestCode ??
|
|
1814
|
-
await buildRequestModuleArtifactCode({
|
|
1806
|
+
if (metadataArtifactFiles.has(file)) {
|
|
1807
|
+
const code =
|
|
1808
|
+
requestBatchOutputs.get(routeRequestArtifactBatchKey(file, "metadata")) ??
|
|
1809
|
+
(await bundleRouteRequestModuleCode({
|
|
1815
1810
|
appDir: options.project.routesDir,
|
|
1816
1811
|
bundleCache: options.bundleCache,
|
|
1817
1812
|
cacheDir: options.cacheDir,
|
|
1813
|
+
code: stripRouteMetadataOnlyExports(source, absoluteFile),
|
|
1818
1814
|
filename: absoluteFile,
|
|
1819
1815
|
importPolicy: requestModuleImportPolicy,
|
|
1820
|
-
|
|
1821
|
-
source,
|
|
1816
|
+
label: "Metadata",
|
|
1822
1817
|
vitePlugins: options.vitePlugins,
|
|
1823
|
-
})
|
|
1824
|
-
|
|
1825
|
-
|
|
1818
|
+
}));
|
|
1819
|
+
artifact.routeMetadata = {
|
|
1820
|
+
code,
|
|
1821
|
+
sourceHash: hashText(source),
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
if (requestArtifactFiles.has(file)) {
|
|
1826
|
+
const batchedRequestCode = requestBatchOutputs.get(
|
|
1827
|
+
routeRequestArtifactBatchKey(file, "request"),
|
|
1828
|
+
);
|
|
1829
|
+
artifact.request = {
|
|
1830
|
+
code:
|
|
1831
|
+
batchedRequestCode ??
|
|
1832
|
+
(await buildRequestModuleArtifactCode({
|
|
1833
|
+
appDir: options.project.routesDir,
|
|
1834
|
+
bundleCache: options.bundleCache,
|
|
1835
|
+
cacheDir: options.cacheDir,
|
|
1836
|
+
filename: absoluteFile,
|
|
1837
|
+
importPolicy: requestModuleImportPolicy,
|
|
1838
|
+
routeKind: route?.kind,
|
|
1839
|
+
source,
|
|
1840
|
+
vitePlugins: options.vitePlugins,
|
|
1841
|
+
})),
|
|
1842
|
+
sourceHash: hashText(source),
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1826
1845
|
}
|
|
1827
|
-
}
|
|
1828
1846
|
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1847
|
+
if (!isServerComponentFile(file)) {
|
|
1848
|
+
return Object.keys(artifact).length > 0 ? ([file, artifact] as const) : undefined;
|
|
1849
|
+
}
|
|
1832
1850
|
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1851
|
+
const closureUsesAwait =
|
|
1852
|
+
routeAnalysis?.streamRoute ??
|
|
1853
|
+
shouldBuildRouteAsStream({
|
|
1854
|
+
filename: file,
|
|
1855
|
+
files: options.files,
|
|
1856
|
+
projectRoot: options.projectRoot,
|
|
1857
|
+
source,
|
|
1858
|
+
});
|
|
1859
|
+
const streamRoute = route !== undefined && closureUsesAwait;
|
|
1860
|
+
const serverOutputs =
|
|
1861
|
+
streamRoute || (route === undefined && closureUsesAwait)
|
|
1862
|
+
? (["stream", "string"] as const)
|
|
1863
|
+
: (["string"] as const);
|
|
1864
|
+
const code =
|
|
1865
|
+
routeAnalysis?.routeCode ??
|
|
1866
|
+
(route === undefined ? source : stripRouteBuildExports(source, absoluteFile));
|
|
1867
|
+
const clientInference =
|
|
1868
|
+
routeAnalysis === undefined
|
|
1869
|
+
? await inferClientRouteModule({
|
|
1870
|
+
...(route === undefined ? {} : { appDir: options.project.routesDir }),
|
|
1871
|
+
cache: options.clientRouteInferenceCache,
|
|
1872
|
+
code:
|
|
1873
|
+
route === undefined
|
|
1874
|
+
? stripRouteClientOnlyExports(source, absoluteFile)
|
|
1875
|
+
: stripRouteClientSource({ code: source, filename: route.file }),
|
|
1876
|
+
filename: join(options.projectRoot, file),
|
|
1877
|
+
...(route === undefined ? {} : { routePath: route.path }),
|
|
1878
|
+
vitePlugins: options.vitePlugins,
|
|
1879
|
+
})
|
|
1880
|
+
: undefined;
|
|
1881
|
+
const clientBoundaryImports =
|
|
1882
|
+
routeAnalysis?.clientBoundaryImports ?? clientInference?.clientBoundaryImports ?? [];
|
|
1883
|
+
const clientBoundaryFallbackImports =
|
|
1884
|
+
routeAnalysis?.clientBoundaryFallbackImports ??
|
|
1885
|
+
clientInference?.clientBoundaryFallbackImports ??
|
|
1886
|
+
[];
|
|
1887
|
+
|
|
1888
|
+
for (const diagnostic of clientInference?.diagnostics ?? []) {
|
|
1889
|
+
console.warn(formatClientRouteInferenceDiagnostic(diagnostic));
|
|
1890
|
+
}
|
|
1863
1891
|
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1892
|
+
if (routeAnalysis !== undefined) {
|
|
1893
|
+
artifact.analysis = builtRouteSourceAnalysisSummary({
|
|
1894
|
+
analysis: routeAnalysis,
|
|
1895
|
+
});
|
|
1896
|
+
}
|
|
1867
1897
|
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1898
|
+
const serverOutputArtifacts = await mapWithBuildConcurrency(
|
|
1899
|
+
serverOutputs,
|
|
1900
|
+
async (serverOutput) => {
|
|
1901
|
+
const output = await transformServerRouteSource({
|
|
1902
|
+
cache: options.serverTransformCache,
|
|
1903
|
+
code,
|
|
1904
|
+
clientBoundaryImports,
|
|
1905
|
+
clientBoundaryFallbackImports,
|
|
1906
|
+
filename: join(options.projectRoot, file),
|
|
1907
|
+
moduleContextCache: options.clientRouteInferenceCache,
|
|
1908
|
+
serverOutput,
|
|
1909
|
+
});
|
|
1910
|
+
const fatalDiagnostics = output.diagnostics.filter(
|
|
1911
|
+
(diagnostic) => diagnostic.code !== "MR_UNSUPPORTED_SERVER_EVENT_HANDLER",
|
|
1912
|
+
);
|
|
1873
1913
|
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1914
|
+
if (fatalDiagnostics.length > 0) {
|
|
1915
|
+
if (
|
|
1916
|
+
serverOutput === "string" &&
|
|
1917
|
+
streamRoute &&
|
|
1918
|
+
route?.kind === "page" &&
|
|
1919
|
+
fatalDiagnostics.every(
|
|
1920
|
+
(diagnostic) => diagnostic.code === "MR_UNSUPPORTED_AWAIT_INNER_COMPONENT",
|
|
1921
|
+
)
|
|
1922
|
+
) {
|
|
1923
|
+
return undefined;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
throw new Error(
|
|
1927
|
+
fatalDiagnostics.map((diagnostic) => formatDiagnostic(file, diagnostic)).join("\n"),
|
|
1928
|
+
);
|
|
1929
|
+
}
|
|
1888
1930
|
|
|
1889
|
-
if (fatalDiagnostics.length > 0) {
|
|
1890
1931
|
if (
|
|
1891
1932
|
serverOutput === "string" &&
|
|
1892
1933
|
streamRoute &&
|
|
1893
1934
|
route?.kind === "page" &&
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
)
|
|
1935
|
+
source.includes("<Await") &&
|
|
1936
|
+
/\bLink\b/.test(source)
|
|
1897
1937
|
) {
|
|
1938
|
+
// Native Link renders pre-rendered children as HTML. Keep direct
|
|
1939
|
+
// Await renderers on the stream artifact so the string artifact
|
|
1940
|
+
// cannot drop deferred Link content before the boundary resolves.
|
|
1898
1941
|
return undefined;
|
|
1899
1942
|
}
|
|
1900
1943
|
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1944
|
+
return [
|
|
1945
|
+
serverOutput,
|
|
1946
|
+
{
|
|
1947
|
+
...(options.prebundleServerComponents
|
|
1948
|
+
? {
|
|
1949
|
+
bundleCode: await buildServerComponentBundleArtifactCode({
|
|
1950
|
+
clientRouteInferenceCache: options.clientRouteInferenceCache,
|
|
1951
|
+
code: output.code,
|
|
1952
|
+
filename: absoluteFile,
|
|
1953
|
+
root: options.projectRoot,
|
|
1954
|
+
serverOutput,
|
|
1955
|
+
vitePlugins: options.vitePlugins,
|
|
1956
|
+
}),
|
|
1957
|
+
}
|
|
1958
|
+
: {}),
|
|
1959
|
+
code: output.code,
|
|
1960
|
+
metadata: output.metadata,
|
|
1961
|
+
sourceHash: hashText(code),
|
|
1962
|
+
},
|
|
1963
|
+
] as const;
|
|
1964
|
+
},
|
|
1965
|
+
);
|
|
1905
1966
|
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
route?.kind === "page" &&
|
|
1910
|
-
source.includes("<Await") &&
|
|
1911
|
-
/\bLink\b/.test(source)
|
|
1912
|
-
) {
|
|
1913
|
-
// Native Link renders pre-rendered children as HTML. Keep direct
|
|
1914
|
-
// Await renderers on the stream artifact so the string artifact
|
|
1915
|
-
// cannot drop deferred Link content before the boundary resolves.
|
|
1916
|
-
return undefined;
|
|
1967
|
+
for (const entry of serverOutputArtifacts) {
|
|
1968
|
+
if (entry !== undefined) {
|
|
1969
|
+
artifact[entry[0]] = entry[1];
|
|
1917
1970
|
}
|
|
1918
|
-
|
|
1919
|
-
return [
|
|
1920
|
-
serverOutput,
|
|
1921
|
-
{
|
|
1922
|
-
...(options.prebundleServerComponents
|
|
1923
|
-
? {
|
|
1924
|
-
bundleCode: await buildServerComponentBundleArtifactCode({
|
|
1925
|
-
clientRouteInferenceCache: options.clientRouteInferenceCache,
|
|
1926
|
-
code: output.code,
|
|
1927
|
-
filename: absoluteFile,
|
|
1928
|
-
root: options.projectRoot,
|
|
1929
|
-
serverOutput,
|
|
1930
|
-
vitePlugins: options.vitePlugins,
|
|
1931
|
-
}),
|
|
1932
|
-
}
|
|
1933
|
-
: {}),
|
|
1934
|
-
code: output.code,
|
|
1935
|
-
metadata: output.metadata,
|
|
1936
|
-
sourceHash: hashText(code),
|
|
1937
|
-
},
|
|
1938
|
-
] as const;
|
|
1939
|
-
},
|
|
1940
|
-
);
|
|
1941
|
-
|
|
1942
|
-
for (const entry of serverOutputArtifacts) {
|
|
1943
|
-
if (entry !== undefined) {
|
|
1944
|
-
artifact[entry[0]] = entry[1];
|
|
1945
1971
|
}
|
|
1946
|
-
}
|
|
1947
1972
|
|
|
1948
|
-
|
|
1949
|
-
|
|
1973
|
+
return [file, artifact] as const;
|
|
1974
|
+
},
|
|
1975
|
+
);
|
|
1950
1976
|
|
|
1951
1977
|
for (const entry of artifactEntries) {
|
|
1952
1978
|
if (entry !== undefined) {
|
|
@@ -1984,6 +2010,7 @@ async function buildServerComponentBundleArtifactCode(options: {
|
|
|
1984
2010
|
async function transformServerRouteSource(options: {
|
|
1985
2011
|
cache: ServerTransformCache;
|
|
1986
2012
|
clientBoundaryImports: readonly string[];
|
|
2013
|
+
clientBoundaryFallbackImports?: readonly string[];
|
|
1987
2014
|
code: string;
|
|
1988
2015
|
filename: string;
|
|
1989
2016
|
moduleContextCache: ClientRouteInferenceCache;
|
|
@@ -1991,6 +2018,7 @@ async function transformServerRouteSource(options: {
|
|
|
1991
2018
|
}): Promise<ServerTransformOutput> {
|
|
1992
2019
|
const cacheKey = stableCacheKey({
|
|
1993
2020
|
clientBoundaryImports: options.clientBoundaryImports,
|
|
2021
|
+
clientBoundaryFallbackImports: options.clientBoundaryFallbackImports ?? [],
|
|
1994
2022
|
codeHash: hashText(options.code),
|
|
1995
2023
|
filename: resolve(options.filename),
|
|
1996
2024
|
serverOutput: options.serverOutput,
|
|
@@ -2012,6 +2040,7 @@ async function transformServerRouteSource(options: {
|
|
|
2012
2040
|
return transformCompilerModuleContext({
|
|
2013
2041
|
code: options.code,
|
|
2014
2042
|
clientBoundaryImports: options.clientBoundaryImports,
|
|
2043
|
+
clientBoundaryFallbackImports: options.clientBoundaryFallbackImports ?? [],
|
|
2015
2044
|
dev: false,
|
|
2016
2045
|
filename: options.filename,
|
|
2017
2046
|
moduleContext,
|
|
@@ -2029,8 +2058,11 @@ function builtRouteSourceAnalysisSummary(options: {
|
|
|
2029
2058
|
}): BuiltRouteSourceAnalysisSummary {
|
|
2030
2059
|
return {
|
|
2031
2060
|
authIncludesClaims: options.analysis.authIncludesClaims,
|
|
2032
|
-
...(options.analysis.cachePolicy === undefined
|
|
2061
|
+
...(options.analysis.cachePolicy === undefined
|
|
2062
|
+
? {}
|
|
2063
|
+
: { cachePolicy: options.analysis.cachePolicy }),
|
|
2033
2064
|
clientBoundaryImports: options.analysis.clientBoundaryImports,
|
|
2065
|
+
clientBoundaryFallbackImports: options.analysis.clientBoundaryFallbackImports,
|
|
2034
2066
|
clientRoute: options.analysis.clientRoute,
|
|
2035
2067
|
hasLoader: options.analysis.hasLoader,
|
|
2036
2068
|
routeCode: options.analysis.routeCode,
|
|
@@ -2089,7 +2121,10 @@ function usesRuntimeCacheControl(code: string): boolean {
|
|
|
2089
2121
|
return /\bcacheControl\s*\(/.test(code);
|
|
2090
2122
|
}
|
|
2091
2123
|
|
|
2092
|
-
function routeRequestArtifactBatchKey(
|
|
2124
|
+
function routeRequestArtifactBatchKey(
|
|
2125
|
+
file: string,
|
|
2126
|
+
kind: "loader" | "metadata" | "request",
|
|
2127
|
+
): string {
|
|
2093
2128
|
return `${kind}:${file}`;
|
|
2094
2129
|
}
|
|
2095
2130
|
|
|
@@ -2129,15 +2164,15 @@ async function buildRequestModuleArtifactCode(options: {
|
|
|
2129
2164
|
});
|
|
2130
2165
|
}
|
|
2131
2166
|
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2167
|
+
return await bundleRouteLoaderModuleCode({
|
|
2168
|
+
appDir: options.appDir,
|
|
2169
|
+
bundleCache: options.bundleCache,
|
|
2170
|
+
cacheDir: options.cacheDir,
|
|
2171
|
+
code: stripRouteRequestOnlyExports(options.source, options.filename),
|
|
2172
|
+
filename: options.filename,
|
|
2173
|
+
importPolicy: options.importPolicy,
|
|
2174
|
+
vitePlugins: options.vitePlugins,
|
|
2175
|
+
});
|
|
2141
2176
|
}
|
|
2142
2177
|
|
|
2143
2178
|
async function bundleRouteLoaderModuleCode(options: {
|
|
@@ -2214,24 +2249,29 @@ async function bundleRouteRequestModuleBatchCode(options: {
|
|
|
2214
2249
|
label: "Request artifact",
|
|
2215
2250
|
}),
|
|
2216
2251
|
],
|
|
2217
|
-
root:
|
|
2252
|
+
root:
|
|
2253
|
+
options.importPolicy?.projectRoot ?? dirname(options.entries[0]?.filename ?? options.appDir),
|
|
2218
2254
|
vitePlugins: options.vitePlugins,
|
|
2219
2255
|
});
|
|
2220
2256
|
|
|
2221
2257
|
if (output.chunks.some((chunk) => !chunk.isEntry)) {
|
|
2222
|
-
const fallbackEntries = await mapWithBuildConcurrency(
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2258
|
+
const fallbackEntries = await mapWithBuildConcurrency(
|
|
2259
|
+
options.entries,
|
|
2260
|
+
async (entry) =>
|
|
2261
|
+
[
|
|
2262
|
+
entry.key,
|
|
2263
|
+
await bundleRouteRequestModuleCode({
|
|
2264
|
+
appDir: options.appDir,
|
|
2265
|
+
bundleCache: options.bundleCache,
|
|
2266
|
+
cacheDir: options.cacheDir,
|
|
2267
|
+
code: entry.code,
|
|
2268
|
+
filename: entry.filename,
|
|
2269
|
+
importPolicy: options.importPolicy,
|
|
2270
|
+
label: entry.label,
|
|
2271
|
+
vitePlugins: options.vitePlugins,
|
|
2272
|
+
}),
|
|
2273
|
+
] as const,
|
|
2274
|
+
);
|
|
2235
2275
|
return new Map(fallbackEntries);
|
|
2236
2276
|
}
|
|
2237
2277
|
|
|
@@ -2346,9 +2386,11 @@ function isMiddlewareFile(appDir: string, file: string): boolean {
|
|
|
2346
2386
|
}
|
|
2347
2387
|
|
|
2348
2388
|
function hasMetadataExport(code: string): boolean {
|
|
2349
|
-
return
|
|
2389
|
+
return (
|
|
2390
|
+
/\bexport\s+const\s+metadata\s*=/.test(code) ||
|
|
2350
2391
|
/\bexport\s+(?:async\s+)?function\s+generateMetadata\b/.test(code) ||
|
|
2351
|
-
/\bexport\s*\{[^}]*\bgenerateMetadata\b[^}]*\}/.test(code)
|
|
2392
|
+
/\bexport\s*\{[^}]*\bgenerateMetadata\b[^}]*\}/.test(code)
|
|
2393
|
+
);
|
|
2352
2394
|
}
|
|
2353
2395
|
|
|
2354
2396
|
async function readDeclaredProjectPackages(projectRoot: string): Promise<string[]> {
|
|
@@ -2432,11 +2474,13 @@ async function writeCloudflareRouteModules(options: {
|
|
|
2432
2474
|
|
|
2433
2475
|
return analysis === undefined
|
|
2434
2476
|
? []
|
|
2435
|
-
: [
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2477
|
+
: [
|
|
2478
|
+
{
|
|
2479
|
+
route,
|
|
2480
|
+
routeFile,
|
|
2481
|
+
routeId: routeIdForPath(route.path),
|
|
2482
|
+
},
|
|
2483
|
+
];
|
|
2440
2484
|
}),
|
|
2441
2485
|
);
|
|
2442
2486
|
|
|
@@ -2455,8 +2499,10 @@ async function writeCloudflareRouteModules(options: {
|
|
|
2455
2499
|
cacheDir: options.cacheDir,
|
|
2456
2500
|
define: options.define,
|
|
2457
2501
|
routes: requiredRoutes
|
|
2458
|
-
.filter(
|
|
2459
|
-
route
|
|
2502
|
+
.filter(
|
|
2503
|
+
({ route, routeFile }) =>
|
|
2504
|
+
route.kind === "page" &&
|
|
2505
|
+
options.sourceAnalysis.byRouteFile.get(routeFile)?.hasLoader === true,
|
|
2460
2506
|
)
|
|
2461
2507
|
.map(({ route, routeId }) => ({ filename: route.file, routeId })),
|
|
2462
2508
|
root: options.projectRoot,
|
|
@@ -2504,114 +2550,120 @@ async function writeCloudflareRouteModules(options: {
|
|
|
2504
2550
|
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, stringShellComponentModules),
|
|
2505
2551
|
]);
|
|
2506
2552
|
|
|
2507
|
-
const registryEntries = await mapWithBuildConcurrency(
|
|
2508
|
-
|
|
2509
|
-
|
|
2553
|
+
const registryEntries = await mapWithBuildConcurrency(
|
|
2554
|
+
requiredRoutes,
|
|
2555
|
+
async ({ route, routeFile, routeId }) => {
|
|
2556
|
+
const routeModuleFile = `routes/${routeId}.mjs`;
|
|
2557
|
+
let routeModuleExports: string[];
|
|
2510
2558
|
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2559
|
+
if (route.kind === "server" || route.kind === "metadata") {
|
|
2560
|
+
try {
|
|
2561
|
+
const serverRouteModule = serverRouteModules.entries.get(routeId);
|
|
2514
2562
|
|
|
2515
|
-
|
|
2516
|
-
|
|
2563
|
+
if (serverRouteModule === undefined) {
|
|
2564
|
+
throw new Error(`Missing bundled Cloudflare ${route.kind} route module.`);
|
|
2565
|
+
}
|
|
2566
|
+
|
|
2567
|
+
const serverRouteFile = serverRouteModule.fileName;
|
|
2568
|
+
const serverRouteImport = `./${serverRouteFile.split("/").pop() ?? serverRouteFile}`;
|
|
2569
|
+
routeModuleExports = [
|
|
2570
|
+
`export * from ${JSON.stringify(serverRouteImport)};`,
|
|
2571
|
+
...(route.kind === "metadata"
|
|
2572
|
+
? [`export { default } from ${JSON.stringify(serverRouteImport)};`]
|
|
2573
|
+
: []),
|
|
2574
|
+
];
|
|
2575
|
+
} catch (error) {
|
|
2576
|
+
throw new Error(
|
|
2577
|
+
`Failed to build Cloudflare ${route.kind} route module for ${routeFile}: ${errorMessage(error)}`,
|
|
2578
|
+
);
|
|
2517
2579
|
}
|
|
2518
2580
|
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
`export * from ${JSON.stringify(serverRouteImport)};`,
|
|
2523
|
-
...(route.kind === "metadata"
|
|
2524
|
-
? [`export { default } from ${JSON.stringify(serverRouteImport)};`]
|
|
2525
|
-
: []),
|
|
2526
|
-
];
|
|
2527
|
-
} catch (error) {
|
|
2528
|
-
throw new Error(
|
|
2529
|
-
`Failed to build Cloudflare ${route.kind} route module for ${routeFile}: ${errorMessage(error)}`,
|
|
2581
|
+
await writeFile(
|
|
2582
|
+
join(options.cloudflareDir, routeModuleFile),
|
|
2583
|
+
`${routeModuleExports.join("\n")}\n`,
|
|
2530
2584
|
);
|
|
2585
|
+
return `${JSON.stringify(routeFile)}: () => import(${JSON.stringify(`./${routeModuleFile}`)})`;
|
|
2531
2586
|
}
|
|
2532
2587
|
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
options.serverModules[routeFile]?.analysis?.streamRoute === true ||
|
|
2539
|
-
options.sourceAnalysis.byRouteFile.get(routeFile)?.streamRoute === true
|
|
2540
|
-
? "stream"
|
|
2541
|
-
: "string";
|
|
2588
|
+
const serverOutput =
|
|
2589
|
+
options.serverModules[routeFile]?.analysis?.streamRoute === true ||
|
|
2590
|
+
options.sourceAnalysis.byRouteFile.get(routeFile)?.streamRoute === true
|
|
2591
|
+
? "stream"
|
|
2592
|
+
: "string";
|
|
2542
2593
|
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
stringShellComponentRouteIds.has(routeId)
|
|
2594
|
+
try {
|
|
2595
|
+
const batchedComponent = stringShellComponentRouteIds.has(routeId)
|
|
2546
2596
|
? stringShellComponentModules.entries.get(routeId)
|
|
2547
2597
|
: directComponentRouteIds.has(routeId)
|
|
2548
2598
|
? directComponentModules.entries.get(routeId)
|
|
2549
2599
|
: undefined;
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2600
|
+
let componentFile = batchedComponent?.fileName;
|
|
2601
|
+
|
|
2602
|
+
if (batchedComponent === undefined) {
|
|
2603
|
+
const componentOutput =
|
|
2604
|
+
serverOutput === "stream"
|
|
2605
|
+
? await buildCloudflareStreamRouteComponentModule({
|
|
2606
|
+
cacheDir: options.cacheDir,
|
|
2607
|
+
define: options.define,
|
|
2608
|
+
filename: route.file,
|
|
2609
|
+
projectRoot: options.projectRoot,
|
|
2610
|
+
routesDir: options.routesDir,
|
|
2611
|
+
serverModules: options.serverModules,
|
|
2612
|
+
sourceAnalysis: options.sourceAnalysis,
|
|
2613
|
+
vitePlugins: options.vitePlugins,
|
|
2614
|
+
})
|
|
2615
|
+
: await buildCloudflareStringRouteComponentModule({
|
|
2616
|
+
cacheDir: options.cacheDir,
|
|
2617
|
+
define: options.define,
|
|
2618
|
+
filename: route.file,
|
|
2619
|
+
projectRoot: options.projectRoot,
|
|
2620
|
+
routesDir: options.routesDir,
|
|
2621
|
+
serverModules: options.serverModules,
|
|
2622
|
+
sourceAnalysis: options.sourceAnalysis,
|
|
2623
|
+
vitePlugins: options.vitePlugins,
|
|
2624
|
+
});
|
|
2625
|
+
|
|
2626
|
+
componentFile = `routes/${routeId}.${hashText(componentOutput).slice(0, 8)}.component.mjs`;
|
|
2627
|
+
await writeFile(join(options.cloudflareDir, componentFile), componentOutput);
|
|
2628
|
+
}
|
|
2575
2629
|
|
|
2576
|
-
componentFile
|
|
2577
|
-
|
|
2578
|
-
|
|
2630
|
+
if (componentFile === undefined) {
|
|
2631
|
+
throw new Error("Missing bundled Cloudflare component module.");
|
|
2632
|
+
}
|
|
2579
2633
|
|
|
2580
|
-
|
|
2581
|
-
|
|
2634
|
+
const componentImport = `./${componentFile.split("/").pop() ?? componentFile}`;
|
|
2635
|
+
routeModuleExports = [cloudflarePageRouteFacadeModuleSource(componentImport)];
|
|
2636
|
+
} catch (error) {
|
|
2637
|
+
throw new Error(
|
|
2638
|
+
`Failed to build Cloudflare route module for ${routeFile}: ${errorMessage(error)}`,
|
|
2639
|
+
);
|
|
2582
2640
|
}
|
|
2583
2641
|
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
];
|
|
2588
|
-
} catch (error) {
|
|
2589
|
-
throw new Error(
|
|
2590
|
-
`Failed to build Cloudflare route module for ${routeFile}: ${errorMessage(error)}`,
|
|
2591
|
-
);
|
|
2592
|
-
}
|
|
2642
|
+
if (options.sourceAnalysis.byRouteFile.get(routeFile)?.hasLoader === true) {
|
|
2643
|
+
try {
|
|
2644
|
+
const loaderModule = loaderRouteModules.entries.get(routeId);
|
|
2593
2645
|
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2646
|
+
if (loaderModule === undefined) {
|
|
2647
|
+
throw new Error("Missing bundled Cloudflare loader module.");
|
|
2648
|
+
}
|
|
2597
2649
|
|
|
2598
|
-
|
|
2599
|
-
|
|
2650
|
+
const loaderFile = loaderModule.fileName;
|
|
2651
|
+
const loaderImport = `./${loaderFile.split("/").pop() ?? loaderFile}`;
|
|
2652
|
+
routeModuleExports.push(`export { loader } from ${JSON.stringify(loaderImport)};`);
|
|
2653
|
+
} catch (error) {
|
|
2654
|
+
throw new Error(
|
|
2655
|
+
`Failed to build Cloudflare loader module for ${routeFile}: ${errorMessage(error)}`,
|
|
2656
|
+
);
|
|
2600
2657
|
}
|
|
2601
|
-
|
|
2602
|
-
const loaderFile = loaderModule.fileName;
|
|
2603
|
-
const loaderImport = `./${loaderFile.split("/").pop() ?? loaderFile}`;
|
|
2604
|
-
routeModuleExports.push(`export { loader } from ${JSON.stringify(loaderImport)};`);
|
|
2605
|
-
} catch (error) {
|
|
2606
|
-
throw new Error(
|
|
2607
|
-
`Failed to build Cloudflare loader module for ${routeFile}: ${errorMessage(error)}`,
|
|
2608
|
-
);
|
|
2609
2658
|
}
|
|
2610
|
-
}
|
|
2611
2659
|
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2660
|
+
await writeFile(
|
|
2661
|
+
join(options.cloudflareDir, routeModuleFile),
|
|
2662
|
+
`${routeModuleExports.join("\n")}\n`,
|
|
2663
|
+
);
|
|
2664
|
+
return `${JSON.stringify(routeFile)}: () => import(${JSON.stringify(`./${routeModuleFile}`)})`;
|
|
2665
|
+
},
|
|
2666
|
+
);
|
|
2615
2667
|
|
|
2616
2668
|
const registrySource = [
|
|
2617
2669
|
`export const routeModules = {`,
|
|
@@ -2893,7 +2945,9 @@ async function buildCloudflareStringRouteComponentModuleBatch(options: {
|
|
|
2893
2945
|
contents: pageMetadataModule,
|
|
2894
2946
|
resolveDir: dirname(route.filename),
|
|
2895
2947
|
});
|
|
2896
|
-
metadataImports.push(
|
|
2948
|
+
metadataImports.push(
|
|
2949
|
+
`import * as pageMetadataModule from ${JSON.stringify(pageMetadataId)};`,
|
|
2950
|
+
);
|
|
2897
2951
|
}
|
|
2898
2952
|
|
|
2899
2953
|
const shellMetadataImports = await Promise.all(
|
|
@@ -3084,7 +3138,11 @@ async function buildCloudflareServerComponentModule(options: {
|
|
|
3084
3138
|
cacheDir: options.cacheDir,
|
|
3085
3139
|
define: options.define,
|
|
3086
3140
|
filename: options.filename,
|
|
3087
|
-
hasMetadata: buildSourceAnalysisForFile(
|
|
3141
|
+
hasMetadata: buildSourceAnalysisForFile(
|
|
3142
|
+
options.sourceAnalysis,
|
|
3143
|
+
options.projectRoot,
|
|
3144
|
+
options.filename,
|
|
3145
|
+
)?.hasMetadata,
|
|
3088
3146
|
root: options.projectRoot,
|
|
3089
3147
|
vitePlugins: options.vitePlugins,
|
|
3090
3148
|
});
|
|
@@ -3098,9 +3156,8 @@ async function buildCloudflareServerComponentModule(options: {
|
|
|
3098
3156
|
filename: `${options.filename}.mreact-cloudflare-component.js`,
|
|
3099
3157
|
cacheDir: options.cacheDir,
|
|
3100
3158
|
define: options.define,
|
|
3101
|
-
modules:
|
|
3102
|
-
? new Map()
|
|
3103
|
-
: new Map([["mreact:metadata", metadataModule]]),
|
|
3159
|
+
modules:
|
|
3160
|
+
metadataModule === undefined ? new Map() : new Map([["mreact:metadata", metadataModule]]),
|
|
3104
3161
|
plugins: [
|
|
3105
3162
|
cloudflareServerSourceTransformPlugin({
|
|
3106
3163
|
projectRoot: options.projectRoot,
|
|
@@ -3180,7 +3237,9 @@ async function buildCloudflareStringRouteComponentModule(options: {
|
|
|
3180
3237
|
}),
|
|
3181
3238
|
),
|
|
3182
3239
|
);
|
|
3183
|
-
const shellImports = shellFiles.map(
|
|
3240
|
+
const shellImports = shellFiles.map(
|
|
3241
|
+
(_, index) => `import * as shell${index} from "mreact:shell-${index}";`,
|
|
3242
|
+
);
|
|
3184
3243
|
const shellDefinitions = shellFiles.map(
|
|
3185
3244
|
(shell, index) =>
|
|
3186
3245
|
`{ component: selectComponent(shell${index}, ${JSON.stringify(shell.file)}), id: ${JSON.stringify(shell.id)}, kind: ${JSON.stringify(shell.kind)}, module: shell${index} }`,
|
|
@@ -3287,7 +3346,9 @@ async function buildCloudflareStreamRouteComponentModule(options: {
|
|
|
3287
3346
|
}),
|
|
3288
3347
|
),
|
|
3289
3348
|
);
|
|
3290
|
-
const shellImports = shellFiles.map(
|
|
3349
|
+
const shellImports = shellFiles.map(
|
|
3350
|
+
(_, index) => `import * as shell${index} from "mreact:shell-${index}";`,
|
|
3351
|
+
);
|
|
3291
3352
|
const shellDefinitions = shellFiles.map(
|
|
3292
3353
|
(shell, index) =>
|
|
3293
3354
|
`{ component: selectComponent(shell${index}, ${JSON.stringify(shell.file)}), id: ${JSON.stringify(shell.id)}, kind: ${JSON.stringify(shell.kind)}, module: shell${index} }`,
|
|
@@ -3687,7 +3748,11 @@ async function buildCloudflareComponentExportModule(options: {
|
|
|
3687
3748
|
cacheDir: options.cacheDir,
|
|
3688
3749
|
define: options.define,
|
|
3689
3750
|
filename: options.filename,
|
|
3690
|
-
hasMetadata: buildSourceAnalysisForFile(
|
|
3751
|
+
hasMetadata: buildSourceAnalysisForFile(
|
|
3752
|
+
options.sourceAnalysis,
|
|
3753
|
+
options.projectRoot,
|
|
3754
|
+
options.filename,
|
|
3755
|
+
)?.hasMetadata,
|
|
3691
3756
|
root: options.projectRoot,
|
|
3692
3757
|
vitePlugins: options.vitePlugins,
|
|
3693
3758
|
});
|
|
@@ -3706,9 +3771,8 @@ export const slots = routeModule.slots;`;
|
|
|
3706
3771
|
cacheDir: options.cacheDir,
|
|
3707
3772
|
define: options.define,
|
|
3708
3773
|
filename: `${options.filename}.mreact-cloudflare-${options.serverOutput}-component.js`,
|
|
3709
|
-
modules:
|
|
3710
|
-
? new Map()
|
|
3711
|
-
: new Map([["mreact:metadata", metadataModule]]),
|
|
3774
|
+
modules:
|
|
3775
|
+
metadataModule === undefined ? new Map() : new Map([["mreact:metadata", metadataModule]]),
|
|
3712
3776
|
plugins: [
|
|
3713
3777
|
cloudflareServerSourceTransformPlugin({
|
|
3714
3778
|
projectRoot: options.projectRoot,
|
|
@@ -4093,6 +4157,7 @@ async function transformCloudflareServerSource(options: {
|
|
|
4093
4157
|
const output = transformCompilerModuleContext({
|
|
4094
4158
|
code: options.source,
|
|
4095
4159
|
clientBoundaryImports: clientInference.clientBoundaryImports,
|
|
4160
|
+
clientBoundaryFallbackImports: clientInference.clientBoundaryFallbackImports,
|
|
4096
4161
|
dev: false,
|
|
4097
4162
|
filename: options.filename,
|
|
4098
4163
|
moduleContext,
|
|
@@ -4106,7 +4171,9 @@ async function transformCloudflareServerSource(options: {
|
|
|
4106
4171
|
|
|
4107
4172
|
if (fatalDiagnostics.length > 0) {
|
|
4108
4173
|
throw new Error(
|
|
4109
|
-
fatalDiagnostics
|
|
4174
|
+
fatalDiagnostics
|
|
4175
|
+
.map((diagnostic) => formatDiagnostic(options.filename, diagnostic))
|
|
4176
|
+
.join("\n"),
|
|
4110
4177
|
);
|
|
4111
4178
|
}
|
|
4112
4179
|
|
|
@@ -4147,9 +4214,18 @@ function cloudflareWorkspaceRuntimePlugin(): RouterCompatPlugin {
|
|
|
4147
4214
|
"@reckona/mreact-compat/event-priority",
|
|
4148
4215
|
packageFile("react-compat", "@reckona/mreact-compat", "event-priority"),
|
|
4149
4216
|
],
|
|
4150
|
-
[
|
|
4151
|
-
|
|
4152
|
-
|
|
4217
|
+
[
|
|
4218
|
+
"@reckona/mreact-compat/flight",
|
|
4219
|
+
packageFile("react-compat", "@reckona/mreact-compat", "flight"),
|
|
4220
|
+
],
|
|
4221
|
+
[
|
|
4222
|
+
"@reckona/mreact-compat/hooks",
|
|
4223
|
+
packageFile("react-compat", "@reckona/mreact-compat", "hooks-entry"),
|
|
4224
|
+
],
|
|
4225
|
+
[
|
|
4226
|
+
"@reckona/mreact-compat/internal",
|
|
4227
|
+
packageFile("react-compat", "@reckona/mreact-compat", "internal"),
|
|
4228
|
+
],
|
|
4153
4229
|
[
|
|
4154
4230
|
"@reckona/mreact-compat/jsx-dev-runtime",
|
|
4155
4231
|
packageFile("react-compat", "@reckona/mreact-compat", "jsx-dev-runtime"),
|
|
@@ -4158,9 +4234,15 @@ function cloudflareWorkspaceRuntimePlugin(): RouterCompatPlugin {
|
|
|
4158
4234
|
"@reckona/mreact-compat/jsx-runtime",
|
|
4159
4235
|
packageFile("react-compat", "@reckona/mreact-compat", "jsx-runtime"),
|
|
4160
4236
|
],
|
|
4161
|
-
[
|
|
4237
|
+
[
|
|
4238
|
+
"@reckona/mreact-compat/scheduler",
|
|
4239
|
+
packageFile("react-compat", "@reckona/mreact-compat", "scheduler"),
|
|
4240
|
+
],
|
|
4162
4241
|
["@reckona/mreact-query", packageFile("query", "@reckona/mreact-query", "index")],
|
|
4163
|
-
[
|
|
4242
|
+
[
|
|
4243
|
+
"@reckona/mreact-reactive-core",
|
|
4244
|
+
packageFile("reactive-core", "@reckona/mreact-reactive-core", "index"),
|
|
4245
|
+
],
|
|
4164
4246
|
[
|
|
4165
4247
|
"@reckona/mreact-router/adapters/cloudflare",
|
|
4166
4248
|
packageFile("router", "@reckona/mreact-router", "adapters/cloudflare"),
|
|
@@ -4179,10 +4261,13 @@ function cloudflareWorkspaceRuntimePlugin(): RouterCompatPlugin {
|
|
|
4179
4261
|
return {
|
|
4180
4262
|
name: "mreact-cloudflare-workspace-runtime",
|
|
4181
4263
|
setup(buildApi) {
|
|
4182
|
-
buildApi.onResolve(
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4264
|
+
buildApi.onResolve(
|
|
4265
|
+
{ filter: /^@reckona\/mreact-router\/(?:internal\/)?native-escape$/ },
|
|
4266
|
+
() => ({
|
|
4267
|
+
namespace: "mreact-cloudflare-native-escape",
|
|
4268
|
+
path: "native-escape",
|
|
4269
|
+
}),
|
|
4270
|
+
);
|
|
4186
4271
|
buildApi.onResolve({ filter: /^@reckona\/mreact-router$/ }, () => ({
|
|
4187
4272
|
namespace: "mreact-cloudflare-router-index",
|
|
4188
4273
|
path: "index",
|
|
@@ -4192,8 +4277,10 @@ function cloudflareWorkspaceRuntimePlugin(): RouterCompatPlugin {
|
|
|
4192
4277
|
|
|
4193
4278
|
return path === undefined ? undefined : { path };
|
|
4194
4279
|
});
|
|
4195
|
-
buildApi.onLoad(
|
|
4196
|
-
|
|
4280
|
+
buildApi.onLoad(
|
|
4281
|
+
{ filter: /^native-escape$/, namespace: "mreact-cloudflare-native-escape" },
|
|
4282
|
+
() => ({
|
|
4283
|
+
contents: `function escapeHtml(value) {
|
|
4197
4284
|
return String(value ?? "").replace(/[&<>"']/g, (char) =>
|
|
4198
4285
|
char === "&" ? "&" : char === "<" ? "<" : char === ">" ? ">" : char === '"' ? """ : "'"
|
|
4199
4286
|
);
|
|
@@ -4201,8 +4288,9 @@ function cloudflareWorkspaceRuntimePlugin(): RouterCompatPlugin {
|
|
|
4201
4288
|
export function escapeHtmlBatch(values) {
|
|
4202
4289
|
return values.map(escapeHtml);
|
|
4203
4290
|
}`,
|
|
4204
|
-
|
|
4205
|
-
|
|
4291
|
+
loader: "js",
|
|
4292
|
+
}),
|
|
4293
|
+
);
|
|
4206
4294
|
buildApi.onLoad({ filter: /^index$/, namespace: "mreact-cloudflare-router-index" }, () => ({
|
|
4207
4295
|
contents: `export { cacheControl, revalidatePath } from ${JSON.stringify(routerCachePath)};
|
|
4208
4296
|
export { deleteCookie, parseCookieHeader, serializeCookie, setCookie } from ${JSON.stringify(routerCookiesPath)};
|
|
@@ -4216,12 +4304,15 @@ export { getServerRuntimeState } from ${JSON.stringify(routerRuntimeStatePath)};
|
|
|
4216
4304
|
loader: "js",
|
|
4217
4305
|
resolveDir: dirname(routerNavigationPath),
|
|
4218
4306
|
}));
|
|
4219
|
-
buildApi.onLoad(
|
|
4220
|
-
|
|
4307
|
+
buildApi.onLoad(
|
|
4308
|
+
{ filter: /(?:^|[/\\])packages[/\\]server[/\\](?:src|dist)[/\\]native-flight\.[jt]s$/ },
|
|
4309
|
+
() => ({
|
|
4310
|
+
contents: `export function getNativeFlight() {
|
|
4221
4311
|
return undefined;
|
|
4222
4312
|
}`,
|
|
4223
|
-
|
|
4224
|
-
|
|
4313
|
+
loader: "js",
|
|
4314
|
+
}),
|
|
4315
|
+
);
|
|
4225
4316
|
},
|
|
4226
4317
|
};
|
|
4227
4318
|
}
|
|
@@ -4423,18 +4514,23 @@ async function writeClientRouteBundles(options: {
|
|
|
4423
4514
|
});
|
|
4424
4515
|
} catch (error) {
|
|
4425
4516
|
const routeContexts = clientEntries
|
|
4426
|
-
.map(
|
|
4517
|
+
.map(
|
|
4518
|
+
(entry) => `Failed to build client bundle for ${entry.route.path} (${entry.route.file}).`,
|
|
4519
|
+
)
|
|
4427
4520
|
.join("\n");
|
|
4428
4521
|
|
|
4429
|
-
throw new Error(
|
|
4430
|
-
|
|
4431
|
-
|
|
4522
|
+
throw new Error(
|
|
4523
|
+
`${routeContexts}\nFailed to build client route bundles.\n${errorMessage(error)}`,
|
|
4524
|
+
{
|
|
4525
|
+
cause: error,
|
|
4526
|
+
},
|
|
4527
|
+
);
|
|
4432
4528
|
}
|
|
4433
4529
|
|
|
4434
4530
|
const routeOutputs = new Map(output.routes.map((route) => [route.routePath, route]));
|
|
4435
4531
|
const mapAssets = new Map(
|
|
4436
4532
|
output.chunks.flatMap((chunk) =>
|
|
4437
|
-
chunk.map === undefined ? [] : [[`${chunk.fileName}.map`, chunk.map] as const]
|
|
4533
|
+
chunk.map === undefined ? [] : [[`${chunk.fileName}.map`, chunk.map] as const],
|
|
4438
4534
|
),
|
|
4439
4535
|
);
|
|
4440
4536
|
|
|
@@ -4459,9 +4555,7 @@ async function writeClientRouteBundles(options: {
|
|
|
4459
4555
|
|
|
4460
4556
|
for (const asset of output.assets ?? []) {
|
|
4461
4557
|
const source =
|
|
4462
|
-
typeof asset.source === "string"
|
|
4463
|
-
? asset.source
|
|
4464
|
-
: Buffer.from(asset.source).toString("utf8");
|
|
4558
|
+
typeof asset.source === "string" ? asset.source : Buffer.from(asset.source).toString("utf8");
|
|
4465
4559
|
|
|
4466
4560
|
await mkdir(dirname(join(options.clientDir, asset.fileName)), { recursive: true });
|
|
4467
4561
|
await writeFile(join(options.clientDir, asset.fileName), source);
|
|
@@ -4538,12 +4632,16 @@ async function writeRouteCssAssetBatches(options: {
|
|
|
4538
4632
|
appDir: options.appDir,
|
|
4539
4633
|
pageFile: route.file,
|
|
4540
4634
|
projectRoot: options.projectRoot,
|
|
4541
|
-
readSource: (file) =>
|
|
4635
|
+
readSource: (file) =>
|
|
4636
|
+
buildSourceAnalysisForFile(options.sourceAnalysis, options.projectRoot, file)?.source,
|
|
4542
4637
|
});
|
|
4543
4638
|
|
|
4544
4639
|
return { cssFiles, route };
|
|
4545
4640
|
});
|
|
4546
|
-
const groups = new Map<
|
|
4641
|
+
const groups = new Map<
|
|
4642
|
+
string,
|
|
4643
|
+
{ cssFiles: string[]; routeIds: string[]; routeFiles: string[] }
|
|
4644
|
+
>();
|
|
4547
4645
|
|
|
4548
4646
|
for (const { cssFiles, route } of cssInputs) {
|
|
4549
4647
|
if (cssFiles.length === 0) {
|
|
@@ -4557,18 +4655,22 @@ async function writeRouteCssAssetBatches(options: {
|
|
|
4557
4655
|
groups.set(key, group);
|
|
4558
4656
|
}
|
|
4559
4657
|
|
|
4560
|
-
const writtenGroups = await mapWithBuildConcurrency(
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4658
|
+
const writtenGroups = await mapWithBuildConcurrency(
|
|
4659
|
+
[...groups.entries()],
|
|
4660
|
+
async ([key, group]) =>
|
|
4661
|
+
[
|
|
4662
|
+
key,
|
|
4663
|
+
await writeRouteCssAssetsForFiles({
|
|
4664
|
+
cacheDir: options.cacheDir,
|
|
4665
|
+
clientDir: options.clientDir,
|
|
4666
|
+
cssFiles: group.cssFiles,
|
|
4667
|
+
pageFile: group.routeFiles[0] ?? options.appDir,
|
|
4668
|
+
projectRoot: options.projectRoot,
|
|
4669
|
+
routeIds: group.routeIds,
|
|
4670
|
+
vitePlugins: options.vitePlugins,
|
|
4671
|
+
}),
|
|
4672
|
+
] as const,
|
|
4673
|
+
);
|
|
4572
4674
|
const cssByGroup = new Map(writtenGroups);
|
|
4573
4675
|
const cssByRoute = new Map<string, string[]>();
|
|
4574
4676
|
|
|
@@ -4612,15 +4714,14 @@ async function writeRouteCssAssetsForFiles(options: {
|
|
|
4612
4714
|
});
|
|
4613
4715
|
const cssAssets = (output.assets ?? []).filter((asset) => asset.fileName.endsWith(".css"));
|
|
4614
4716
|
const written: string[] = [];
|
|
4615
|
-
const routeStem =
|
|
4616
|
-
|
|
4617
|
-
|
|
4717
|
+
const routeStem =
|
|
4718
|
+
options.routeIds.length === 1
|
|
4719
|
+
? (options.routeIds[0] ?? "index")
|
|
4720
|
+
: `shared.${hashText(cssFiles.join("\0")).slice(0, 8)}`;
|
|
4618
4721
|
|
|
4619
4722
|
for (const [index, asset] of cssAssets.entries()) {
|
|
4620
4723
|
const source =
|
|
4621
|
-
typeof asset.source === "string"
|
|
4622
|
-
? asset.source
|
|
4623
|
-
: Buffer.from(asset.source).toString("utf8");
|
|
4724
|
+
typeof asset.source === "string" ? asset.source : Buffer.from(asset.source).toString("utf8");
|
|
4624
4725
|
const hash = createHash("sha256").update(source).digest("hex").slice(0, 8);
|
|
4625
4726
|
const cssFile = `assets/routes/${routeStem}${cssAssets.length === 1 ? "" : `.${index}`}.${hash}.css`;
|
|
4626
4727
|
|
|
@@ -4798,7 +4899,9 @@ function isBarePackageImport(specifier: string): boolean {
|
|
|
4798
4899
|
|
|
4799
4900
|
async function assertAwsLambdaRuntimeDependencies(outDir: string): Promise<void> {
|
|
4800
4901
|
try {
|
|
4801
|
-
const info = await stat(
|
|
4902
|
+
const info = await stat(
|
|
4903
|
+
join(outDir, "node_modules", "@reckona", "mreact-router", "package.json"),
|
|
4904
|
+
);
|
|
4802
4905
|
if (info.isFile()) {
|
|
4803
4906
|
return;
|
|
4804
4907
|
}
|
|
@@ -4891,7 +4994,9 @@ function assertPackageOutputDoesNotReplaceBuildOutput(options: {
|
|
|
4891
4994
|
outDir: string;
|
|
4892
4995
|
}): void {
|
|
4893
4996
|
if (resolve(options.fromDir) === resolve(options.outDir)) {
|
|
4894
|
-
throw new Error(
|
|
4997
|
+
throw new Error(
|
|
4998
|
+
"Package output directory must be different from the mreact build output directory.",
|
|
4999
|
+
);
|
|
4895
5000
|
}
|
|
4896
5001
|
}
|
|
4897
5002
|
|
|
@@ -4955,7 +5060,9 @@ async function collectArtifactFiles(
|
|
|
4955
5060
|
}
|
|
4956
5061
|
}
|
|
4957
5062
|
|
|
4958
|
-
return files.sort(
|
|
5063
|
+
return files.sort(
|
|
5064
|
+
(left, right) => right.bytes - left.bytes || left.path.localeCompare(right.path),
|
|
5065
|
+
);
|
|
4959
5066
|
}
|
|
4960
5067
|
|
|
4961
5068
|
function awsLambdaHandlerSource(outDirRelativeToHandler: string): string {
|
|
@@ -5000,6 +5107,7 @@ async function validateProductionRoutes(options: {
|
|
|
5000
5107
|
cache: options.serverTransformCache,
|
|
5001
5108
|
code: analysis.routeCode,
|
|
5002
5109
|
clientBoundaryImports: analysis.clientBoundaryImports,
|
|
5110
|
+
clientBoundaryFallbackImports: analysis.clientBoundaryFallbackImports,
|
|
5003
5111
|
filename: route.file,
|
|
5004
5112
|
moduleContextCache: options.clientRouteInferenceCache,
|
|
5005
5113
|
serverOutput: analysis.streamRoute ? "stream" : "string",
|
|
@@ -5039,10 +5147,10 @@ async function collectBuildFiles(
|
|
|
5039
5147
|
|
|
5040
5148
|
return [{ file, relativeFile }];
|
|
5041
5149
|
});
|
|
5042
|
-
const fileContents = await mapWithBuildConcurrency(
|
|
5043
|
-
|
|
5044
|
-
await readFile(file, "utf8"),
|
|
5045
|
-
|
|
5150
|
+
const fileContents = await mapWithBuildConcurrency(
|
|
5151
|
+
sourceFiles,
|
|
5152
|
+
async ({ file, relativeFile }) => [relativeFile, await readFile(file, "utf8")] as const,
|
|
5153
|
+
);
|
|
5046
5154
|
|
|
5047
5155
|
for (const [relativeFile, source] of fileContents) {
|
|
5048
5156
|
files[relativeFile] = source;
|