evolit 0.1.0-alpha.12 → 0.1.0-alpha.13
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/package.json +1 -1
- package/src/client-assets.js +105 -30
- package/src/compiler.js +109 -5
- package/src/deployment-runtime.js +106 -27
- package/src/render.js +11 -4
- package/src/server.js +11 -3
package/package.json
CHANGED
package/src/client-assets.js
CHANGED
|
@@ -229,9 +229,12 @@ function createSharedEntrySource(specifier) {
|
|
|
229
229
|
].join("\n");
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
export async function collectSharedVendorSpecifiers(
|
|
232
|
+
export async function collectSharedVendorSpecifiers(
|
|
233
|
+
additionalEntrySpecifiers = [],
|
|
234
|
+
options = {},
|
|
235
|
+
) {
|
|
233
236
|
return [...new Set([
|
|
234
|
-
...SHARED_VENDOR_SPECIFIERS,
|
|
237
|
+
...(options.includeBase === false ? [] : SHARED_VENDOR_SPECIFIERS),
|
|
235
238
|
...additionalEntrySpecifiers.filter((specifier) => isBareSpecifier(specifier)),
|
|
236
239
|
])].sort();
|
|
237
240
|
}
|
|
@@ -426,20 +429,52 @@ export async function buildSharedVendorRuntime(
|
|
|
426
429
|
? options.additionalEntrySpecifiers.filter((specifier) => isBareSpecifier(specifier))
|
|
427
430
|
: [],
|
|
428
431
|
)].sort();
|
|
429
|
-
|
|
432
|
+
if (mode === "development" && !options.vendorGroup) {
|
|
433
|
+
const baseRuntime = await buildSharedVendorRuntime(projectRoot, mode, {
|
|
434
|
+
...options,
|
|
435
|
+
additionalEntrySpecifiers: [],
|
|
436
|
+
vendorGroup: "base",
|
|
437
|
+
includeBase: true,
|
|
438
|
+
});
|
|
439
|
+
const additionalRuntimes = await Promise.all(
|
|
440
|
+
additionalEntrySpecifiers
|
|
441
|
+
.filter((specifier) => !SHARED_VENDOR_SPECIFIERS.includes(specifier))
|
|
442
|
+
.map((specifier) => buildSharedVendorRuntime(projectRoot, mode, {
|
|
443
|
+
...options,
|
|
444
|
+
additionalEntrySpecifiers: [specifier],
|
|
445
|
+
vendorGroup: `vendor-${crypto.createHash("sha1").update(specifier).digest("hex").slice(0, 10)}`,
|
|
446
|
+
includeBase: false,
|
|
447
|
+
})),
|
|
448
|
+
);
|
|
449
|
+
return {
|
|
450
|
+
imports: Object.assign(
|
|
451
|
+
{},
|
|
452
|
+
baseRuntime.imports,
|
|
453
|
+
...additionalRuntimes.map((runtime) => runtime.imports),
|
|
454
|
+
),
|
|
455
|
+
outputRoot: getSharedOutputRoot(projectRoot, mode),
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const vendorGroup = options.vendorGroup ?? null;
|
|
460
|
+
const cacheKey = `${projectRoot}::${mode}::${vendorGroup ?? "all"}::${additionalEntrySpecifiers.join("|")}`;
|
|
430
461
|
if (sharedRuntimeBuildCache.has(cacheKey)) {
|
|
431
462
|
return sharedRuntimeBuildCache.get(cacheKey);
|
|
432
463
|
}
|
|
433
464
|
|
|
434
465
|
const pendingBuild = (async () => {
|
|
435
|
-
const
|
|
466
|
+
const sharedRootBase = getSharedOutputRoot(projectRoot, mode);
|
|
467
|
+
const sharedRoot = vendorGroup ? path.join(sharedRootBase, vendorGroup) : sharedRootBase;
|
|
436
468
|
const entriesRoot = path.join(
|
|
437
469
|
projectRoot,
|
|
438
470
|
INTERNAL_DIRECTORY,
|
|
439
471
|
mode === "development" ? DEV_DIRECTORY : BUILD_DIRECTORY,
|
|
440
472
|
"__shared_entries__",
|
|
473
|
+
...(vendorGroup ? [vendorGroup] : []),
|
|
441
474
|
);
|
|
442
|
-
const specifiers = await collectSharedVendorSpecifiers(additionalEntrySpecifiers
|
|
475
|
+
const specifiers = await collectSharedVendorSpecifiers(additionalEntrySpecifiers, {
|
|
476
|
+
includeBase: options.includeBase !== false,
|
|
477
|
+
});
|
|
443
478
|
const inputEntries = await writeSharedRuntimeEntrySources(entriesRoot, specifiers);
|
|
444
479
|
|
|
445
480
|
await fs.rm(sharedRoot, { recursive: true, force: true });
|
|
@@ -494,7 +529,7 @@ export async function buildSharedVendorRuntime(
|
|
|
494
529
|
continue;
|
|
495
530
|
}
|
|
496
531
|
|
|
497
|
-
imports[specifier] = `/_evolit/shared/${chunk.fileName}`;
|
|
532
|
+
imports[specifier] = `/_evolit/shared/${vendorGroup ? `${vendorGroup}/` : ""}${chunk.fileName}`;
|
|
498
533
|
}
|
|
499
534
|
|
|
500
535
|
return {
|
|
@@ -1134,7 +1169,32 @@ function rewriteStaticAssetPlaceholdersWithMap(source, publicPathByRelativePath)
|
|
|
1134
1169
|
}
|
|
1135
1170
|
|
|
1136
1171
|
function rewriteRelativeCssAssetUrls(source, fileRelativePath, publicPathByRelativePath) {
|
|
1137
|
-
|
|
1172
|
+
const rewrittenImports = source.replaceAll(
|
|
1173
|
+
/@import(\s+)(url\(\s*)?(?:(["'])([^"']+)\3|([^\s;)]+))(\s*\))?/g,
|
|
1174
|
+
(match, whitespace, urlPrefix = "", quote = "", quotedSpecifier, unquotedSpecifier, closing = "") => {
|
|
1175
|
+
const specifier = quotedSpecifier ?? unquotedSpecifier;
|
|
1176
|
+
if (!isRelativeSpecifier(specifier)) {
|
|
1177
|
+
return match;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
const resolvedRelativePath = resolveRelativeClientImportPath(fileRelativePath, specifier);
|
|
1181
|
+
const rewrittenTarget = publicPathByRelativePath.get(resolvedRelativePath);
|
|
1182
|
+
if (!rewrittenTarget) {
|
|
1183
|
+
return match;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
const cleanSpecifier = stripImportSearchAndHash(specifier);
|
|
1187
|
+
const rewrittenSpecifier = `${normalizeRelativeImportPath(
|
|
1188
|
+
path.relative(
|
|
1189
|
+
path.dirname(publicPathByRelativePath.get(fileRelativePath)),
|
|
1190
|
+
rewrittenTarget,
|
|
1191
|
+
),
|
|
1192
|
+
)}${specifier.slice(cleanSpecifier.length)}`;
|
|
1193
|
+
return `@import${whitespace}${urlPrefix}${quote}${rewrittenSpecifier}${quote}${closing}`;
|
|
1194
|
+
},
|
|
1195
|
+
);
|
|
1196
|
+
|
|
1197
|
+
return rewrittenImports.replaceAll(
|
|
1138
1198
|
/url\(\s*(['"]?)([^"'()]+)\1\s*\)/g,
|
|
1139
1199
|
(match, quote = "", rawSpecifier) => {
|
|
1140
1200
|
const specifier = String(rawSpecifier).trim();
|
|
@@ -1460,7 +1520,9 @@ async function bundleClientAssets(projectRoot, options = {}) {
|
|
|
1460
1520
|
publicPathByRelativePath.set(entry.relativePath, hashedRelativePath);
|
|
1461
1521
|
}
|
|
1462
1522
|
|
|
1463
|
-
|
|
1523
|
+
if (mode !== "development") {
|
|
1524
|
+
await fs.rm(staticRoot, { recursive: true, force: true });
|
|
1525
|
+
}
|
|
1464
1526
|
await ensureDirectory(staticRoot);
|
|
1465
1527
|
|
|
1466
1528
|
const nonScriptAssets = [];
|
|
@@ -1670,30 +1732,43 @@ async function bundleClientAssets(projectRoot, options = {}) {
|
|
|
1670
1732
|
}
|
|
1671
1733
|
|
|
1672
1734
|
const mapAssets = [];
|
|
1673
|
-
const
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1735
|
+
for (const asset of scriptAssetRecords) {
|
|
1736
|
+
const mapPath = `${asset.outputPath}.map`;
|
|
1737
|
+
try {
|
|
1738
|
+
const stat = await fs.stat(mapPath);
|
|
1739
|
+
const relativePath = path.relative(staticRoot, mapPath).split(path.sep).join("/");
|
|
1740
|
+
const publicUrl = toStaticPublicUrl(relativePath);
|
|
1741
|
+
byPublicPath[publicUrl] = mapPath;
|
|
1742
|
+
mapAssets.push({
|
|
1743
|
+
clientModule: relativePath,
|
|
1744
|
+
type: "asset",
|
|
1745
|
+
kind: "asset",
|
|
1746
|
+
publicUrl,
|
|
1747
|
+
outputPath: mapPath,
|
|
1748
|
+
hash: null,
|
|
1749
|
+
size: stat.size,
|
|
1750
|
+
imports: [],
|
|
1751
|
+
importUrls: [],
|
|
1752
|
+
styleImports: [],
|
|
1753
|
+
styleUrls: [],
|
|
1754
|
+
assetImports: [],
|
|
1755
|
+
assetUrls: [],
|
|
1756
|
+
});
|
|
1757
|
+
} catch {
|
|
1758
|
+
// Source maps are optional in non-development builds.
|
|
1677
1759
|
}
|
|
1760
|
+
}
|
|
1678
1761
|
|
|
1679
|
-
|
|
1680
|
-
const
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
size: (await fs.stat(filePath)).size,
|
|
1690
|
-
imports: [],
|
|
1691
|
-
importUrls: [],
|
|
1692
|
-
styleImports: [],
|
|
1693
|
-
styleUrls: [],
|
|
1694
|
-
assetImports: [],
|
|
1695
|
-
assetUrls: [],
|
|
1696
|
-
});
|
|
1762
|
+
if (mode === "development") {
|
|
1763
|
+
const retainedOutputPaths = new Set(
|
|
1764
|
+
[...scriptAssetRecords, ...nonScriptAssets, ...mapAssets]
|
|
1765
|
+
.map((asset) => asset.outputPath),
|
|
1766
|
+
);
|
|
1767
|
+
for (const filePath of await walkFiles(staticRoot)) {
|
|
1768
|
+
if (!retainedOutputPaths.has(filePath)) {
|
|
1769
|
+
await fs.rm(filePath, { force: true });
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1697
1772
|
}
|
|
1698
1773
|
|
|
1699
1774
|
const assets = [...scriptAssetRecords, ...nonScriptAssets, ...mapAssets]
|
package/src/compiler.js
CHANGED
|
@@ -21,6 +21,10 @@ const RESOLVABLE_IMPORT_EXTENSIONS = [
|
|
|
21
21
|
...MODULE_EXTENSIONS,
|
|
22
22
|
...STATIC_ASSET_EXTENSIONS,
|
|
23
23
|
];
|
|
24
|
+
const developmentGraphCache = new Map();
|
|
25
|
+
const developmentGraphDependencies = new Map();
|
|
26
|
+
const developmentModuleNamespaceCache = new Map();
|
|
27
|
+
const developmentGraphVersions = new Map();
|
|
24
28
|
|
|
25
29
|
function isRelativeSpecifier(specifier) {
|
|
26
30
|
return specifier.startsWith("./") || specifier.startsWith("../");
|
|
@@ -272,7 +276,46 @@ async function rewriteRelativeSpecifiers({
|
|
|
272
276
|
};
|
|
273
277
|
}
|
|
274
278
|
|
|
275
|
-
|
|
279
|
+
function getDevelopmentGraphCacheKey(entryPath, options) {
|
|
280
|
+
return [
|
|
281
|
+
options.projectRoot,
|
|
282
|
+
entryPath,
|
|
283
|
+
options.target ?? "server",
|
|
284
|
+
options.ssr === true ? "ssr" : "client",
|
|
285
|
+
options.sourceMaps === false ? "without-maps" : "with-maps",
|
|
286
|
+
].join("::");
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function invalidateDevelopmentCompilationCache(projectRoot, changedPaths = null) {
|
|
290
|
+
const prefix = `${path.resolve(projectRoot)}::`;
|
|
291
|
+
const normalizedChangedPaths = Array.isArray(changedPaths) && changedPaths.length > 0
|
|
292
|
+
? new Set(changedPaths.map((changedPath) => path.resolve(changedPath)))
|
|
293
|
+
: null;
|
|
294
|
+
let invalidated = false;
|
|
295
|
+
|
|
296
|
+
for (const key of developmentGraphCache.keys()) {
|
|
297
|
+
if (!key.startsWith(prefix)) {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const dependencies = developmentGraphDependencies.get(key);
|
|
302
|
+
const shouldInvalidate =
|
|
303
|
+
normalizedChangedPaths == null ||
|
|
304
|
+
!dependencies ||
|
|
305
|
+
[...dependencies].some((dependency) => normalizedChangedPaths.has(dependency));
|
|
306
|
+
if (shouldInvalidate) {
|
|
307
|
+
developmentGraphCache.delete(key);
|
|
308
|
+
developmentGraphDependencies.delete(key);
|
|
309
|
+
developmentModuleNamespaceCache.delete(key);
|
|
310
|
+
developmentGraphVersions.set(key, (developmentGraphVersions.get(key) ?? 0) + 1);
|
|
311
|
+
invalidated = true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return invalidated;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async function compileModuleGraphUncached(entryPath, options = {}) {
|
|
276
319
|
const {
|
|
277
320
|
projectRoot,
|
|
278
321
|
mode = "development",
|
|
@@ -346,16 +389,77 @@ export async function compileModuleGraph(entryPath, options = {}) {
|
|
|
346
389
|
return {
|
|
347
390
|
entrypoint: await compileModule(entryPath),
|
|
348
391
|
outputRoot,
|
|
392
|
+
sourceFiles: [...visited.keys()],
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export async function compileModuleGraph(entryPath, options = {}) {
|
|
397
|
+
const mode = options.mode ?? "development";
|
|
398
|
+
if (mode !== "development") {
|
|
399
|
+
return compileModuleGraphUncached(entryPath, options);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const normalizedOptions = {
|
|
403
|
+
...options,
|
|
404
|
+
projectRoot: path.resolve(options.projectRoot ?? process.cwd()),
|
|
349
405
|
};
|
|
406
|
+
const cacheKey = getDevelopmentGraphCacheKey(
|
|
407
|
+
path.resolve(entryPath),
|
|
408
|
+
normalizedOptions,
|
|
409
|
+
);
|
|
410
|
+
let pendingCompile = developmentGraphCache.get(cacheKey);
|
|
411
|
+
if (!pendingCompile) {
|
|
412
|
+
pendingCompile = compileModuleGraphUncached(entryPath, normalizedOptions);
|
|
413
|
+
developmentGraphCache.set(cacheKey, pendingCompile);
|
|
414
|
+
pendingCompile.then((result) => {
|
|
415
|
+
if (developmentGraphCache.get(cacheKey) === pendingCompile) {
|
|
416
|
+
developmentGraphDependencies.set(cacheKey, new Set(result.sourceFiles));
|
|
417
|
+
}
|
|
418
|
+
}, () => {});
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
try {
|
|
422
|
+
return await pendingCompile;
|
|
423
|
+
} catch (error) {
|
|
424
|
+
if (developmentGraphCache.get(cacheKey) === pendingCompile) {
|
|
425
|
+
developmentGraphCache.delete(cacheKey);
|
|
426
|
+
developmentGraphDependencies.delete(cacheKey);
|
|
427
|
+
}
|
|
428
|
+
throw error;
|
|
429
|
+
}
|
|
350
430
|
}
|
|
351
431
|
|
|
352
432
|
export async function importCompiledModule(entryPath, options = {}) {
|
|
353
|
-
const
|
|
433
|
+
const mode = options.mode ?? "development";
|
|
434
|
+
const normalizedOptions = mode === "development"
|
|
435
|
+
? { ...options, projectRoot: path.resolve(options.projectRoot ?? process.cwd()) }
|
|
436
|
+
: options;
|
|
437
|
+
const cacheKey = mode === "development"
|
|
438
|
+
? getDevelopmentGraphCacheKey(path.resolve(entryPath), normalizedOptions)
|
|
439
|
+
: null;
|
|
440
|
+
const cachedModule = cacheKey ? developmentModuleNamespaceCache.get(cacheKey) : null;
|
|
441
|
+
if (cachedModule) {
|
|
442
|
+
return cachedModule;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const { entrypoint } = await compileModuleGraph(entryPath, normalizedOptions);
|
|
354
446
|
const moduleUrl = new URL(pathToFileURL(entrypoint).href);
|
|
355
447
|
|
|
356
|
-
if (
|
|
357
|
-
moduleUrl.searchParams.set("t", String(
|
|
448
|
+
if (mode === "development") {
|
|
449
|
+
moduleUrl.searchParams.set("t", String(developmentGraphVersions.get(cacheKey) ?? 0));
|
|
358
450
|
}
|
|
359
451
|
|
|
360
|
-
|
|
452
|
+
const pendingModule = import(moduleUrl.href);
|
|
453
|
+
if (cacheKey) {
|
|
454
|
+
developmentModuleNamespaceCache.set(cacheKey, pendingModule);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
try {
|
|
458
|
+
return await pendingModule;
|
|
459
|
+
} catch (error) {
|
|
460
|
+
if (developmentModuleNamespaceCache.get(cacheKey) === pendingModule) {
|
|
461
|
+
developmentModuleNamespaceCache.delete(cacheKey);
|
|
462
|
+
}
|
|
463
|
+
throw error;
|
|
464
|
+
}
|
|
361
465
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
compileModuleGraph,
|
|
5
|
+
invalidateDevelopmentCompilationCache,
|
|
6
|
+
} from "./compiler.js";
|
|
4
7
|
import {
|
|
5
8
|
collectTransitiveAssetPreloads,
|
|
6
9
|
collectTransitiveStyleUrls,
|
|
@@ -220,8 +223,27 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
|
|
|
220
223
|
"@litsx/ssr/hydration",
|
|
221
224
|
);
|
|
222
225
|
const devBundledEntries = new Set();
|
|
226
|
+
const devPreparedClientModules = new Set();
|
|
227
|
+
const devClientModuleDependencies = new Map();
|
|
223
228
|
let devRollupCache = null;
|
|
229
|
+
let devClientAssetWork = Promise.resolve();
|
|
230
|
+
const developmentMetrics = {
|
|
231
|
+
clientArtifactBuilds: 0,
|
|
232
|
+
clientArtifactCacheHits: 0,
|
|
233
|
+
invalidations: 0,
|
|
234
|
+
selectivelyInvalidatedClientEntries: 0,
|
|
235
|
+
};
|
|
224
236
|
const usesFrameworkRouteResolver = !routeResolver;
|
|
237
|
+
|
|
238
|
+
function enqueueDevClientAssetWork(work) {
|
|
239
|
+
const nextWork = devClientAssetWork.then(work, work);
|
|
240
|
+
devClientAssetWork = nextWork.catch(() => {});
|
|
241
|
+
return nextWork;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function getDevClientModuleKey(clientModule) {
|
|
245
|
+
return path.resolve(projectRoot, clientModule);
|
|
246
|
+
}
|
|
225
247
|
async function createFrameworkRouteResolver() {
|
|
226
248
|
return createRouteResolver(projectRoot, mode, {
|
|
227
249
|
getStaticAssetPublicUrls() {
|
|
@@ -282,21 +304,44 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
|
|
|
282
304
|
return effectiveRouteResolver;
|
|
283
305
|
},
|
|
284
306
|
responseCacheController,
|
|
285
|
-
async invalidateDevelopmentState() {
|
|
307
|
+
async invalidateDevelopmentState(changedPaths = null) {
|
|
286
308
|
if (mode !== "development") {
|
|
287
309
|
return;
|
|
288
310
|
}
|
|
289
311
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
312
|
+
return enqueueDevClientAssetWork(async () => {
|
|
313
|
+
developmentMetrics.invalidations += 1;
|
|
314
|
+
const normalizedChangedPaths = Array.isArray(changedPaths) && changedPaths.length > 0
|
|
315
|
+
? new Set(changedPaths.map((changedPath) => path.resolve(changedPath)))
|
|
316
|
+
: null;
|
|
317
|
+
invalidateDevelopmentCompilationCache(projectRoot, changedPaths);
|
|
318
|
+
const affectedClientModules = normalizedChangedPaths == null
|
|
319
|
+
? new Set(devPreparedClientModules)
|
|
320
|
+
: new Set(
|
|
321
|
+
[...devClientModuleDependencies]
|
|
322
|
+
.filter(([, dependencies]) =>
|
|
323
|
+
[...dependencies].some((dependency) => normalizedChangedPaths.has(dependency))
|
|
324
|
+
)
|
|
325
|
+
.map(([clientModule]) => clientModule),
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
if (affectedClientModules.size > 0 || normalizedChangedPaths == null) {
|
|
329
|
+
developmentMetrics.selectivelyInvalidatedClientEntries += affectedClientModules.size;
|
|
330
|
+
currentAssetManifest = null;
|
|
331
|
+
currentAssetResolver = createAssetResolver(projectRoot, {
|
|
332
|
+
assetManifest: currentAssetManifest,
|
|
333
|
+
});
|
|
334
|
+
devRollupCache = null;
|
|
335
|
+
for (const clientModule of affectedClientModules) {
|
|
336
|
+
devPreparedClientModules.delete(clientModule);
|
|
337
|
+
devClientModuleDependencies.delete(clientModule);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
296
340
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
341
|
+
if (usesFrameworkRouteResolver) {
|
|
342
|
+
effectiveRouteResolver = await createFrameworkRouteResolver();
|
|
343
|
+
}
|
|
344
|
+
});
|
|
300
345
|
},
|
|
301
346
|
async prepareRouteClientArtifacts(routeResult) {
|
|
302
347
|
if (routeResult.type !== "route" && !routeResult.boundaryModule) {
|
|
@@ -308,19 +353,49 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
|
|
|
308
353
|
...(routeResult.boundaryModule ? [routeResult.boundaryModule] : []),
|
|
309
354
|
];
|
|
310
355
|
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
356
|
+
if (mode !== "development") {
|
|
357
|
+
for (const clientModule of new Set(clientModules)) {
|
|
358
|
+
await compileModuleGraph(clientModule, {
|
|
359
|
+
projectRoot,
|
|
360
|
+
mode,
|
|
361
|
+
sourceMaps: false,
|
|
362
|
+
target: "client",
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
return;
|
|
321
366
|
}
|
|
322
367
|
|
|
323
|
-
|
|
368
|
+
return enqueueDevClientAssetWork(async () => {
|
|
369
|
+
let discoveredClientEntry = false;
|
|
370
|
+
for (const clientModule of new Set(clientModules)) {
|
|
371
|
+
const clientModuleKey = getDevClientModuleKey(clientModule);
|
|
372
|
+
if (devPreparedClientModules.has(clientModuleKey)) {
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const clientBuild = await compileModuleGraph(clientModule, {
|
|
377
|
+
projectRoot,
|
|
378
|
+
mode,
|
|
379
|
+
sourceMaps: true,
|
|
380
|
+
target: "client",
|
|
381
|
+
});
|
|
382
|
+
devPreparedClientModules.add(clientModuleKey);
|
|
383
|
+
devClientModuleDependencies.set(
|
|
384
|
+
clientModuleKey,
|
|
385
|
+
new Set(clientBuild.sourceFiles ?? [clientModuleKey]),
|
|
386
|
+
);
|
|
387
|
+
devBundledEntries.add(
|
|
388
|
+
path.relative(clientBuild.outputRoot, clientBuild.entrypoint).split(path.sep).join("/"),
|
|
389
|
+
);
|
|
390
|
+
discoveredClientEntry = true;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (!discoveredClientEntry && currentAssetManifest) {
|
|
394
|
+
developmentMetrics.clientArtifactCacheHits += 1;
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
developmentMetrics.clientArtifactBuilds += 1;
|
|
324
399
|
const bundledClientAssets = await emitBundledClientAssetsWithState(projectRoot, {
|
|
325
400
|
mode: "development",
|
|
326
401
|
entryClientModules: devBundledEntries,
|
|
@@ -340,19 +415,20 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
|
|
|
340
415
|
},
|
|
341
416
|
) ?? currentHydrationModuleUrl;
|
|
342
417
|
devRollupCache = bundledClientAssets.rollupCache;
|
|
343
|
-
}
|
|
418
|
+
});
|
|
344
419
|
},
|
|
345
420
|
async resolveRoutePolicy(request) {
|
|
346
421
|
return effectiveRouteResolver.resolveRoutePolicy(request);
|
|
347
422
|
},
|
|
348
423
|
async renderRoute(request, routePolicyResult = null) {
|
|
349
424
|
const shouldPrepareBeforeResolve = mode === "development" && !currentAssetManifest;
|
|
425
|
+
let resolvedRoutePolicyResult = routePolicyResult;
|
|
350
426
|
if (shouldPrepareBeforeResolve) {
|
|
351
|
-
|
|
427
|
+
resolvedRoutePolicyResult ??= await effectiveRouteResolver.resolveRoutePolicy(request);
|
|
352
428
|
await this.prepareRouteClientArtifacts(resolvedRoutePolicyResult);
|
|
353
429
|
}
|
|
354
430
|
|
|
355
|
-
const routeResult = await effectiveRouteResolver.resolveRequest(request);
|
|
431
|
+
const routeResult = await effectiveRouteResolver.resolveRequest(request, resolvedRoutePolicyResult);
|
|
356
432
|
if (!shouldPrepareBeforeResolve || routeResult.boundaryModule) {
|
|
357
433
|
await this.prepareRouteClientArtifacts(routeResult);
|
|
358
434
|
}
|
|
@@ -365,6 +441,9 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
|
|
|
365
441
|
get assetManifest() {
|
|
366
442
|
return currentAssetManifest;
|
|
367
443
|
},
|
|
444
|
+
get developmentMetrics() {
|
|
445
|
+
return mode === "development" ? { ...developmentMetrics } : null;
|
|
446
|
+
},
|
|
368
447
|
};
|
|
369
448
|
}
|
|
370
449
|
|
|
@@ -403,12 +482,12 @@ export async function createDeploymentRuntime({
|
|
|
403
482
|
assets,
|
|
404
483
|
cache: renderer.responseCacheController,
|
|
405
484
|
renderer,
|
|
406
|
-
async invalidateDevelopmentState() {
|
|
485
|
+
async invalidateDevelopmentState(changedPaths = null) {
|
|
407
486
|
if (mode !== "development") {
|
|
408
487
|
return;
|
|
409
488
|
}
|
|
410
489
|
|
|
411
|
-
await renderer.invalidateDevelopmentState();
|
|
490
|
+
await renderer.invalidateDevelopmentState(changedPaths);
|
|
412
491
|
if (typeof effectiveResponseCacheRuntime.store.clear === "function") {
|
|
413
492
|
await effectiveResponseCacheRuntime.store.clear();
|
|
414
493
|
}
|
package/src/render.js
CHANGED
|
@@ -384,7 +384,10 @@ export async function createRouteResolver(projectRoot, mode = "development", res
|
|
|
384
384
|
return renderNotFound(request);
|
|
385
385
|
}
|
|
386
386
|
|
|
387
|
-
const
|
|
387
|
+
const preloadedModules = options.routePolicyResult?.route === match.route
|
|
388
|
+
? options.routePolicyResult.__evolitLoadedModules
|
|
389
|
+
: null;
|
|
390
|
+
const { pageModule, layoutModules } = preloadedModules ?? await loadRouteModules(
|
|
388
391
|
match.route,
|
|
389
392
|
projectRoot,
|
|
390
393
|
mode,
|
|
@@ -394,7 +397,7 @@ export async function createRouteResolver(projectRoot, mode = "development", res
|
|
|
394
397
|
const cachePolicy = normalizeRouteCachePolicy(routeConfig);
|
|
395
398
|
|
|
396
399
|
if (options.renderTree === false) {
|
|
397
|
-
|
|
400
|
+
const routePolicyResult = {
|
|
398
401
|
type: "route",
|
|
399
402
|
status: 200,
|
|
400
403
|
route: match.route,
|
|
@@ -404,6 +407,10 @@ export async function createRouteResolver(projectRoot, mode = "development", res
|
|
|
404
407
|
cachePolicy,
|
|
405
408
|
cacheKey: createRequestCacheKey(url),
|
|
406
409
|
};
|
|
410
|
+
Object.defineProperty(routePolicyResult, "__evolitLoadedModules", {
|
|
411
|
+
value: { pageModule, layoutModules },
|
|
412
|
+
});
|
|
413
|
+
return routePolicyResult;
|
|
407
414
|
}
|
|
408
415
|
|
|
409
416
|
const pageComponent = assertServerComponent(
|
|
@@ -509,8 +516,8 @@ export async function createRouteResolver(projectRoot, mode = "development", res
|
|
|
509
516
|
async resolveRoutePolicy(request) {
|
|
510
517
|
return resolveMatchedRequest(request, { renderTree: false });
|
|
511
518
|
},
|
|
512
|
-
async resolveRequest(request) {
|
|
513
|
-
return resolveMatchedRequest(request, { renderTree: true });
|
|
519
|
+
async resolveRequest(request, routePolicyResult = null) {
|
|
520
|
+
return resolveMatchedRequest(request, { renderTree: true, routePolicyResult });
|
|
514
521
|
},
|
|
515
522
|
};
|
|
516
523
|
}
|
package/src/server.js
CHANGED
|
@@ -78,7 +78,7 @@ async function createRecursiveDirectoryWatcher(rootDirectory, onChange) {
|
|
|
78
78
|
let watcher;
|
|
79
79
|
try {
|
|
80
80
|
watcher = watch(directory, (eventType, fileName) => {
|
|
81
|
-
onChange();
|
|
81
|
+
onChange(fileName ? path.join(directory, String(fileName)) : null);
|
|
82
82
|
|
|
83
83
|
if (eventType === "rename" && fileName) {
|
|
84
84
|
void watchNewDirectory(path.join(directory, fileName));
|
|
@@ -165,8 +165,12 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
165
165
|
let pendingInvalidation = null;
|
|
166
166
|
let resolvePendingInvalidation = null;
|
|
167
167
|
let invalidationPromise = Promise.resolve();
|
|
168
|
+
const pendingChangedPaths = new Set();
|
|
168
169
|
|
|
169
|
-
function scheduleDevelopmentInvalidation() {
|
|
170
|
+
function scheduleDevelopmentInvalidation(changedPath = null) {
|
|
171
|
+
if (changedPath) {
|
|
172
|
+
pendingChangedPaths.add(path.resolve(changedPath));
|
|
173
|
+
}
|
|
170
174
|
if (invalidationTimer) {
|
|
171
175
|
clearTimeout(invalidationTimer);
|
|
172
176
|
}
|
|
@@ -180,11 +184,15 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
180
184
|
invalidationTimer = setTimeout(() => {
|
|
181
185
|
invalidationTimer = null;
|
|
182
186
|
const resolve = resolvePendingInvalidation;
|
|
187
|
+
const changedPaths = pendingChangedPaths.size > 0
|
|
188
|
+
? [...pendingChangedPaths]
|
|
189
|
+
: null;
|
|
190
|
+
pendingChangedPaths.clear();
|
|
183
191
|
pendingInvalidation = null;
|
|
184
192
|
resolvePendingInvalidation = null;
|
|
185
193
|
invalidationPromise = invalidationPromise
|
|
186
194
|
.catch(() => {})
|
|
187
|
-
.then(() => deploymentRuntime.invalidateDevelopmentState());
|
|
195
|
+
.then(() => deploymentRuntime.invalidateDevelopmentState(changedPaths));
|
|
188
196
|
invalidationPromise.then(
|
|
189
197
|
() => {
|
|
190
198
|
for (const socket of liveReloadSockets) {
|