@antelopejs/dms-frontend 0.3.7 → 0.3.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antelopejs/dms-frontend",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Frontend-agnostic loader for AntelopeJS DMS, shipping the Vue 3 renderer (Vite, Inertia, SSR)",
5
5
  "keywords": [
6
6
  "antelope",
@@ -333,6 +333,11 @@ export interface DmsFrontendRuntime {
333
333
  pendingNavigation?: Promise<void>;
334
334
  hasNavigationListener: boolean;
335
335
  pageVersion: number;
336
+ /**
337
+ * Identifies the page on screen (its path, or the error page shown at that
338
+ * path), whose meta `route.meta` holds.
339
+ */
340
+ pageKey?: string;
336
341
  /** The `Cookie` header of the request a server runtime renders. */
337
342
  requestCookies?: string;
338
343
  /**
@@ -495,7 +500,10 @@ function parseRoute(runtime: DmsFrontendRuntime, url: string): DmsRoute {
495
500
  }
496
501
 
497
502
  function updateRoute(runtime: DmsFrontendRuntime, url: string): void {
498
- Object.assign(runtime.route, parseRoute(runtime, url));
503
+ // The meta is the page's, not the URL's: a page declares it, then reads its
504
+ // route, and the middleware the meta selected must still find it.
505
+ const { meta: _pageMeta, ...location } = parseRoute(runtime, url);
506
+ Object.assign(runtime.route, location);
499
507
  }
500
508
 
501
509
  function locationToUrl(
@@ -578,16 +586,22 @@ async function visit(
578
586
  export function useDmsRoute(pattern?: string): DmsRoute {
579
587
  const runtime = useDmsRuntime();
580
588
  runtime.currentRoutePattern = pattern;
589
+ // A server render answers one request, whose URL the runtime was given with
590
+ // its page, and never changes it. Inertia's page is one ref for the whole
591
+ // process, written by each render as it starts: after an await it may hold
592
+ // another request's URL, and while the plugins set up, the previous one's.
593
+ if (runtime.isServer) {
594
+ updateRoute(runtime, runtime.route.fullPath);
595
+ return runtime.route;
596
+ }
581
597
  const page = usePage();
582
- updateRoute(runtime, page.url);
583
- // A server render never changes its URL, and Inertia's page is shared by
584
- // every render the process runs: a watcher there would only tie this
585
- // request's runtime to all the requests after it.
586
- if (!runtime.isServer)
587
- watch(
588
- () => page.url,
589
- (url) => updateRoute(runtime, url),
590
- );
598
+ // The browser's plugins set up before Inertia has a page: until then the
599
+ // runtime's route is the initial page's.
600
+ if (page.url !== undefined) updateRoute(runtime, page.url);
601
+ watch(
602
+ () => page.url,
603
+ (url) => updateRoute(runtime, url),
604
+ );
591
605
  return runtime.route;
592
606
  }
593
607
 
@@ -1360,6 +1374,14 @@ export function getDmsLayoutProps(
1360
1374
  export function hydrateDmsPageProps(props: DmsPageProps, url?: string): void {
1361
1375
  const runtime = useDmsRuntime();
1362
1376
  if (url) updateRoute(runtime, url);
1377
+ // Pages are keyed by path: another path mounts another page, which declares
1378
+ // its own meta, and so does an error page shown in place of the page. A
1379
+ // visit that only changes the query keeps the page, and so its meta.
1380
+ const pageKey = props.error ? `error:${props.path}` : props.path;
1381
+ if (pageKey !== runtime.pageKey) {
1382
+ runtime.pageKey = pageKey;
1383
+ runtime.route.meta = {};
1384
+ }
1363
1385
  runtime.pageVersion++;
1364
1386
  runtime.currentError.value = null;
1365
1387
  useDmsState<DmsUser | null>("dms-user", () => null).value =
@@ -401,6 +401,22 @@ async function answeredByVite(devServer, request, response) {
401
401
  return result.status !== "unhandled";
402
402
  }
403
403
 
404
+ /**
405
+ * Vite's own URLs (`/@vite/client`, `/@id/…`, `/@fs/…`) and paths with an
406
+ * extension name files: modules, stylesheets, fonts, images, built assets.
407
+ * The backend's routes outside `/api` and `/dms` are mostly the paths of the
408
+ * pages they serve data for, which have none (`/<page>/pagelayout`).
409
+ */
410
+ function isFilePath(pathname) {
411
+ return pathname.startsWith("/@") || extname(pathname) !== "";
412
+ }
413
+
414
+ /** Vite's files in development, the build's in production. */
415
+ async function answeredWithFile(devServer, request, response, pathname) {
416
+ if (!devServer) return serveAsset(pathname, request, response);
417
+ return pathname !== "/" && answeredByVite(devServer, request, response);
418
+ }
419
+
404
420
  export async function handleRequest(request, response) {
405
421
  const url = new URL(request.url, "http://frontend.local");
406
422
  const pathname = url.pathname;
@@ -421,13 +437,18 @@ export async function handleRequest(request, response) {
421
437
  return proxy(request, response);
422
438
  if (requestFailure.hasMalformedPath(request.url))
423
439
  return requestFailure.writeBadRequest(response);
424
- if (!isFrontendVisit(request) && (await proxy(request, response, true)))
425
- return;
426
440
  const devServer = await developmentServer();
427
- if (devServer && pathname !== "/") {
428
- if (await answeredByVite(devServer, request, response)) return;
429
- }
430
- if (!devServer && serveAsset(pathname, request, response)) return;
441
+ const visit = isFrontendVisit(request);
442
+ // A file is looked for among the frontend's own before the backend is asked
443
+ // for it: asking first cost a backend round trip for each of the hundreds of
444
+ // modules a development page loads, and for each built asset. A file the
445
+ // frontend does not have, a media file, is still the backend's.
446
+ const fileFirst = !visit && isFilePath(pathname);
447
+ const serveFile = () =>
448
+ answeredWithFile(devServer, request, response, pathname);
449
+ if (fileFirst && (await serveFile())) return;
450
+ if (!visit && (await proxy(request, response, true))) return;
451
+ if (!fileFirst && (await serveFile())) return;
431
452
  if (handleAssetVersionMismatch(request, response)) return;
432
453
  if (redirectToHomepage(request, response, pathname)) return;
433
454
  const props = await pageProps(request);