@primate/core 0.9.6 → 0.9.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.
@@ -93,8 +93,15 @@ export default async function build_client(app) {
93
93
  const NO_HR = app.config("livereload.exclude") ?? [];
94
94
  app.entrypoint(`
95
95
  const NO_HR = ${JSON.stringify(NO_HR)};
96
- new EventSource("/esbuild").addEventListener("change", () => {
97
- if (!NO_HR.includes(location.pathname)) location.reload();
96
+ const live_reload = new EventSource("/esbuild");
97
+ const close_live_reload = () => live_reload.close();
98
+ addEventListener("pagehide", close_live_reload);
99
+ addEventListener("beforeunload", close_live_reload);
100
+ live_reload.addEventListener("change", () => {
101
+ if (!NO_HR.includes(location.pathname)) {
102
+ close_live_reload();
103
+ location.reload();
104
+ }
98
105
  });
99
106
  `);
100
107
  }
@@ -2,6 +2,7 @@ import type Mode from "#Mode";
2
2
  import type RequestView from "#request/RequestView";
3
3
  import type { Dict } from "@rcompat/type";
4
4
  type ClientData<T extends Dict = Dict> = {
5
+ frontend: string;
5
6
  view: string;
6
7
  request: RequestView;
7
8
  csr: boolean;
@@ -1,5 +1,5 @@
1
1
  import type { Updater } from "#client/root";
2
2
  import type { Dict } from "@rcompat/type";
3
3
  export default _default;
4
- declare function _default<T extends Dict>(u: Updater<T>): void;
4
+ declare function _default<T extends Dict>(frontend: string, u: Updater<T>): void;
5
5
  //# sourceMappingURL=boot.d.ts.map
@@ -3,8 +3,12 @@ import root from "#client/root";
3
3
  import storage from "#client/storage";
4
4
  import submit from "#client/submit";
5
5
  import http from "@rcompat/http";
6
- export default (u) => {
7
- root.set(u);
6
+ let booted = false;
7
+ export default (frontend, u) => {
8
+ root.set(u, frontend);
9
+ if (booted)
10
+ return;
11
+ booted = true;
8
12
  const { location, history } = globalThis;
9
13
  if (document.contentType === "application/json") {
10
14
  location.reload();
@@ -11,7 +11,7 @@ import type ValidateUpdater from "#client/ValidateUpdater";
11
11
  import type ValidationError from "#client/ValidationError";
12
12
  import type ViewResponse from "#client/ViewResponse";
13
13
  declare const client: {
14
- boot: <T extends import("@rcompat/type").Dict>(u: import("./root.js").Updater<T>) => void;
14
+ boot: <T extends import("@rcompat/type").Dict>(frontend: string, u: import("./root.js").Updater<T>) => void;
15
15
  navigate: (href: string, event?: Event) => Promise<void>;
16
16
  submit: typeof submit;
17
17
  createForm: typeof createForm;
@@ -21,8 +21,14 @@ async function goto(target, state = false, after) {
21
21
  const path = target.pathname + target.search;
22
22
  const { requested, response } = await transport.refetch(path, { headers });
23
23
  if (transport.is_json(response)) {
24
- if (response.ok)
25
- root.update(await response.json());
24
+ if (response.ok) {
25
+ const data = await response.json();
26
+ if (!root.same(data)) {
27
+ location.assign(requested.toString() + target.hash);
28
+ return;
29
+ }
30
+ root.update(data);
31
+ }
26
32
  if (state) {
27
33
  storage.new({ hash: location.hash, pathname: location.pathname, scrollTop });
28
34
  history.pushState({}, "", `${path}${target.hash}`);
@@ -2,7 +2,8 @@ import type ClientData from "#client/Data";
2
2
  import type { Dict } from "@rcompat/type";
3
3
  export type Updater<T extends Dict> = (json: ClientData<T>, after?: () => void) => void;
4
4
  declare const root: {
5
- set(updater: Updater<any>): void;
5
+ set(updater: Updater<any>, name: string): void;
6
+ same(data: ClientData): boolean;
6
7
  update(data: any, after?: () => void): void;
7
8
  };
8
9
  export default root;
@@ -1,7 +1,12 @@
1
1
  let current;
2
+ let frontend;
2
3
  const root = {
3
- set(updater) {
4
+ set(updater, name) {
4
5
  current = updater;
6
+ frontend = name;
7
+ },
8
+ same(data) {
9
+ return data.frontend === frontend;
5
10
  },
6
11
  update(data, after) {
7
12
  current(data, after);
@@ -58,7 +58,7 @@ export default function frontend_module(init) {
58
58
  if (app_asset === undefined)
59
59
  throw E.frontend_missing_app_js();
60
60
  const app_script = `<script type="module" src="${app_asset.src}"></script>`;
61
- const props = JSON.stringify({ frontend: init.name, ...client });
61
+ const props = JSON.stringify(client);
62
62
  const hydrated = await inline(props, http.MIME.APPLICATION_JSON, "hydration");
63
63
  const script_src = [hydrated.integrity];
64
64
  return {
@@ -84,6 +84,7 @@ export default function frontend_module(init) {
84
84
  }
85
85
  : { props, request: $request };
86
86
  const client = {
87
+ frontend: init.name,
87
88
  view: init.layouts ? "root" : await normalize(view),
88
89
  csr,
89
90
  ssr: ssr(),
@@ -1,7 +1,14 @@
1
1
  import location from "#location";
2
2
  import http from "@rcompat/http";
3
3
  const sse_reload = `<script>
4
- new EventSource("/esbuild").addEventListener("change", () => location.reload());
4
+ const live_reload = new EventSource("/esbuild");
5
+ const close_live_reload = () => live_reload.close();
6
+ addEventListener("pagehide", close_live_reload);
7
+ addEventListener("beforeunload", close_live_reload);
8
+ live_reload.addEventListener("change", () => {
9
+ close_live_reload();
10
+ location.reload();
11
+ });
5
12
  </script>`;
6
13
  /**
7
14
  * Render an error page.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primate/core",
3
- "version": "0.9.6",
3
+ "version": "0.9.8",
4
4
  "description": "The universal web framework",
5
5
  "homepage": "https://primate.run",
6
6
  "bugs": "https://github.com/primate-run/primate/issues",