@alepha/react 0.14.3 → 0.14.4

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.
Files changed (45) hide show
  1. package/dist/auth/index.browser.js +29 -14
  2. package/dist/auth/index.browser.js.map +1 -1
  3. package/dist/auth/index.js +959 -194
  4. package/dist/auth/index.js.map +1 -1
  5. package/dist/head/index.browser.js +59 -19
  6. package/dist/head/index.browser.js.map +1 -1
  7. package/dist/head/index.d.ts +99 -560
  8. package/dist/head/index.d.ts.map +1 -1
  9. package/dist/head/index.js +91 -87
  10. package/dist/head/index.js.map +1 -1
  11. package/dist/router/index.browser.js +30 -15
  12. package/dist/router/index.browser.js.map +1 -1
  13. package/dist/router/index.d.ts +616 -192
  14. package/dist/router/index.d.ts.map +1 -1
  15. package/dist/router/index.js +960 -195
  16. package/dist/router/index.js.map +1 -1
  17. package/package.json +4 -4
  18. package/src/core/__tests__/Router.spec.tsx +4 -4
  19. package/src/head/{__tests__/expandSeo.spec.ts → helpers/SeoExpander.spec.ts} +1 -1
  20. package/src/head/index.ts +10 -28
  21. package/src/head/providers/BrowserHeadProvider.browser.spec.ts +1 -76
  22. package/src/head/providers/BrowserHeadProvider.ts +25 -19
  23. package/src/head/providers/HeadProvider.ts +76 -10
  24. package/src/head/providers/ServerHeadProvider.ts +22 -138
  25. package/src/router/__tests__/page-head-browser.browser.spec.ts +91 -0
  26. package/src/router/__tests__/page-head.spec.ts +44 -0
  27. package/src/{head → router}/__tests__/seo-head.spec.ts +2 -2
  28. package/src/router/atoms/ssrManifestAtom.ts +60 -0
  29. package/src/router/constants/PAGE_PRELOAD_KEY.ts +6 -0
  30. package/src/router/errors/Redirection.ts +1 -1
  31. package/src/router/index.shared.ts +1 -0
  32. package/src/router/index.ts +16 -2
  33. package/src/router/primitives/$page.browser.spec.tsx +15 -15
  34. package/src/router/primitives/$page.spec.tsx +18 -18
  35. package/src/router/primitives/$page.ts +46 -10
  36. package/src/router/providers/ReactBrowserProvider.ts +14 -29
  37. package/src/router/providers/ReactBrowserRouterProvider.ts +5 -0
  38. package/src/router/providers/ReactPageProvider.ts +11 -4
  39. package/src/router/providers/ReactServerProvider.ts +331 -316
  40. package/src/router/providers/ReactServerTemplateProvider.ts +775 -0
  41. package/src/router/providers/SSRManifestProvider.ts +365 -0
  42. package/src/router/services/ReactPageServerService.ts +5 -3
  43. package/src/router/services/ReactRouter.ts +3 -3
  44. package/src/head/__tests__/page-head.spec.ts +0 -39
  45. package/src/head/providers/ServerHeadProvider.spec.ts +0 -163
@@ -1,36 +1,14 @@
1
- import {
2
- $atom,
3
- $env,
4
- $hook,
5
- $inject,
6
- $use,
7
- Alepha,
8
- type State,
9
- type Static,
10
- t,
11
- } from "alepha";
1
+ import { $atom, $env, $hook, $inject, $use, Alepha, type State, type Static, t, } from "alepha";
12
2
  import { DateTimeProvider } from "alepha/datetime";
13
3
  import { $logger } from "alepha/logger";
14
4
  import { LinkProvider } from "alepha/server/links";
5
+ import { BrowserHeadProvider } from "@alepha/react/head";
15
6
  import { ReactBrowserRouterProvider } from "./ReactBrowserRouterProvider.ts";
16
- import type {
17
- PreviousLayerData,
18
- ReactRouterState,
19
- TransitionOptions,
20
- } from "./ReactPageProvider.ts";
7
+ import type { PreviousLayerData, ReactRouterState, } from "./ReactPageProvider.ts";
21
8
  import type { RouterGoOptions } from "../services/ReactRouter.ts";
22
9
 
23
10
  export type { RouterGoOptions } from "../services/ReactRouter.ts";
24
11
 
25
- // ---------------------------------------------------------------------------------------------------------------------
26
-
27
- const envSchema = t.object({
28
- REACT_ROOT_ID: t.text({ default: "root" }),
29
- });
30
-
31
- declare module "alepha" {
32
- interface Env extends Partial<Static<typeof envSchema>> {}
33
- }
34
12
 
35
13
  /**
36
14
  * React browser renderer configuration atom
@@ -38,7 +16,7 @@ declare module "alepha" {
38
16
  export const reactBrowserOptions = $atom({
39
17
  name: "alepha.react.browser.options",
40
18
  schema: t.object({
41
- scrollRestoration: t.enum(["top", "manual"]),
19
+ scrollRestoration: t.enum(["top", "manual"]), // TODO: must be per page?
42
20
  }),
43
21
  default: {
44
22
  scrollRestoration: "top" as const,
@@ -58,23 +36,27 @@ declare module "alepha" {
58
36
  // ---------------------------------------------------------------------------------------------------------------------
59
37
 
60
38
  export class ReactBrowserProvider {
61
- protected readonly env = $env(envSchema);
62
39
  protected readonly log = $logger();
63
40
  protected readonly client = $inject(LinkProvider);
64
41
  protected readonly alepha = $inject(Alepha);
65
42
  protected readonly router = $inject(ReactBrowserRouterProvider);
66
43
  protected readonly dateTimeProvider = $inject(DateTimeProvider);
44
+ protected readonly browserHeadProvider = $inject(BrowserHeadProvider);
67
45
 
68
46
  protected readonly options = $use(reactBrowserOptions);
69
47
 
48
+ public get rootId() {
49
+ return "root";
50
+ }
51
+
70
52
  protected getRootElement() {
71
- const root = this.document.getElementById(this.env.REACT_ROOT_ID);
53
+ const root = this.document.getElementById(this.rootId);
72
54
  if (root) {
73
55
  return root;
74
56
  }
75
57
 
76
58
  const div = this.document.createElement("div");
77
- div.id = this.env.REACT_ROOT_ID;
59
+ div.id = this.rootId;
78
60
 
79
61
  this.document.body.prepend(div);
80
62
 
@@ -281,6 +263,9 @@ export class ReactBrowserProvider {
281
263
  state: this.state,
282
264
  });
283
265
 
266
+ // Fill and render head from route configurations
267
+ this.browserHeadProvider.fillAndRenderHead(this.state);
268
+
284
269
  window.addEventListener("popstate", () => {
285
270
  // when you update silently queryParams or hash, skip rendering
286
271
  // if you want to force a rendering, use #go()
@@ -2,6 +2,7 @@ import { $hook, $inject, Alepha } from "alepha";
2
2
  import { $logger } from "alepha/logger";
3
3
  import { type Route, RouterProvider } from "alepha/router";
4
4
  import { createElement, type ReactNode } from "react";
5
+ import { BrowserHeadProvider } from "@alepha/react/head";
5
6
  import NotFoundPage from "../components/NotFound.tsx";
6
7
  import {
7
8
  isPageRoute,
@@ -23,6 +24,7 @@ export class ReactBrowserRouterProvider extends RouterProvider<BrowserRoute> {
23
24
  protected readonly log = $logger();
24
25
  protected readonly alepha = $inject(Alepha);
25
26
  protected readonly pageApi = $inject(ReactPageProvider);
27
+ protected readonly browserHeadProvider = $inject(BrowserHeadProvider);
26
28
 
27
29
  public add(entry: PageRouteEntry) {
28
30
  this.pageApi.add(entry);
@@ -147,6 +149,9 @@ export class ReactBrowserRouterProvider extends RouterProvider<BrowserRoute> {
147
149
  await this.alepha.events.emit("react:transition:end", {
148
150
  state,
149
151
  });
152
+
153
+ // Fill and render head from route configurations
154
+ this.browserHeadProvider.fillAndRenderHead(state);
150
155
  }
151
156
 
152
157
  public root(state: ReactRouterState): ReactNode {
@@ -22,6 +22,7 @@ import {
22
22
  type PagePrimitive,
23
23
  type PagePrimitiveOptions,
24
24
  } from "../primitives/$page.ts";
25
+ import type { Head } from "@alepha/react/head";
25
26
 
26
27
  const envSchema = t.object({
27
28
  REACT_STRICT_MODE: t.boolean({ default: true }),
@@ -251,15 +252,15 @@ export class ReactPageProvider {
251
252
  forceRefresh = true;
252
253
  }
253
254
 
254
- // no resolve, render a basic view by default
255
- if (!route.resolve) {
255
+ // no loader, render a basic view by default
256
+ if (!route.loader) {
256
257
  continue;
257
258
  }
258
259
 
259
260
  try {
260
261
  const args = Object.create(state);
261
262
  Object.assign(args, config, context);
262
- const props = (await route.resolve?.(args)) ?? {};
263
+ const props = (await route.loader?.(args)) ?? {};
263
264
 
264
265
  // save props
265
266
  it.props = {
@@ -279,7 +280,7 @@ export class ReactPageProvider {
279
280
  };
280
281
  }
281
282
 
282
- this.log.error("Page resolver has failed", e);
283
+ this.log.error("Page loader has failed", e);
283
284
 
284
285
  it.error = e as Error;
285
286
  break;
@@ -696,6 +697,12 @@ export interface ReactRouterState {
696
697
  */
697
698
  meta: Record<string, any>;
698
699
 
700
+ /**
701
+ * Head configuration for the current page (title, meta tags, etc.).
702
+ * Populated by HeadProvider during SSR.
703
+ */
704
+ head: Head;
705
+
699
706
  //
700
707
  name?: string;
701
708
  }