crelte 0.5.11 → 0.5.12

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 (90) hide show
  1. package/dist/bodyClass/BodyClass.d.ts +39 -0
  2. package/dist/bodyClass/BodyClass.d.ts.map +1 -0
  3. package/dist/bodyClass/BodyClass.js +51 -0
  4. package/dist/bodyClass/ClientBodyClass.d.ts +12 -0
  5. package/dist/bodyClass/ClientBodyClass.d.ts.map +1 -0
  6. package/dist/bodyClass/ClientBodyClass.js +57 -0
  7. package/dist/bodyClass/ServerBodyClass.d.ts +12 -0
  8. package/dist/bodyClass/ServerBodyClass.d.ts.map +1 -0
  9. package/dist/bodyClass/ServerBodyClass.js +47 -0
  10. package/dist/bodyClass/index.d.ts +2 -0
  11. package/dist/bodyClass/index.d.ts.map +1 -0
  12. package/dist/bodyClass/index.js +1 -0
  13. package/dist/cookies/ClientCookies.d.ts +8 -3
  14. package/dist/cookies/ClientCookies.d.ts.map +1 -1
  15. package/dist/cookies/ClientCookies.js +31 -7
  16. package/dist/cookies/Cookies.d.ts +42 -0
  17. package/dist/cookies/Cookies.d.ts.map +1 -0
  18. package/dist/cookies/Cookies.js +44 -0
  19. package/dist/cookies/ServerCookies.d.ts +3 -2
  20. package/dist/cookies/ServerCookies.d.ts.map +1 -1
  21. package/dist/cookies/ServerCookies.js +6 -4
  22. package/dist/cookies/index.d.ts +1 -25
  23. package/dist/cookies/index.d.ts.map +1 -1
  24. package/dist/cookies/index.js +1 -1
  25. package/dist/crelte.d.ts +7 -1
  26. package/dist/crelte.d.ts.map +1 -1
  27. package/dist/crelte.js +2 -1
  28. package/dist/index.d.ts +13 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +9 -0
  31. package/dist/init/client.d.ts.map +1 -1
  32. package/dist/init/client.js +23 -14
  33. package/dist/init/server.d.ts.map +1 -1
  34. package/dist/init/server.js +11 -3
  35. package/dist/init/shared.d.ts +1 -0
  36. package/dist/init/shared.d.ts.map +1 -1
  37. package/dist/init/shared.js +16 -5
  38. package/dist/loadData/Globals.d.ts.map +1 -1
  39. package/dist/node/index.js +1 -1
  40. package/dist/plugins/Events.d.ts +6 -1
  41. package/dist/plugins/Events.d.ts.map +1 -1
  42. package/dist/plugins/Plugins.d.ts +36 -1
  43. package/dist/plugins/Plugins.d.ts.map +1 -1
  44. package/dist/plugins/Plugins.js +32 -0
  45. package/dist/routing/route/Request.d.ts +1 -1
  46. package/dist/routing/route/Request.d.ts.map +1 -1
  47. package/dist/routing/route/Request.js +7 -3
  48. package/dist/routing/router/ClientRouter.d.ts.map +1 -1
  49. package/dist/routing/router/ClientRouter.js +18 -11
  50. package/dist/routing/router/Router.d.ts.map +1 -1
  51. package/dist/routing/router/Router.js +8 -12
  52. package/dist/server/CrelteServer.d.ts +1 -0
  53. package/dist/server/CrelteServer.d.ts.map +1 -1
  54. package/dist/server/CrelteServer.js +5 -2
  55. package/dist/std/stores/StagedWritable.d.ts +48 -0
  56. package/dist/std/stores/StagedWritable.d.ts.map +1 -0
  57. package/dist/std/stores/StagedWritable.js +84 -0
  58. package/dist/std/stores/index.d.ts +2 -1
  59. package/dist/std/stores/index.d.ts.map +1 -1
  60. package/dist/std/stores/index.js +2 -1
  61. package/dist/std/sync/Barrier.js +1 -1
  62. package/dist/utils.d.ts +9 -0
  63. package/dist/utils.d.ts.map +1 -1
  64. package/dist/utils.js +11 -0
  65. package/package.json +5 -1
  66. package/src/bodyClass/BodyClass.ts +72 -0
  67. package/src/bodyClass/ClientBodyClass.ts +62 -0
  68. package/src/bodyClass/ServerBodyClass.ts +65 -0
  69. package/src/bodyClass/index.ts +1 -0
  70. package/src/cookies/ClientCookies.ts +41 -10
  71. package/src/cookies/Cookies.ts +70 -0
  72. package/src/cookies/ServerCookies.ts +9 -6
  73. package/src/cookies/index.ts +5 -29
  74. package/src/crelte.ts +9 -0
  75. package/src/index.ts +15 -1
  76. package/src/init/client.ts +26 -14
  77. package/src/init/server.ts +11 -3
  78. package/src/init/shared.ts +18 -6
  79. package/src/loadData/Globals.ts +1 -1
  80. package/src/node/index.ts +1 -1
  81. package/src/plugins/Events.ts +12 -1
  82. package/src/plugins/Plugins.ts +66 -1
  83. package/src/routing/route/Request.ts +11 -4
  84. package/src/routing/router/ClientRouter.ts +23 -14
  85. package/src/routing/router/Router.ts +8 -10
  86. package/src/server/CrelteServer.ts +4 -2
  87. package/src/std/stores/StagedWritable.ts +96 -0
  88. package/src/std/stores/index.ts +2 -1
  89. package/src/std/sync/Barrier.ts +1 -1
  90. package/src/utils.ts +15 -0
package/src/crelte.ts CHANGED
@@ -9,6 +9,7 @@ import Queries, { Query, QueryOptions } from './queries/Queries.js';
9
9
  import { Readable } from './std/stores/index.js';
10
10
  import { Entry } from './loadData/index.js';
11
11
  import { urlWithPath } from './utils.js';
12
+ import { BodyClass } from './bodyClass/index.js';
12
13
 
13
14
  /** The type for the app.config object */
14
15
  export type Config = {
@@ -113,6 +114,11 @@ export type Crelte = {
113
114
  */
114
115
  cookies: Cookies;
115
116
 
117
+ /**
118
+ * Get the BodyClass instance
119
+ */
120
+ bodyClass: BodyClass;
121
+
116
122
  /**
117
123
  * Get a Plugin by name
118
124
  */
@@ -263,6 +269,7 @@ export function newCrelte({
263
269
  router,
264
270
  queries,
265
271
  cookies,
272
+ bodyClass,
266
273
  }: {
267
274
  config: Required<Config>;
268
275
  ssrCache: SsrCache;
@@ -272,6 +279,7 @@ export function newCrelte({
272
279
  router: Router;
273
280
  queries: Queries;
274
281
  cookies: Cookies;
282
+ bodyClass: BodyClass;
275
283
  }): Crelte {
276
284
  return {
277
285
  config,
@@ -282,6 +290,7 @@ export function newCrelte({
282
290
  router,
283
291
  queries,
284
292
  cookies,
293
+ bodyClass,
285
294
 
286
295
  getPlugin: name => plugins.get(name),
287
296
  getEnv: key => ssrCache.get(key as any) as any,
package/src/index.ts CHANGED
@@ -17,7 +17,8 @@ import {
17
17
  LoadDataObj,
18
18
  } from './loadData/index.js';
19
19
  import Queries from './queries/Queries.js';
20
- import { Readable } from './std/stores/index.js';
20
+ import { Readable, Writable } from './std/stores/index.js';
21
+ import { BodyClass } from './bodyClass/index.js';
21
22
 
22
23
  export {
23
24
  type Crelte,
@@ -33,6 +34,9 @@ export {
33
34
  /** The type for the app.init function */
34
35
  export type Init = (crelte: Crelte) => void;
35
36
 
37
+ /** The Props that are passed to the app */
38
+ export type AppProps = { route: Writable<Route> };
39
+
36
40
  function innerGetCrelte(): Crelte {
37
41
  return getContext('crelte');
38
42
  }
@@ -174,6 +178,16 @@ export function getCookies(): Cookies {
174
178
  return innerGetCrelte().cookies;
175
179
  }
176
180
 
181
+ /**
182
+ * returns the body class instance
183
+ *
184
+ * #### Note
185
+ * This only works during component initialisation.
186
+ */
187
+ export function getBodyClass(): BodyClass {
188
+ return innerGetCrelte().bodyClass;
189
+ }
190
+
177
191
  /**
178
192
  * Listen for route changes
179
193
  *
@@ -3,6 +3,7 @@ import {
3
3
  loadFn,
4
4
  newQueries,
5
5
  onNewCrelteRequest,
6
+ pluginsAfterRender,
6
7
  pluginsBeforeRender,
7
8
  pluginsBeforeRequest,
8
9
  setupPlugins,
@@ -19,6 +20,9 @@ import Plugins from '../plugins/Plugins.js';
19
20
  import Events from '../plugins/Events.js';
20
21
  import Globals from '../loadData/Globals.js';
21
22
  import { Writable } from '../std/stores/index.js';
23
+ import ClientBodyClass from '../bodyClass/ClientBodyClass.js';
24
+ import { BodyClass } from '../bodyClass/index.js';
25
+ import { Cookies } from '../cookies/index.js';
22
26
 
23
27
  /**
24
28
  * The main function to start the client side rendering
@@ -74,7 +78,6 @@ export async function main(data: MainData) {
74
78
  });
75
79
 
76
80
  const queries = newQueries(ssrCache, router.route.readonly(), config);
77
- const cookies = new ClientCookies();
78
81
 
79
82
  const crelte = newCrelte({
80
83
  config,
@@ -84,7 +87,8 @@ export async function main(data: MainData) {
84
87
  globals: new Globals(),
85
88
  router: new Router(router),
86
89
  queries,
87
- cookies,
90
+ cookies: new Cookies(new ClientCookies()),
91
+ bodyClass: new BodyClass(new ClientBodyClass()),
88
92
  });
89
93
 
90
94
  const app = new InternalApp(data.app);
@@ -101,22 +105,22 @@ export async function main(data: MainData) {
101
105
 
102
106
  // render Space
103
107
 
104
- let appInstance: any;
105
- let routeProp: Writable<Route>;
108
+ let routeProp: Writable<Route> | null = null;
106
109
  const renderApp = (route: Route) => {
107
- if (appInstance) {
108
- routeProp!.set(route);
110
+ if (routeProp) {
111
+ routeProp.set(route);
109
112
  return;
110
113
  }
111
114
 
112
115
  routeProp = new Writable(route);
113
- appInstance = svelteMount(data.app.default, {
116
+ svelteMount(data.app.default, {
114
117
  target: document.body,
115
118
  props: { route: routeProp },
116
119
  context: new Map([['crelte', crelte]]),
117
120
  intro: config.playIntro,
118
121
  });
119
122
  };
123
+ const appMounted = () => !!routeProp;
120
124
 
121
125
  router.onError = (e, req) => {
122
126
  console.error('routing failed:', e, 'reloading trying to fix it');
@@ -126,9 +130,9 @@ export async function main(data: MainData) {
126
130
  };
127
131
 
128
132
  router.onRender = async (cr, readyForRoute, domUpdated) => {
129
- if (appInstance && cr.req.disableLoadData) {
133
+ if (appMounted() && cr.req.disableLoadData) {
130
134
  // if the app is already rendered and entry did not change
131
- // we just wan't to run domUpdated because we don't wan't to update anything
135
+ // we just wan't to run domUpdated because we don't want to update anything
132
136
 
133
137
  const route = readyForRoute();
134
138
  cr.router.z_requestCompleted();
@@ -140,6 +144,7 @@ export async function main(data: MainData) {
140
144
  await tick();
141
145
 
142
146
  domUpdated(cr, route);
147
+ pluginsAfterRender(cr, route);
143
148
 
144
149
  return route;
145
150
  }
@@ -149,9 +154,15 @@ export async function main(data: MainData) {
149
154
  let render = async () => {
150
155
  const route = readyForRoute();
151
156
  cr.router.z_requestCompleted();
152
- if (route.entryChanged) cr.globals.z_syncToStores();
153
- // we should trigger the route update here
154
- pluginsBeforeRender(cr, route);
157
+ // this is only important on the first render
158
+ // else we will catch an earlier branch in onRender
159
+ if (route.entryChanged) {
160
+ cr.globals.z_syncToStores();
161
+ pluginsBeforeRender(cr, route);
162
+ cr.cookies.z_render();
163
+ cr.bodyClass.z_render();
164
+ }
165
+
155
166
  renderApp(route);
156
167
 
157
168
  await tick();
@@ -163,6 +174,7 @@ export async function main(data: MainData) {
163
174
  }
164
175
 
165
176
  domUpdated(cr, route);
177
+ pluginsAfterRender(cr, route);
166
178
 
167
179
  return route;
168
180
  };
@@ -170,7 +182,7 @@ export async function main(data: MainData) {
170
182
  // render with view Transition if enabled and not in hydration
171
183
  if (
172
184
  config.viewTransition &&
173
- appInstance &&
185
+ appMounted() &&
174
186
  (document as any).startViewTransition
175
187
  ) {
176
188
  const prevRender = render;
@@ -211,8 +223,8 @@ function handleLoadError(e: any) {
211
223
 
212
224
  // Messages in different languages
213
225
  const messages: Record<string, string> = {
214
- en: 'An error has occurred. Please reload the page or try again later.',
215
226
  de: 'Leider ist ein Fehler aufgetreten. Laden Sie die Seite neu, oder versuchen Sie es später noch mal.',
227
+ en: 'An error has occurred. Please reload the page or try again later.',
216
228
  fr: 'Une erreur s’est produite. Veuillez recharger la page ou réessayer plus tard.',
217
229
  it: 'Si è verificato un errore. Ricarica la pagina o riprova più tardi.',
218
230
  nl: 'Er is een fout opgetreden. Herlaad de pagina of probeer het later opnieuw.',
@@ -23,6 +23,9 @@ import {
23
23
  RenderRequest,
24
24
  RenderResponse,
25
25
  } from '../server/shared.js';
26
+ import ServerBodyClass from '../bodyClass/ServerBodyClass.js';
27
+ import BodyClass from '../bodyClass/BodyClass.js';
28
+ import { Cookies } from '../cookies/index.js';
26
29
 
27
30
  export { type RenderRequest, type RenderResponse } from '../server/shared.js';
28
31
 
@@ -75,6 +78,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
75
78
  ssrCache.set('FRONTEND_URL', data.serverData.frontend);
76
79
 
77
80
  const cookies = new ServerCookies(data.serverData.headers);
81
+ const bodyClass = new ServerBodyClass();
78
82
 
79
83
  ssrCache.set('crelteSites', data.serverData.sites);
80
84
  const router = new ServerRouter(
@@ -93,7 +97,8 @@ export async function main(data: MainData): Promise<RenderResponse> {
93
97
  globals: new Globals(),
94
98
  router: new Router(router),
95
99
  queries,
96
- cookies,
100
+ cookies: new Cookies(cookies),
101
+ bodyClass: new BodyClass(bodyClass),
97
102
  });
98
103
 
99
104
  const app = new InternalApp(data.app);
@@ -111,6 +116,8 @@ export async function main(data: MainData): Promise<RenderResponse> {
111
116
  cr.router.z_requestCompleted();
112
117
  cr.globals.z_syncToStores();
113
118
  pluginsBeforeRender(cr, route);
119
+ cr.cookies.z_render();
120
+ cr.bodyClass.z_render();
114
121
 
115
122
  return route;
116
123
  };
@@ -121,7 +128,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
121
128
  // if redirect
122
129
  if (!route) {
123
130
  const headers = new Headers();
124
- (crelte.cookies as ServerCookies)._populateHeaders(headers);
131
+ cookies._populateHeaders(headers);
125
132
 
126
133
  return {
127
134
  status: req.statusCode ?? 302,
@@ -153,6 +160,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
153
160
  '<!--page-lang-->',
154
161
  route.site.language,
155
162
  );
163
+ htmlTemplate = bodyClass.z_processHtmlTemplate(htmlTemplate);
156
164
 
157
165
  const finalHtml = htmlTemplate
158
166
  .replace('</head>', head + '\n\t</head>')
@@ -161,7 +169,7 @@ export async function main(data: MainData): Promise<RenderResponse> {
161
169
  const entry = route.entry;
162
170
 
163
171
  const headers = new Headers();
164
- (crelte.cookies as ServerCookies)._populateHeaders(headers);
172
+ cookies._populateHeaders(headers);
165
173
 
166
174
  return {
167
175
  status:
@@ -32,6 +32,11 @@ export function pluginsBeforeRequest(cr: CrelteRequest): Promise<void> | void {
32
32
 
33
33
  export function pluginsBeforeRender(cr: CrelteRequest, route: Route): void {
34
34
  cr.events.trigger('beforeRender', cr, route);
35
+ cr.plugins.z_render(cr, route);
36
+ }
37
+
38
+ export function pluginsAfterRender(cr: CrelteRequest, route: Route): void {
39
+ cr.events.trigger('afterRender', cr, route);
35
40
  }
36
41
 
37
42
  export function newQueries(
@@ -64,12 +69,15 @@ export function onNewCrelteRequest(
64
69
  ...crelte,
65
70
  router: crelte.router.z_toRequest(req),
66
71
  queries: crelte.queries.z_toRequest(req),
72
+ plugins: crelte.plugins.z_toRequest(req),
67
73
  globals: crelte.globals.z_toRequest(),
74
+ cookies: crelte.cookies.z_toRequest(),
75
+ bodyClass: crelte.bodyClass.z_toRequest(),
68
76
  };
69
77
  return crelteToRequest(nCrelte, req);
70
78
  }
71
79
 
72
- async function pluginsLoadEntry(cr: CrelteRequest): Promise<Entry | null> {
80
+ async function eventsLoadEntry(cr: CrelteRequest): Promise<Entry | null> {
73
81
  const listeners = cr.events.getListeners('loadEntry');
74
82
 
75
83
  for (const loadEntry of listeners) {
@@ -123,7 +131,7 @@ export async function loadFn(
123
131
  // checked to be empty before doing it
124
132
  const entryProm = (async () => {
125
133
  // first let's try to call the plugin loadEntry
126
- let entry = await pluginsLoadEntry(cr);
134
+ let entry = await eventsLoadEntry(cr);
127
135
  if (isCanceled()) return [];
128
136
 
129
137
  // if no plugin provides an entry we load it from the app
@@ -152,7 +160,8 @@ export async function loadFn(
152
160
  return [entry, template] as [Entry, TemplateModule];
153
161
  })();
154
162
 
155
- const pluginsLoadGlobalData = cr.events.trigger('loadGlobalData', cr);
163
+ const eventsLoadGlobalData = cr.events.trigger('loadGlobalData', cr);
164
+ const pluginsLoadGlobalData = cr.plugins.z_loadGlobalData(cr);
156
165
 
157
166
  // loading progress is at 20%
158
167
  loadOpts?.setProgress(0.2);
@@ -160,6 +169,7 @@ export async function loadFn(
160
169
  const loadGlobalDataProm = Promise.all([
161
170
  globalProm,
162
171
  entryProm,
172
+ ...eventsLoadGlobalData,
163
173
  ...pluginsLoadGlobalData,
164
174
  ]);
165
175
 
@@ -167,7 +177,7 @@ export async function loadFn(
167
177
  // we force resolve them to prevent deadlocks
168
178
  if (
169
179
  import.meta.env.DEV &&
170
- !(await Promise.any([loadGlobalDataProm, timeout(2000)]))
180
+ !(await Promise.race([loadGlobalDataProm, timeout(2000)]))
171
181
  ) {
172
182
  console.error(
173
183
  'DEV: globals took longer than 2 seconds to load. ' +
@@ -184,8 +194,6 @@ export async function loadFn(
184
194
  // loading progress is at 60%
185
195
  loadOpts?.setProgress(0.6);
186
196
 
187
- const pluginsLoadData = cr.events.trigger('loadData', cr, entry);
188
-
189
197
  let loadDataProm = null;
190
198
  if (template.loadData) {
191
199
  loadDataProm = callLoadData(template.loadData, cr, entry);
@@ -196,9 +204,13 @@ export async function loadFn(
196
204
  entryDataProm = callLoadData(app.loadEntryData, cr, entry);
197
205
  }
198
206
 
207
+ const eventsLoadData = cr.events.trigger('loadData', cr, entry);
208
+ const pluginsLoadData = cr.plugins.z_loadData(cr);
209
+
199
210
  const [templateData, entryData] = await Promise.all([
200
211
  loadDataProm,
201
212
  entryDataProm,
213
+ ...eventsLoadData,
202
214
  ...pluginsLoadData,
203
215
  ]);
204
216
 
@@ -131,7 +131,7 @@ export default class Globals {
131
131
  * @hidden
132
132
  * call this before starting the loadGlobalData phase
133
133
  */
134
- z_toRequest() {
134
+ z_toRequest(): Globals {
135
135
  const nGlobals = new Globals(this.stores);
136
136
  nGlobals.waiters = new Map();
137
137
  nGlobals.newData = new Map();
package/src/node/index.ts CHANGED
@@ -166,7 +166,7 @@ export default async function createServer(serverMod: any, buildTime: string) {
166
166
  } catch (e) {
167
167
  basicError(res, e);
168
168
  }
169
- }).listen(8080);
169
+ }).listen(process.env.PORT ?? 8080);
170
170
  }
171
171
 
172
172
  function basicError(res: ServerResponse, err: any) {
@@ -32,6 +32,9 @@ export default class Events {
32
32
  * Will be executed in preload as well.
33
33
  *
34
34
  * @returns a function to remove the listener
35
+ *
36
+ * #### afterRender
37
+ * Note this will also be executed when disableLoadData is true
35
38
  */
36
39
  // override this function to add your own function signatures
37
40
  on(
@@ -58,7 +61,14 @@ export default class Events {
58
61
  ev: 'loadData',
59
62
  fn: (cr: CrelteRequest, entry: Entry) => Promise<any> | any,
60
63
  ): () => void;
61
- on(ev: 'beforeRender', fn: (cr: CrelteRequest) => void): () => void;
64
+ on(
65
+ ev: 'beforeRender',
66
+ fn: (cr: CrelteRequest, route: Route) => void,
67
+ ): () => void;
68
+ on(
69
+ ev: 'afterRender',
70
+ fn: (cr: CrelteRequest, route: Route) => void,
71
+ ): () => void;
62
72
  on(ev: string, fn: (...args: any[]) => any): () => void {
63
73
  let set = this.inner.get(ev);
64
74
  if (!set) {
@@ -108,6 +118,7 @@ export default class Events {
108
118
  entry: Entry,
109
119
  ): (Promise<any> | any)[];
110
120
  trigger(ev: 'beforeRender', cr: CrelteRequest, route: Route): void[];
121
+ trigger(ev: 'afterRender', cr: CrelteRequest, route: Route): void[];
111
122
  trigger(ev: string, ...args: any[]): any[] {
112
123
  const set = this.inner.get(ev);
113
124
  if (!set) return [];
@@ -1,10 +1,32 @@
1
- import { Crelte } from '../crelte.js';
1
+ import { Crelte, CrelteRequest } from '../crelte.js';
2
+ import { Request, Route } from '../routing/index.js';
2
3
 
3
4
  /**
4
5
  * A plugin
5
6
  */
6
7
  export interface Plugin {
7
8
  name: string;
9
+ /**
10
+ * The returned value will be used inside of CrelteRequest
11
+ */
12
+ toRequest?: (req: Request) => Plugin;
13
+
14
+ /**
15
+ * This will be called during the loadGlobalData phase.
16
+ */
17
+ loadGlobalData?: (cr: CrelteRequest) => Promise<void> | void;
18
+
19
+ /**
20
+ * This will be called during the loadData phase.
21
+ */
22
+ loadData?: (cr: CrelteRequest) => Promise<void> | void;
23
+
24
+ /**
25
+ * This will be called before the dom gets updated.
26
+ *
27
+ * At this point you can update variables or stores.
28
+ */
29
+ render?: (cr: CrelteRequest, route: Route) => void;
8
30
  }
9
31
 
10
32
  /**
@@ -46,4 +68,47 @@ export default class Plugins {
46
68
  get(name: string): Plugin | null {
47
69
  return this.plugins.get(name) ?? null;
48
70
  }
71
+
72
+ /**
73
+ * @hidden
74
+ */
75
+ z_toRequest(req: Request): Plugins {
76
+ const nPlugins = new Plugins();
77
+
78
+ for (let plugin of this.plugins.values()) {
79
+ if (typeof plugin.toRequest === 'function')
80
+ plugin = plugin.toRequest(req);
81
+
82
+ nPlugins.add(plugin);
83
+ }
84
+
85
+ return nPlugins;
86
+ }
87
+
88
+ /**
89
+ * @hidden
90
+ */
91
+ z_loadGlobalData(cr: CrelteRequest): (Promise<void> | void | undefined)[] {
92
+ return Array.from(this.plugins.values()).map(plugin =>
93
+ plugin.loadGlobalData?.(cr),
94
+ );
95
+ }
96
+
97
+ /**
98
+ * @hidden
99
+ */
100
+ z_loadData(cr: CrelteRequest): (Promise<void> | void | undefined)[] {
101
+ return Array.from(this.plugins.values()).map(plugin =>
102
+ plugin.loadData?.(cr),
103
+ );
104
+ }
105
+
106
+ /**
107
+ * @hidden
108
+ */
109
+ z_render(cr: CrelteRequest, route: Route): void {
110
+ for (const plugin of this.plugins.values()) {
111
+ plugin.render?.(cr, route);
112
+ }
113
+ }
49
114
  }
@@ -1,5 +1,5 @@
1
1
  import Site from '../Site.js';
2
- import { objClone } from '../../utils.js';
2
+ import { objClone, promiseThen } from '../../utils.js';
3
3
  import BaseRoute, { RouteOrigin } from './BaseRoute.js';
4
4
  import Route, { TemplateModule } from './Route.js';
5
5
  import { Entry } from '../../loadData/index.js';
@@ -254,8 +254,15 @@ class RenderBarrier {
254
254
  const action = this.inner.add();
255
255
 
256
256
  return {
257
- ready: async () => {
258
- if (!this.inner.isOpen()) await action.ready(null);
257
+ ready: () => {
258
+ if (!this.inner.isOpen())
259
+ return promiseThen(
260
+ // wait for action.ready
261
+ action.ready(null),
262
+ // then return if it was cancelled
263
+ () => this.cancelled,
264
+ );
265
+
259
266
  return this.cancelled;
260
267
  },
261
268
  remove: () => {
@@ -292,7 +299,7 @@ export type DelayRender = {
292
299
  *
293
300
  * @returns if the render was cancelled
294
301
  */
295
- ready: () => Promise<boolean>;
302
+ ready: () => Promise<boolean> | boolean;
296
303
 
297
304
  /**
298
305
  * If youre not interested when the render happens anymore
@@ -107,7 +107,7 @@ export default class ClientRouter extends BaseRouter {
107
107
  async pushRequest(req: Request, _opts: RequestOptions = {}) {
108
108
  const url = req.url;
109
109
 
110
- return await this.handleRequest(req, route => {
110
+ return this.handleRequest(req, route => {
111
111
  window.history.pushState(
112
112
  route.z_toState(),
113
113
  '',
@@ -119,18 +119,13 @@ export default class ClientRouter extends BaseRouter {
119
119
  async replaceRequest(req: Request, _opts: RequestOptions = {}) {
120
120
  const url = req.url;
121
121
 
122
- try {
123
- return await this.handleRequest(req, () => {
124
- window.history.replaceState(
125
- req.z_toState(),
126
- '',
127
- url.pathname + url.search + url.hash,
128
- );
129
- });
130
- } catch (e) {
131
- console.warn('replacing route failed', e);
132
- throw e;
133
- }
122
+ return this.handleRequest(req, () => {
123
+ window.history.replaceState(
124
+ req.z_toState(),
125
+ '',
126
+ url.pathname + url.search + url.hash,
127
+ );
128
+ });
134
129
  }
135
130
 
136
131
  back(): void {
@@ -164,6 +159,7 @@ export default class ClientRouter extends BaseRouter {
164
159
  const req = this.targetToRequest(link.href, {
165
160
  origin: 'click',
166
161
  context: { ...link.dataset },
162
+ disableScroll: attributeToBool(link, 'data-disable-scroll'),
167
163
  });
168
164
  const currRoute = this.route.get();
169
165
  const routeEq =
@@ -189,7 +185,9 @@ export default class ClientRouter extends BaseRouter {
189
185
 
190
186
  if (
191
187
  link &&
192
- !link.hasAttribute('data-no-preload') &&
188
+ // todo remove data-no-preload
189
+ !attributeToBool(link, 'data-no-preload') &&
190
+ !attributeToBool(link, 'data-disable-preload') &&
193
191
  link.href
194
192
  ) {
195
193
  this.preload(link.href);
@@ -311,3 +309,14 @@ export default class ClientRouter extends BaseRouter {
311
309
  }
312
310
  }
313
311
  }
312
+
313
+ function attributeToBool(el: HTMLElement, attr: string): boolean {
314
+ switch (el.getAttribute(attr)) {
315
+ case '':
316
+ case 'true':
317
+ return true;
318
+ case 'false':
319
+ default:
320
+ return false;
321
+ }
322
+ }
@@ -226,19 +226,18 @@ export default class Router {
226
226
  });
227
227
  if (!req) return;
228
228
 
229
- try {
230
- return await this.inner.pushRequest(req, opts);
231
- } catch (e) {
229
+ return this.inner.pushRequest(req, opts).catch(e => {
232
230
  console.warn('pushing route failed', e);
233
231
  throw e;
234
- }
232
+ });
235
233
  }
236
234
 
237
235
  /**
238
236
  * @deprecated use push instead
239
237
  */
240
238
  pushState(route: Route | Request) {
241
- console.warn('pushState is deprecated, use push instead');
239
+ if (import.meta.env.DEV)
240
+ console.warn('pushState is deprecated, use push instead');
242
241
  this.push(route);
243
242
  }
244
243
 
@@ -287,19 +286,18 @@ export default class Router {
287
286
  });
288
287
  if (!req) return;
289
288
 
290
- try {
291
- return await this.inner.replaceRequest(req, opts);
292
- } catch (e) {
289
+ return this.inner.replaceRequest(req, opts).catch(e => {
293
290
  console.warn('replacing route failed', e);
294
291
  throw e;
295
- }
292
+ });
296
293
  }
297
294
 
298
295
  /**
299
296
  * @deprecated use replace instead
300
297
  */
301
298
  replaceState(route: Route | Request) {
302
- console.warn('replaceState is deprecated, use replace instead');
299
+ if (import.meta.env.DEV)
300
+ console.warn('replaceState is deprecated, use replace instead');
303
301
  this.replace(route);
304
302
  }
305
303
 
@@ -24,6 +24,7 @@ export default class CrelteServerRequest {
24
24
  private _sites: Site[];
25
25
  private _langs: string[];
26
26
  private _queries: Queries;
27
+ private _scookies: ServerCookies;
27
28
  private _cookies: Cookies;
28
29
 
29
30
  constructor(req: ServerRequest, opts: CrelteServerRequestOptions) {
@@ -37,7 +38,8 @@ export default class CrelteServerRequest {
37
38
  this._queries = opts.queries.z_toRequest(
38
39
  new Request(new URL(req.url), req.site),
39
40
  );
40
- this._cookies = new ServerCookies(req.headers);
41
+ this._scookies = new ServerCookies(req.headers);
42
+ this._cookies = new Cookies(this._scookies);
41
43
  }
42
44
 
43
45
  /**
@@ -145,6 +147,6 @@ export default class CrelteServerRequest {
145
147
 
146
148
  /** @hidden */
147
149
  z_finishResponse(resp: Response) {
148
- (this.cookies as ServerCookies)._populateHeaders(resp.headers);
150
+ this._scookies._populateHeaders(resp.headers);
149
151
  }
150
152
  }