crelte 0.1.3 → 0.2.1

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 (53) hide show
  1. package/dist/CrelteRequest.d.ts +11 -6
  2. package/dist/CrelteRequest.d.ts.map +1 -1
  3. package/dist/CrelteRequest.js +14 -14
  4. package/dist/graphql/GraphQl.d.ts +1 -1
  5. package/dist/graphql/GraphQl.d.ts.map +1 -1
  6. package/dist/graphql/GraphQl.js +1 -1
  7. package/dist/index.d.ts +3 -1
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +10 -3
  10. package/dist/init/client.d.ts.map +1 -1
  11. package/dist/init/client.js +11 -5
  12. package/dist/init/server.d.ts +2 -0
  13. package/dist/init/server.d.ts.map +1 -1
  14. package/dist/init/server.js +24 -10
  15. package/dist/init/shared.d.ts +3 -3
  16. package/dist/init/shared.d.ts.map +1 -1
  17. package/dist/init/shared.js +1 -1
  18. package/dist/loadData/index.d.ts +11 -5
  19. package/dist/loadData/index.d.ts.map +1 -1
  20. package/dist/loadData/index.js +15 -6
  21. package/dist/routing/History.d.ts +5 -3
  22. package/dist/routing/History.d.ts.map +1 -1
  23. package/dist/routing/History.js +9 -4
  24. package/dist/routing/InnerRouter.d.ts +31 -21
  25. package/dist/routing/InnerRouter.d.ts.map +1 -1
  26. package/dist/routing/InnerRouter.js +98 -76
  27. package/dist/routing/PageLoader.d.ts +4 -5
  28. package/dist/routing/PageLoader.d.ts.map +1 -1
  29. package/dist/routing/PageLoader.js +5 -5
  30. package/dist/routing/Request.d.ts +15 -2
  31. package/dist/routing/Request.d.ts.map +1 -1
  32. package/dist/routing/Request.js +22 -1
  33. package/dist/routing/Route.d.ts +61 -25
  34. package/dist/routing/Route.d.ts.map +1 -1
  35. package/dist/routing/Route.js +90 -41
  36. package/dist/routing/Router.d.ts +34 -13
  37. package/dist/routing/Router.d.ts.map +1 -1
  38. package/dist/routing/Router.js +102 -49
  39. package/package.json +3 -2
  40. package/src/CrelteRequest.ts +14 -19
  41. package/src/graphql/GraphQl.ts +5 -2
  42. package/src/index.ts +26 -3
  43. package/src/init/client.ts +14 -10
  44. package/src/init/server.ts +31 -11
  45. package/src/init/shared.ts +4 -4
  46. package/src/loadData/index.ts +47 -15
  47. package/src/routing/History.ts +12 -5
  48. package/src/routing/InnerRouter.ts +109 -82
  49. package/src/routing/PageLoader.ts +7 -17
  50. package/src/routing/Request.ts +28 -6
  51. package/src/routing/Route.ts +115 -52
  52. package/src/routing/Router.ts +123 -59
  53. package/LICENSE.md +0 -41
@@ -1,4 +1,3 @@
1
- import Route from './Route.js';
2
1
  import InnerRouter from './InnerRouter.js';
3
2
  import PageLoader from './PageLoader.js';
4
3
  import { Writable } from 'crelte-std/stores';
@@ -29,7 +28,6 @@ export default class Router {
29
28
  * The loading progress, the value is between 0 and 1
30
29
  */
31
30
  _loadingProgress;
32
- _onRouteEv;
33
31
  _onRequest;
34
32
  /** @hidden */
35
33
  _internal;
@@ -49,19 +47,19 @@ export default class Router {
49
47
  this._request = null;
50
48
  this._loading = new Writable(false);
51
49
  this._loadingProgress = new Writable(0);
52
- this._onRouteEv = new Listeners();
53
50
  this._onRequest = new Listeners();
54
51
  this._internal = {
55
52
  onLoaded: () => { },
53
+ onNothingLoaded: () => { },
56
54
  onLoad: () => { },
57
55
  domReady: req => this.inner.domReady(req),
58
56
  initClient: () => this._initClient(),
59
57
  initServer: (url, acceptLang) => this._initServer(url, acceptLang),
60
58
  };
61
- this.inner.onRoute = (route, site, changeHistory) => this._onRoute(route, site, changeHistory);
62
- this.inner.onPreload = (route, site) => this._onPreload(route, site);
63
- this.pageLoader.onLoaded = (resp, req, site, more) => this._onLoaded(resp, req, site, more);
64
- this.pageLoader.loadFn = (req, site, opts) => this._internal.onLoad(req, site, opts);
59
+ this.inner.onRoute = (route, changeHistory) => this._onRoute(route, changeHistory);
60
+ this.inner.onPreload = route => this._onPreload(route);
61
+ this.pageLoader.onLoaded = (resp, req, more) => this._onLoaded(resp, req, more);
62
+ this.pageLoader.loadFn = (req, opts) => this._internal.onLoad(req, opts);
65
63
  this.pageLoader.onProgress = (loading, progress) => this._onProgress(loading, progress);
66
64
  }
67
65
  /**
@@ -97,10 +95,13 @@ export default class Router {
97
95
  /**
98
96
  * Open a new route
99
97
  *
100
- * @param target the target to open can be an url or a route
98
+ * @param target the target to open can be an url, a route or a request
101
99
  * the url needs to start with http or with a / which will be considered as
102
100
  * the site baseUrl
103
101
  *
102
+ * ## Note
103
+ * The origin will always be set to 'manual'
104
+ *
104
105
  * ## Example
105
106
  * ```
106
107
  * import { getRouter } from 'crelte';
@@ -112,15 +113,24 @@ export default class Router {
112
113
  * // the following page will be opened https://example.com/de/foo/bar
113
114
  * ```
114
115
  */
115
- open(target) {
116
- this.inner.open(target);
116
+ open(target, opts = {}) {
117
+ const req = this.inner.targetToRequest(target, {
118
+ ...opts,
119
+ origin: 'manual',
120
+ });
121
+ this.inner.open(req);
117
122
  }
118
123
  /**
119
- * This pushes the state of the route without triggering an event
124
+ * This pushes the new route without triggering a new pageload
120
125
  *
121
126
  * You can use this when using pagination for example change the route object
122
127
  * (search argument) and then call pushState
123
128
  *
129
+ * ## Note
130
+ * This will always set the origin to 'push'
131
+ * And will clear the scrollY value if you not provide a new one via the `opts`
132
+ * This will disableLoadData by default if you not provide an override via the `opts`
133
+ *
124
134
  * ## Example
125
135
  * ```
126
136
  * import { getRouter } from 'crelte';
@@ -133,16 +143,35 @@ export default class Router {
133
143
  * router.pushState(route);
134
144
  * ```
135
145
  */
136
- pushState(route) {
146
+ push(route, opts = {}) {
147
+ // cancel previous request
137
148
  this.pageLoader.discard();
138
- this.inner.pushState(route);
149
+ const req = this.inner.targetToRequest(route, {
150
+ ...opts,
151
+ origin: 'push',
152
+ scrollY: opts.scrollY ?? undefined,
153
+ disableLoadData: opts.disableLoadData ?? true,
154
+ });
155
+ this.inner.push(req);
156
+ this.destroyRequest();
139
157
  this.setNewRoute(route);
140
158
  }
159
+ /**
160
+ * @deprecated use push instead
161
+ */
162
+ pushState(route) {
163
+ this.push(route);
164
+ }
141
165
  /**
142
166
  * This replaces the state of the route without triggering an event
143
167
  *
144
168
  * You can use this when using some filters for example a search filter
145
169
  *
170
+ * ## Note
171
+ * This will always set the origin to 'replace'
172
+ * And will clear the scrollY value if you not provide a new one via the `opts`
173
+ * This will disableLoadData by default if you not provide an override via the `opts`
174
+ *
146
175
  * ## Example
147
176
  * ```
148
177
  * import { getRouter } from 'crelte';
@@ -155,10 +184,23 @@ export default class Router {
155
184
  * router.replaceState(route);
156
185
  * ```
157
186
  */
158
- replaceState(route) {
187
+ replace(route, opts = {}) {
188
+ // cancel previous request
159
189
  this.pageLoader.discard();
160
- this.inner.replaceState(route);
161
- this.setNewRoute(route);
190
+ const req = this.inner.targetToRequest(route, {
191
+ origin: 'replace',
192
+ scrollY: opts.scrollY ?? undefined,
193
+ disableLoadData: opts.disableLoadData ?? true,
194
+ });
195
+ this.inner.replace(req);
196
+ this.destroyRequest();
197
+ this.setNewRoute(req);
198
+ }
199
+ /**
200
+ * @deprecated use replace instead
201
+ */
202
+ replaceState(route) {
203
+ this.replace(route);
162
204
  }
163
205
  /**
164
206
  * Checks if there are previous routes which would allow it to go back
@@ -181,13 +223,13 @@ export default class Router {
181
223
  /**
182
224
  * Add a listener for the onRoute event
183
225
  *
184
- * This differs from router.route.subscribe in the way that
185
- * it will only trigger if a new render / load will occur
226
+ * This will trigger every time a new route is set
227
+ * and is equivalent to router.route.subscribe(fn)
186
228
  *
187
229
  * @returns a function to remove the listener
188
230
  */
189
231
  onRoute(fn) {
190
- return this._onRouteEv.add(fn);
232
+ return this.route.subscribe(fn);
191
233
  }
192
234
  /**
193
235
  * Add a listener for the onRequest event
@@ -200,12 +242,11 @@ export default class Router {
200
242
  return this._onRequest.add(fn);
201
243
  }
202
244
  setNewRoute(route) {
203
- this.destroyRequest();
204
245
  this._route.setSilent(route);
205
- if (route.site)
206
- this._site.setSilent(route.site);
246
+ const siteChanged = this.site.get()?.id !== route.site.id;
247
+ this._site.setSilent(route.site);
207
248
  this._route.notify();
208
- if (route.site)
249
+ if (siteChanged)
209
250
  this._site.notify();
210
251
  }
211
252
  async _initClient() {
@@ -213,15 +254,17 @@ export default class Router {
213
254
  }
214
255
  async _initServer(url, acceptLang) {
215
256
  this.inner.initServer();
257
+ this._internal.onNothingLoaded = (_req, ready) => {
258
+ ready();
259
+ };
216
260
  const prom = new Promise(resolve => {
217
- this._internal.onLoaded = (success, req, site, ready) => {
261
+ this._internal.onLoaded = (success, req, ready) => {
218
262
  const props = ready();
219
263
  this._internal.onLoaded = () => { };
220
264
  resolve({
221
265
  success,
222
266
  redirect: false,
223
267
  req,
224
- site,
225
268
  props,
226
269
  });
227
270
  };
@@ -230,43 +273,46 @@ export default class Router {
230
273
  route.origin = 'init';
231
274
  // let's see if the url matches any route and site
232
275
  // if not let's redirect to the site which matches the acceptLang
233
- if (!route.site) {
276
+ if (!route.siteMatches()) {
234
277
  const site = this.inner.siteByAcceptLang(acceptLang);
235
278
  return {
236
279
  success: true,
237
280
  redirect: true,
238
281
  req: new Request(site.url, site),
239
- site,
240
282
  props: {},
241
283
  };
242
284
  }
243
285
  this.inner.setRoute(route);
244
286
  const resp = await prom;
245
287
  const hist = this.inner.history;
246
- if (hist.url) {
247
- const nRoute = new Route(hist.url, null);
248
- if (!route.eq(nRoute)) {
288
+ if (hist.url || hist.req) {
289
+ const nReq = this.inner.targetToRequest(hist.req ?? hist.url);
290
+ if (!route.eq(nReq)) {
249
291
  return {
250
292
  success: true,
251
293
  redirect: true,
252
- req: Request.fromRoute(nRoute),
253
- site: route.site,
294
+ req: nReq,
254
295
  props: {},
255
296
  };
256
297
  }
257
298
  }
258
299
  return resp;
259
300
  }
260
- _onRoute(req, site, changeHistory) {
301
+ _onRoute(req, changeHistory) {
261
302
  this.destroyRequest();
262
303
  this._request = req;
263
304
  const barrier = req._renderBarrier;
264
305
  if (barrier.isOpen()) {
265
306
  throw new Error('render barrier is already open');
266
307
  }
267
- this._onRequest.trigger(req, site);
308
+ this._onRequest.trigger(req);
268
309
  // route prepared
269
- this.pageLoader.load(req, site, { changeHistory });
310
+ if (!req.disableLoadData) {
311
+ this.pageLoader.load(req, { changeHistory });
312
+ }
313
+ else {
314
+ this._onNothingLoaded(req, { changeHistory });
315
+ }
270
316
  }
271
317
  destroyRequest() {
272
318
  if (!this._request)
@@ -274,10 +320,10 @@ export default class Router {
274
320
  this._request._renderBarrier.cancel();
275
321
  this._request = null;
276
322
  }
277
- _onPreload(req, site) {
278
- this.pageLoader.preload(req, site);
323
+ _onPreload(req) {
324
+ this.pageLoader.preload(req);
279
325
  }
280
- async _onLoaded(resp, req, site, more) {
326
+ async _onLoaded(resp, req, more) {
281
327
  // check if the render was cancelled
282
328
  if (await req._renderBarrier.ready())
283
329
  return;
@@ -286,20 +332,27 @@ export default class Router {
286
332
  // in the meantime
287
333
  more.changeHistory();
288
334
  const route = req.toRoute();
289
- const updateRoute = () => {
290
- this._route.setSilent(route);
291
- const siteChanged = this.site.get()?.id !== site.id;
292
- this._site.setSilent(site);
293
- this._route.notify();
294
- if (siteChanged)
295
- this._site.notify();
296
- this._onRouteEv.trigger(route.clone(), site);
297
- };
298
- this._internal.onLoaded(resp.success, req, site, () => {
299
- updateRoute();
335
+ // call the client or server saying we are ready for a new render
336
+ this._internal.onLoaded(resp.success, req, () => {
337
+ this.setNewRoute(route);
300
338
  return resp.data;
301
339
  });
302
340
  }
341
+ async _onNothingLoaded(req, more) {
342
+ // check if the render was cancelled
343
+ if (await req._renderBarrier.ready())
344
+ return;
345
+ // when the data is loaded let's update the route of the inner
346
+ // this is will only happen if no other route has been requested
347
+ // in the meantime
348
+ more.changeHistory();
349
+ const route = req.toRoute();
350
+ // call the client or server saying there was an update in the route
351
+ // but no new data was loaded so no render should happen
352
+ this._internal.onNothingLoaded(req, () => {
353
+ this.setNewRoute(route);
354
+ });
355
+ }
303
356
  _onProgress(loading, progress) {
304
357
  if (this._loading.get() !== loading)
305
358
  this._loading.set(loading);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crelte",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "author": "Crelte <support@crelte.com>",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -74,6 +74,7 @@
74
74
  "@sveltejs/vite-plugin-svelte": "^3.0.0",
75
75
  "svelte-check": "^4.1.4",
76
76
  "typescript-svelte-plugin": "^0.3.45",
77
- "vitest": "^2.0.0"
77
+ "vitest": "^2.0.0",
78
+ "vite": "^5.0"
78
79
  }
79
80
  }
@@ -11,19 +11,12 @@ export default class CrelteRequest extends Crelte {
11
11
  */
12
12
  req: Request;
13
13
 
14
- /**
15
- * The current site
16
- */
17
- site: Site;
18
-
19
14
  private innerGlobals: Map<string, any>;
20
15
 
21
- /// requires a site if the route does not contain a site
22
- constructor(inner: Crelte, req: Request, site: Site) {
16
+ constructor(inner: Crelte, req: Request) {
23
17
  super(inner);
24
18
 
25
19
  this.req = req;
26
- this.site = site;
27
20
  this.innerGlobals = new Map();
28
21
  }
29
22
 
@@ -37,24 +30,14 @@ export default class CrelteRequest extends Crelte {
37
30
  * If you provide a route it must contain a site or you must
38
31
  * provide one,
39
32
  */
40
- static fromCrelte(
41
- inner: Crelte,
42
- req?: Route | Request,
43
- site?: Site,
44
- ): CrelteRequest {
33
+ static fromCrelte(inner: Crelte, req?: Route | Request): CrelteRequest {
45
34
  if (!req) {
46
35
  req = inner.router.route.get();
47
36
  }
48
37
 
49
- if (!site) {
50
- if (!req.site) throw new Error('site is required');
51
- site = req.site;
52
- }
53
-
54
38
  return new CrelteRequest(
55
39
  inner,
56
40
  req instanceof Request ? req : Request.fromRoute(req),
57
- site,
58
41
  );
59
42
  }
60
43
 
@@ -66,6 +49,18 @@ export default class CrelteRequest extends Crelte {
66
49
  return this.req;
67
50
  }
68
51
 
52
+ /**
53
+ * Easy access to this.req.site
54
+ *
55
+ * ## Note
56
+ * The site might not always match with the current route
57
+ * but be the site default site or one that matches the
58
+ * users language.
59
+ */
60
+ get site(): Site {
61
+ return this.req.site;
62
+ }
63
+
69
64
  /**
70
65
  * returns a globalSet
71
66
  *
@@ -70,7 +70,9 @@ export type GraphQlOptions = {
70
70
  */
71
71
  export type GraphQlRequestOptions = {
72
72
  path?: string;
73
- route?: Route;
73
+ // !! the route here might not contain a site even if the types
74
+ // says it does. CrelteServer does not know about site
75
+ route?: Route | URL;
74
76
  ignoreStatusCode?: boolean;
75
77
  previewToken?: string;
76
78
  siteToken?: string;
@@ -124,7 +126,8 @@ export default class GraphQl {
124
126
  opts: GraphQlRequestOptions = {},
125
127
  ): Promise<unknown> {
126
128
  if (opts.route) {
127
- const search = opts.route.search;
129
+ const search =
130
+ (opts.route as URL).searchParams ?? opts.route.search;
128
131
 
129
132
  // todo should variables contain siteId
130
133
  // or maybe gql should detect loadData and add it there
package/src/index.ts CHANGED
@@ -9,8 +9,22 @@ import CrelteRequest from './CrelteRequest.js';
9
9
  import type { Global, GlobalData } from './loadData/Globals.js';
10
10
  import type { Cookies } from './cookies/index.js';
11
11
  import type { Readable } from 'crelte-std/stores';
12
+ import {
13
+ LoadData,
14
+ LoadDataArray,
15
+ LoadDataFn,
16
+ LoadDataObj,
17
+ } from './loadData/index.js';
12
18
 
13
- export { Crelte, CrelteRequest, type QueryOptions };
19
+ export {
20
+ Crelte,
21
+ CrelteRequest,
22
+ type QueryOptions,
23
+ type LoadData,
24
+ type LoadDataFn,
25
+ type LoadDataObj,
26
+ type LoadDataArray,
27
+ };
14
28
 
15
29
  /**
16
30
  * Get Crelte from the current context
@@ -129,6 +143,15 @@ export function getCookies(): Cookies {
129
143
  return getCrelte().cookies;
130
144
  }
131
145
 
146
+ export function onRoute(fn: (route: Route, crelte: Crelte) => void) {
147
+ const crelte = getCrelte();
148
+ const rmListener = crelte.router.onRoute(route => {
149
+ fn(route, crelte);
150
+ });
151
+
152
+ onDestroy(rmListener);
153
+ }
154
+
132
155
  /**
133
156
  * Listen for requests
134
157
  *
@@ -137,8 +160,8 @@ export function getCookies(): Cookies {
137
160
  */
138
161
  export function onRequest(fn: (cr: CrelteRequest) => void) {
139
162
  const crelte = getCrelte();
140
- const rmListener = crelte.router.onRequest((req, site) => {
141
- fn(new CrelteRequest(crelte, req, site));
163
+ const rmListener = crelte.router.onRequest(req => {
164
+ fn(new CrelteRequest(crelte, req));
142
165
  });
143
166
 
144
167
  onDestroy(rmListener);
@@ -131,8 +131,8 @@ export function main(data: MainData) {
131
131
 
132
132
  // setup load Data
133
133
 
134
- crelte.router._internal.onLoad = (req, site, opts) => {
135
- const cr = new CrelteRequest(crelte, req, site);
134
+ crelte.router._internal.onLoad = (req, opts) => {
135
+ const cr = new CrelteRequest(crelte, req);
136
136
  return loadFn(cr, data.app, data.entryQuery, data.globalQuery, opts);
137
137
  };
138
138
 
@@ -154,12 +154,7 @@ export function main(data: MainData) {
154
154
  };
155
155
 
156
156
  let firstLoad = true;
157
- crelte.router._internal.onLoaded = async (
158
- success,
159
- req,
160
- site,
161
- readyForProps,
162
- ) => {
157
+ crelte.router._internal.onLoaded = async (success, req, readyForProps) => {
163
158
  const isFirstLoad = firstLoad;
164
159
  firstLoad = false;
165
160
 
@@ -177,13 +172,13 @@ export function main(data: MainData) {
177
172
  return handleLoadError(readyForProps());
178
173
  }
179
174
 
180
- const cr = new CrelteRequest(crelte, req, site);
175
+ const cr = new CrelteRequest(crelte, req);
181
176
 
182
177
  const startTime = data.debugTiming ? Date.now() : null;
183
178
  let render = async () => {
184
179
  // we should trigger the route update here
185
180
  pluginsBeforeRender(cr);
186
- crelte.globals._updateSiteId(site.id);
181
+ crelte.globals._updateSiteId(cr.site.id);
187
182
  updateAppProps(readyForProps());
188
183
 
189
184
  await tick();
@@ -209,6 +204,15 @@ export function main(data: MainData) {
209
204
  await render();
210
205
  };
211
206
 
207
+ crelte.router._internal.onNothingLoaded = async (req, ready) => {
208
+ crelte.globals._updateSiteId(req.site.id);
209
+ ready();
210
+
211
+ await tick();
212
+
213
+ crelte.router._internal.domReady(req);
214
+ };
215
+
212
216
  crelte.router._internal.initClient();
213
217
  }
214
218
 
@@ -16,6 +16,8 @@ export type ServerData = {
16
16
  craftWeb: string;
17
17
  viteEnv: Map<string, string>;
18
18
  cookies?: string;
19
+ readSitesCache?: () => Promise<any>;
20
+ writeSitesCache?: (data: any) => Promise<void>;
19
21
  };
20
22
 
21
23
  /**
@@ -85,7 +87,7 @@ export async function main(data: MainData): Promise<{
85
87
  const cookies = data.serverData.cookies ?? '';
86
88
  builder.setupCookies(cookies);
87
89
 
88
- const csites = await loadSites(builder);
90
+ const csites = await loadSites(builder, data.serverData);
89
91
  builder.ssrCache.set('crelteSites', csites);
90
92
  builder.setupRouter(csites);
91
93
 
@@ -96,12 +98,12 @@ export async function main(data: MainData): Promise<{
96
98
 
97
99
  // setup load Data
98
100
 
99
- crelte.router._internal.onLoad = (req, site) => {
100
- const cr = new CrelteRequest(crelte, req, site);
101
+ crelte.router._internal.onLoad = req => {
102
+ const cr = new CrelteRequest(crelte, req);
101
103
  return loadFn(cr, data.app, data.entryQuery, data.globalQuery);
102
104
  };
103
105
 
104
- const { success, redirect, req, site, props } =
106
+ const { success, redirect, req, props } =
105
107
  await crelte.router._internal.initServer(
106
108
  data.serverData.url,
107
109
  data.serverData.acceptLang,
@@ -110,7 +112,7 @@ export async function main(data: MainData): Promise<{
110
112
 
111
113
  if (redirect) {
112
114
  return {
113
- status: 302,
115
+ status: req.statusCode ?? 302,
114
116
  location: req.url.toString(),
115
117
  };
116
118
  }
@@ -119,8 +121,9 @@ export async function main(data: MainData): Promise<{
119
121
  const ssrComponents = new SsrComponents();
120
122
  ssrComponents.addToContext(context);
121
123
 
122
- pluginsBeforeRender(new CrelteRequest(crelte, req, site));
123
- crelte.globals._updateSiteId(site.id);
124
+ const cr = new CrelteRequest(crelte, req);
125
+ pluginsBeforeRender(cr);
126
+ crelte.globals._updateSiteId(cr.site.id);
124
127
  // eslint-disable-next-line prefer-const
125
128
  let { html, head } = data.app.default.render(props, { context });
126
129
 
@@ -128,7 +131,7 @@ export async function main(data: MainData): Promise<{
128
131
  head += crelte.ssrCache._exportToHead();
129
132
 
130
133
  let htmlTemplate = data.serverData.htmlTemplate;
131
- htmlTemplate = htmlTemplate.replace('<!--page-lang-->', site.language);
134
+ htmlTemplate = htmlTemplate.replace('<!--page-lang-->', cr.site.language);
132
135
 
133
136
  const finalHtml = htmlTemplate
134
137
  .replace('</head>', head + '\n\t</head>')
@@ -205,12 +208,26 @@ export async function mainError(
205
208
  }
206
209
 
207
210
  // requires, GraphQl, SsrCache
208
- async function loadSites(builder: CrelteBuilder): Promise<SiteFromGraphQl[]> {
211
+ async function loadSites(
212
+ builder: CrelteBuilder,
213
+ serverData: ServerData,
214
+ ): Promise<SiteFromGraphQl[]> {
209
215
  if (!builder.graphQl) throw new Error();
210
216
 
211
217
  if ('CRAFT_SITES_CACHED' in globalThis) {
212
- // @ts-ignore
213
- return globalThis['CRAFT_SITES_CACHED'];
218
+ return (globalThis as any)['CRAFT_SITES_CACHED'];
219
+ }
220
+
221
+ if (import.meta.env.PROD && serverData.readSitesCache) {
222
+ try {
223
+ const sites =
224
+ (await serverData.readSitesCache()) as SiteFromGraphQl[];
225
+ // @ts-ignore
226
+ globalThis['CRAFT_SITES_CACHED'] = sites;
227
+ return sites;
228
+ } catch (_e: any) {
229
+ // ignore
230
+ }
214
231
  }
215
232
 
216
233
  const resp = (await builder.graphQl.query(
@@ -233,5 +250,8 @@ async function loadSites(builder: CrelteBuilder): Promise<SiteFromGraphQl[]> {
233
250
 
234
251
  // @ts-ignore
235
252
  globalThis['CRAFT_SITES_CACHED'] = resp.crelteSites;
253
+ if (import.meta.env.PROD && serverData.writeSitesCache) {
254
+ await serverData.writeSitesCache(resp.crelteSites);
255
+ }
236
256
  return resp.crelteSites;
237
257
  }
@@ -5,8 +5,8 @@ import { LoadData, callLoadData } from '../loadData/index.js';
5
5
  import { PluginCreator } from '../plugins/Plugins.js';
6
6
  import { LoadOptions } from '../routing/PageLoader.js';
7
7
 
8
- interface App<D, E, T> {
9
- loadGlobalData?: LoadData<D>;
8
+ interface App<E, T> {
9
+ loadGlobalData?: LoadData<null>;
10
10
 
11
11
  // todo: add a generic
12
12
  loadEntryData?: LoadData<any>;
@@ -60,7 +60,7 @@ export function getEntry(page: any): any {
60
60
 
61
61
  export async function loadFn<D, E, T>(
62
62
  cr: CrelteRequest,
63
- app: App<D, E, T>,
63
+ app: App<E, T>,
64
64
  entryQuery: GraphQlQuery,
65
65
  globalQuery?: GraphQlQuery,
66
66
  loadOpts?: LoadOptions,
@@ -75,7 +75,7 @@ export async function loadFn<D, E, T>(
75
75
  }
76
76
 
77
77
  if (app.loadGlobalData) {
78
- dataProm = callLoadData(app.loadGlobalData, cr) as any;
78
+ dataProm = callLoadData(app.loadGlobalData, cr, null) as any;
79
79
  }
80
80
 
81
81
  let globalProm: Promise<any> | null = null;