crelte 0.4.8 → 0.5.0-alpha.2
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/dist/Crelte.d.ts +7 -6
- package/dist/Crelte.d.ts.map +1 -1
- package/dist/Crelte.js +5 -13
- package/dist/CrelteRequest.d.ts +9 -0
- package/dist/CrelteRequest.d.ts.map +1 -1
- package/dist/CrelteRequest.js +16 -2
- package/dist/blocks/Blocks.svelte +2 -2
- package/dist/blocks/Blocks.svelte.d.ts +3 -19
- package/dist/blocks/Blocks.svelte.d.ts.map +1 -1
- package/dist/cookies/ClientCookies.d.ts +0 -1
- package/dist/cookies/ClientCookies.d.ts.map +1 -1
- package/dist/cookies/ClientCookies.js +0 -1
- package/dist/cookies/ServerCookies.d.ts +1 -2
- package/dist/cookies/ServerCookies.d.ts.map +1 -1
- package/dist/cookies/ServerCookies.js +2 -6
- package/dist/cookies/index.d.ts +0 -2
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/graphql/GraphQl.d.ts +2 -2
- package/dist/graphql/GraphQl.d.ts.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -6
- package/dist/init/InternalApp.d.ts +30 -0
- package/dist/init/InternalApp.d.ts.map +1 -0
- package/dist/init/InternalApp.js +71 -0
- package/dist/init/client.d.ts +0 -5
- package/dist/init/client.d.ts.map +1 -1
- package/dist/init/client.js +88 -75
- package/dist/init/crelte-vite-plugin.d.ts +5 -0
- package/dist/init/server.d.ts +0 -5
- package/dist/init/server.d.ts.map +1 -1
- package/dist/init/server.js +49 -20
- package/dist/init/shared.d.ts +7 -18
- package/dist/init/shared.d.ts.map +1 -1
- package/dist/init/shared.js +97 -154
- package/dist/init/svelteComponents.d.ts +3 -0
- package/dist/init/svelteComponents.d.ts.map +1 -0
- package/dist/init/svelteComponents.js +7 -0
- package/dist/loadData/Globals.d.ts +40 -33
- package/dist/loadData/Globals.d.ts.map +1 -1
- package/dist/loadData/Globals.js +99 -88
- package/dist/loadData/index.d.ts +3 -2
- package/dist/loadData/index.d.ts.map +1 -1
- package/dist/loadData/index.js +2 -0
- package/dist/plugins/Events.d.ts +11 -13
- package/dist/plugins/Events.d.ts.map +1 -1
- package/dist/plugins/Events.js +10 -3
- package/dist/routing/BaseRoute.d.ts +255 -0
- package/dist/routing/BaseRoute.d.ts.map +1 -0
- package/dist/routing/BaseRoute.js +349 -0
- package/dist/routing/BaseRouter.d.ts +210 -0
- package/dist/routing/BaseRouter.d.ts.map +1 -0
- package/dist/routing/BaseRouter.js +444 -0
- package/dist/routing/ClientRouter.d.ts +32 -0
- package/dist/routing/ClientRouter.d.ts.map +1 -0
- package/dist/routing/ClientRouter.js +259 -0
- package/dist/routing/LoadRunner.d.ts +39 -0
- package/dist/routing/LoadRunner.d.ts.map +1 -0
- package/dist/routing/{PageLoader.js → LoadRunner.js} +32 -20
- package/dist/routing/Request.d.ts +35 -3
- package/dist/routing/Request.d.ts.map +1 -1
- package/dist/routing/Request.js +64 -5
- package/dist/routing/Route.d.ts +24 -223
- package/dist/routing/Route.d.ts.map +1 -1
- package/dist/routing/Route.js +26 -315
- package/dist/routing/Router.d.ts +49 -73
- package/dist/routing/Router.d.ts.map +1 -1
- package/dist/routing/Router.js +85 -251
- package/dist/routing/ServerRouter.d.ts +23 -0
- package/dist/routing/ServerRouter.d.ts.map +1 -0
- package/dist/routing/ServerRouter.js +57 -0
- package/dist/routing/utils.d.ts +5 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js +39 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -0
- package/package.json +7 -6
- package/src/Crelte.ts +12 -18
- package/src/CrelteRequest.ts +21 -2
- package/src/cookies/ClientCookies.ts +0 -2
- package/src/cookies/ServerCookies.ts +2 -7
- package/src/cookies/index.ts +0 -3
- package/src/graphql/GraphQl.ts +2 -1
- package/src/index.ts +17 -9
- package/src/init/InternalApp.ts +134 -0
- package/src/init/client.ts +104 -93
- package/src/init/crelte-vite-plugin.d.ts +5 -0
- package/src/init/server.ts +67 -35
- package/src/init/shared.ts +107 -227
- package/src/init/svelteComponents.ts +12 -0
- package/src/loadData/Globals.ts +121 -102
- package/src/loadData/index.ts +3 -2
- package/src/plugins/Events.ts +40 -42
- package/src/routing/BaseRoute.ts +422 -0
- package/src/routing/BaseRouter.ts +528 -0
- package/src/routing/ClientRouter.ts +329 -0
- package/src/routing/{PageLoader.ts → LoadRunner.ts} +43 -30
- package/src/routing/Request.ts +97 -12
- package/src/routing/Route.ts +56 -376
- package/src/routing/Router.ts +100 -359
- package/src/routing/ServerRouter.ts +78 -0
- package/src/routing/utils.ts +53 -0
- package/src/utils.ts +4 -0
- package/dist/routing/InnerRouter.d.ts +0 -113
- package/dist/routing/InnerRouter.d.ts.map +0 -1
- package/dist/routing/InnerRouter.js +0 -417
- package/dist/routing/PageLoader.d.ts +0 -36
- package/dist/routing/PageLoader.d.ts.map +0 -1
- package/src/routing/InnerRouter.ts +0 -498
package/src/routing/Router.ts
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import { Readable, Writable } from 'crelte-std/stores';
|
|
7
|
-
import { Listeners } from 'crelte-std/sync';
|
|
8
|
-
import Request, { RequestOptions } from './Request.js';
|
|
9
|
-
|
|
10
|
-
export type RouterOptions = {
|
|
11
|
-
preloadOnMouseOver?: boolean;
|
|
12
|
-
debugTiming?: boolean;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const defaultRouterOpts = {
|
|
16
|
-
preloadOnMouseOver: false,
|
|
17
|
-
debugTiming: false,
|
|
18
|
-
};
|
|
1
|
+
import { Readable } from 'crelte-std/stores';
|
|
2
|
+
import BaseRouter from './BaseRouter.js';
|
|
3
|
+
import { Request, RequestOptions, Route, Site } from './index.js';
|
|
4
|
+
import { Entry } from '../entry/index.js';
|
|
5
|
+
import CrelteRequest from '../CrelteRequest.js';
|
|
19
6
|
|
|
20
7
|
/**
|
|
21
8
|
* Allows to easely modify a Request
|
|
@@ -29,156 +16,73 @@ const defaultRouterOpts = {
|
|
|
29
16
|
*/
|
|
30
17
|
export type UpdateRequest = (req: Request) => boolean | null | undefined | void;
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
* internal only
|
|
38
|
-
*/
|
|
39
|
-
type Internal = {
|
|
40
|
-
onLoaded: (
|
|
41
|
-
success: boolean,
|
|
42
|
-
req: Request,
|
|
43
|
-
// call ready once your ready to update the dom
|
|
44
|
-
// this makes sure we trigger a route and site update
|
|
45
|
-
// almost at the same moment and probably the same tick
|
|
46
|
-
// to make sure we don't have any flickering
|
|
47
|
-
ready: () => any,
|
|
48
|
-
) => void;
|
|
49
|
-
|
|
50
|
-
// onNothingLoaded get's called if the request did not load new Data
|
|
51
|
-
// since maybe a push or replace was called
|
|
52
|
-
onNothingLoaded: (
|
|
53
|
-
req: Request,
|
|
54
|
-
// call ready once your ready to update the dom
|
|
55
|
-
// this makes sure we trigger a route and site update
|
|
56
|
-
// almost at the same moment and probably the same tick
|
|
57
|
-
// to make sure we don't have any flickering
|
|
58
|
-
ready: () => void,
|
|
59
|
-
) => void;
|
|
60
|
-
|
|
61
|
-
onLoad: LoadFn;
|
|
62
|
-
|
|
63
|
-
domReady: (req: Request) => void;
|
|
64
|
-
|
|
65
|
-
initClient: () => void;
|
|
66
|
-
|
|
67
|
-
initServer: (url: string, acceptLang?: string) => Promise<ServerInited>;
|
|
68
|
-
};
|
|
19
|
+
// Todo this router should be stateful like globals
|
|
20
|
+
// allow to reference the correct route or request
|
|
21
|
+
export default class Router {
|
|
22
|
+
private inner: BaseRouter;
|
|
23
|
+
private _request: Request | null;
|
|
69
24
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
req: Request;
|
|
75
|
-
props: any;
|
|
76
|
-
};
|
|
25
|
+
constructor(inner: BaseRouter) {
|
|
26
|
+
this.inner = inner;
|
|
27
|
+
this._request = null;
|
|
28
|
+
}
|
|
77
29
|
|
|
78
|
-
// Make sure route and nextRoute are not the same object as _inner.route
|
|
79
|
-
export default class Router {
|
|
80
30
|
/**
|
|
81
|
-
*
|
|
31
|
+
* returns a store with the current route
|
|
82
32
|
*
|
|
83
33
|
* ## Note
|
|
84
|
-
* Will always contain a route
|
|
34
|
+
* Will always contain a route except in the first loadData call this
|
|
35
|
+
* is intentional since you will get the wrong route in a loadData call.
|
|
36
|
+
* In a loadData you should always use the `CrelteRequest` provided
|
|
37
|
+
* in each loadData call.
|
|
85
38
|
*/
|
|
86
|
-
|
|
39
|
+
get route(): Readable<Route | null> {
|
|
40
|
+
return this.inner.route.readclone();
|
|
41
|
+
}
|
|
87
42
|
|
|
88
43
|
/**
|
|
89
|
-
*
|
|
44
|
+
* returns a store with the current site
|
|
90
45
|
*
|
|
91
46
|
* ## Note
|
|
92
|
-
* Will always contain a site
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* The loading flag, specifies if a page is currently
|
|
101
|
-
* getting loaded
|
|
102
|
-
*/
|
|
103
|
-
private _loading: Writable<boolean>;
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* The loading progress, the value is between 0 and 1
|
|
47
|
+
* Will always contain a site except in the first loadData call this
|
|
48
|
+
* is intentional since you might get the wrong site if a site switch
|
|
49
|
+
* is happening and you call this in loadData. If possible use the CrelteRequest
|
|
50
|
+
* provided in each loadData call.
|
|
51
|
+
*
|
|
52
|
+
* Else use `router.site.get() ?? router.req.site`
|
|
107
53
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
private _onRequest: Listeners<[Request]>;
|
|
111
|
-
|
|
112
|
-
/** @hidden */
|
|
113
|
-
_internal: Internal;
|
|
114
|
-
|
|
115
|
-
private inner: InnerRouter;
|
|
116
|
-
private pageLoader: PageLoader<LoadedMore>;
|
|
117
|
-
|
|
118
|
-
constructor(sites: SiteFromGraphQl[], opts: RouterOptions = {}) {
|
|
119
|
-
opts = { ...defaultRouterOpts, ...opts };
|
|
120
|
-
|
|
121
|
-
this.inner = new InnerRouter(sites, {
|
|
122
|
-
preloadOnMouseOver: opts.preloadOnMouseOver!,
|
|
123
|
-
});
|
|
124
|
-
this.pageLoader = new PageLoader({
|
|
125
|
-
debugTiming: opts.debugTiming!,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// in the first onRoute call we will update this value
|
|
129
|
-
this._route = new Writable(null!);
|
|
130
|
-
this._site = new Writable(null!);
|
|
131
|
-
this._request = null;
|
|
132
|
-
this._loading = new Writable(false);
|
|
133
|
-
this._loadingProgress = new Writable(0);
|
|
134
|
-
|
|
135
|
-
this._onRequest = new Listeners();
|
|
136
|
-
|
|
137
|
-
// these functions are exposed to the init "module"
|
|
138
|
-
// but should not be used by anybody else
|
|
139
|
-
this._internal = {
|
|
140
|
-
onLoaded: () => {},
|
|
141
|
-
onNothingLoaded: () => {},
|
|
142
|
-
onLoad: () => {},
|
|
143
|
-
domReady: req => this.inner.domReady(req),
|
|
144
|
-
initClient: () => this._initClient(),
|
|
145
|
-
initServer: (url, acceptLang) => this._initServer(url, acceptLang),
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
this.inner.onRoute = (route, changeHistory) =>
|
|
149
|
-
this._onRoute(route, changeHistory);
|
|
150
|
-
this.inner.onPreload = route => this._onPreload(route);
|
|
151
|
-
|
|
152
|
-
this.pageLoader.onLoaded = (resp, req, more) =>
|
|
153
|
-
this._onLoaded(resp, req, more);
|
|
154
|
-
this.pageLoader.loadFn = (req, opts) =>
|
|
155
|
-
this._internal.onLoad(req, opts);
|
|
156
|
-
this.pageLoader.onProgress = (loading, progress) =>
|
|
157
|
-
this._onProgress(loading, progress);
|
|
54
|
+
get site(): Readable<Site | null> {
|
|
55
|
+
return this.inner.site.readonly();
|
|
158
56
|
}
|
|
159
57
|
|
|
160
58
|
/**
|
|
161
|
-
* returns a store with the current
|
|
59
|
+
* returns a store with the current entry
|
|
162
60
|
*
|
|
163
61
|
* ## Note
|
|
164
|
-
* Will always contain
|
|
165
|
-
*
|
|
166
|
-
*
|
|
62
|
+
* Will always contain an entry except in the first loadData call this
|
|
63
|
+
* is intentional since you might get the wrong entry if a request is happening
|
|
64
|
+
* and you call this in loadData. If possible use the CrelteRequest
|
|
65
|
+
* provided in each loadData call.
|
|
167
66
|
*/
|
|
168
|
-
get
|
|
169
|
-
return this.
|
|
67
|
+
get entry(): Readable<Entry | null> {
|
|
68
|
+
return this.inner.entry.readonly();
|
|
170
69
|
}
|
|
171
70
|
|
|
172
71
|
/**
|
|
173
|
-
* returns
|
|
174
|
-
*
|
|
175
|
-
* ## Note
|
|
176
|
-
* Will always contain a site expect in the first loadData call
|
|
72
|
+
* returns the latest request in progress otherwise returns null.
|
|
177
73
|
*
|
|
178
|
-
*
|
|
74
|
+
* ## Important !!
|
|
75
|
+
* If at all possible prefer using the `CrelteRequest` provided in each
|
|
76
|
+
* loadData call. For example in a preload request this will return null.
|
|
77
|
+
* Or a user has clicked multiple times on different links you might get
|
|
78
|
+
* the url of the newer request.
|
|
179
79
|
*/
|
|
180
|
-
get
|
|
181
|
-
|
|
80
|
+
get req(): Request | null {
|
|
81
|
+
// this._request is not used because that could be a weird
|
|
82
|
+
// behaviour for the user
|
|
83
|
+
// we will use that however internally
|
|
84
|
+
// todo maybe reconsider this?
|
|
85
|
+
return this.inner.request;
|
|
182
86
|
}
|
|
183
87
|
|
|
184
88
|
/**
|
|
@@ -192,14 +96,14 @@ export default class Router {
|
|
|
192
96
|
* returns a store which indicates if the a page is loading
|
|
193
97
|
*/
|
|
194
98
|
get loading(): Readable<boolean> {
|
|
195
|
-
return this.
|
|
99
|
+
return this.inner.loading.readonly();
|
|
196
100
|
}
|
|
197
101
|
|
|
198
102
|
/**
|
|
199
103
|
* returns a store which indicates the loading progress between 0 and 1
|
|
200
104
|
*/
|
|
201
105
|
get loadingProgress(): Readable<number> {
|
|
202
|
-
return this.
|
|
106
|
+
return this.inner.loadingProgress.readonly();
|
|
203
107
|
}
|
|
204
108
|
|
|
205
109
|
/**
|
|
@@ -223,23 +127,14 @@ export default class Router {
|
|
|
223
127
|
* // the following page will be opened https://example.com/de/foo/bar
|
|
224
128
|
* ```
|
|
225
129
|
*/
|
|
226
|
-
open(
|
|
130
|
+
async open(
|
|
227
131
|
target: string | URL | Route | Request | UpdateRequest,
|
|
228
132
|
opts: RequestOptions = {},
|
|
229
|
-
) {
|
|
230
|
-
const req = this.targetOrUpdateToRequest(target, opts
|
|
231
|
-
origin: 'manual',
|
|
232
|
-
});
|
|
133
|
+
): Promise<Route | void> {
|
|
134
|
+
const req = this.targetOrUpdateToRequest(target, opts);
|
|
233
135
|
if (!req) return;
|
|
234
136
|
|
|
235
|
-
|
|
236
|
-
throw new Error(
|
|
237
|
-
'Cannot open the same request object twice. Either clone the request ' +
|
|
238
|
-
'or just pass in the url.',
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
this.inner.open(req);
|
|
137
|
+
return await this.inner.open(req);
|
|
243
138
|
}
|
|
244
139
|
|
|
245
140
|
/**
|
|
@@ -275,20 +170,14 @@ export default class Router {
|
|
|
275
170
|
* router.push(route);
|
|
276
171
|
* ```
|
|
277
172
|
*/
|
|
278
|
-
push(
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
// change that in the future
|
|
284
|
-
const req = this.targetOrUpdateToRequest(route, opts, {
|
|
285
|
-
origin: 'push',
|
|
286
|
-
scrollY: opts.scrollY ?? undefined,
|
|
287
|
-
disableLoadData: opts.disableLoadData ?? true,
|
|
288
|
-
});
|
|
173
|
+
async push(
|
|
174
|
+
route: Route | Request | UpdateRequest,
|
|
175
|
+
opts: RequestOptions = {},
|
|
176
|
+
) {
|
|
177
|
+
const req = this.targetOrUpdateToRequest(route, opts);
|
|
289
178
|
if (!req) return;
|
|
290
179
|
|
|
291
|
-
this.inner.push(req);
|
|
180
|
+
return await this.inner.push(req);
|
|
292
181
|
}
|
|
293
182
|
|
|
294
183
|
/**
|
|
@@ -331,20 +220,16 @@ export default class Router {
|
|
|
331
220
|
* router.replace(route);
|
|
332
221
|
* ```
|
|
333
222
|
*/
|
|
334
|
-
replace(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
// change that in the future
|
|
340
|
-
const req = this.targetOrUpdateToRequest(route, opts, {
|
|
341
|
-
origin: 'replace',
|
|
342
|
-
scrollY: opts.scrollY ?? undefined,
|
|
343
|
-
disableLoadData: opts.disableLoadData ?? true,
|
|
344
|
-
});
|
|
223
|
+
async replace(
|
|
224
|
+
route: Route | Request | UpdateRequest,
|
|
225
|
+
opts: RequestOptions = {},
|
|
226
|
+
) {
|
|
227
|
+
const req = this.targetOrUpdateToRequest(route, opts);
|
|
345
228
|
if (!req) return;
|
|
346
229
|
|
|
347
|
-
|
|
230
|
+
// we don't force disableLoadData here
|
|
231
|
+
// because the user might want to reload the data
|
|
232
|
+
return await this.inner.replace(req);
|
|
348
233
|
}
|
|
349
234
|
|
|
350
235
|
/**
|
|
@@ -357,16 +242,20 @@ export default class Router {
|
|
|
357
242
|
|
|
358
243
|
/**
|
|
359
244
|
* Checks if there are previous routes which would allow it to go back
|
|
245
|
+
*
|
|
246
|
+
* On the server this will always return false
|
|
360
247
|
*/
|
|
361
248
|
canGoBack(): boolean {
|
|
362
|
-
return this.inner.
|
|
249
|
+
return this.inner.canGoBack();
|
|
363
250
|
}
|
|
364
251
|
|
|
365
252
|
/**
|
|
366
253
|
* Go back in the history
|
|
254
|
+
*
|
|
255
|
+
* On the server this throw an error
|
|
367
256
|
*/
|
|
368
257
|
back() {
|
|
369
|
-
this.inner.
|
|
258
|
+
this.inner.back();
|
|
370
259
|
}
|
|
371
260
|
|
|
372
261
|
/**
|
|
@@ -381,13 +270,12 @@ export default class Router {
|
|
|
381
270
|
*
|
|
382
271
|
* This will trigger every time a new route is set
|
|
383
272
|
* and is equivalent to router.route.subscribe(fn)
|
|
384
|
-
*
|
|
273
|
+
* except that it will not trigger instantly
|
|
385
274
|
*
|
|
386
275
|
* @returns a function to remove the listener
|
|
387
276
|
*/
|
|
388
277
|
onRoute(fn: (route: Route) => void): () => void {
|
|
389
|
-
|
|
390
|
-
return this.route.subscribe(r => (first ? (first = false) : fn(r!)));
|
|
278
|
+
return this.inner.onRouteListeners.add(fn);
|
|
391
279
|
}
|
|
392
280
|
|
|
393
281
|
/**
|
|
@@ -397,8 +285,8 @@ export default class Router {
|
|
|
397
285
|
*
|
|
398
286
|
* @returns a function to remove the listener
|
|
399
287
|
*/
|
|
400
|
-
onRequest(fn: (req:
|
|
401
|
-
return this.
|
|
288
|
+
onRequest(fn: (req: CrelteRequest) => void): () => void {
|
|
289
|
+
return this.inner.onRequestListeners.add(fn);
|
|
402
290
|
}
|
|
403
291
|
|
|
404
292
|
/**
|
|
@@ -415,161 +303,6 @@ export default class Router {
|
|
|
415
303
|
return this.inner.targetToRequest(target, opts);
|
|
416
304
|
}
|
|
417
305
|
|
|
418
|
-
private setNewRoute(route: Route) {
|
|
419
|
-
this._route.setSilent(route);
|
|
420
|
-
const siteChanged = this.site.get()?.id !== route.site.id;
|
|
421
|
-
this._site.setSilent(route.site);
|
|
422
|
-
this._route.notify();
|
|
423
|
-
if (siteChanged) this._site.notify();
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
private async _initClient() {
|
|
427
|
-
this.inner.initClient();
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
private async _initServer(
|
|
431
|
-
url: string,
|
|
432
|
-
acceptLang?: string,
|
|
433
|
-
): Promise<ServerInited> {
|
|
434
|
-
this.inner.initServer();
|
|
435
|
-
|
|
436
|
-
this._internal.onNothingLoaded = (_req, ready) => {
|
|
437
|
-
ready();
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
const prom: Promise<ServerInited> = new Promise(resolve => {
|
|
441
|
-
this._internal.onLoaded = (success, req, ready) => {
|
|
442
|
-
const props = ready();
|
|
443
|
-
this._internal.onLoaded = () => {};
|
|
444
|
-
|
|
445
|
-
resolve({
|
|
446
|
-
success,
|
|
447
|
-
redirect: false,
|
|
448
|
-
req,
|
|
449
|
-
props,
|
|
450
|
-
});
|
|
451
|
-
};
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
const req = this.inner.targetToRequest(url);
|
|
455
|
-
req.origin = 'init';
|
|
456
|
-
|
|
457
|
-
// let's see if the url matches any route and site
|
|
458
|
-
// if not let's redirect to the site which matches the acceptLang
|
|
459
|
-
if (!req.siteMatches()) {
|
|
460
|
-
const site = this.inner.siteByAcceptLang(acceptLang);
|
|
461
|
-
|
|
462
|
-
return {
|
|
463
|
-
success: true,
|
|
464
|
-
redirect: true,
|
|
465
|
-
req: new Request(site.url, site),
|
|
466
|
-
props: {},
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
this.inner.route = req.toRoute();
|
|
471
|
-
this.inner.onRoute(req, () => {});
|
|
472
|
-
|
|
473
|
-
const resp = await prom;
|
|
474
|
-
|
|
475
|
-
const hist = this.inner.history as ServerHistory;
|
|
476
|
-
if (hist.url || hist.req) {
|
|
477
|
-
const nReq = this.inner.targetToRequest(hist.req ?? hist.url!);
|
|
478
|
-
if (!req.eq(nReq)) {
|
|
479
|
-
return {
|
|
480
|
-
success: true,
|
|
481
|
-
redirect: true,
|
|
482
|
-
req: nReq,
|
|
483
|
-
props: {},
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
return resp;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// gets called by the InnerRouter when a new route is requested
|
|
492
|
-
private _onRoute(req: Request, changeHistory: () => void) {
|
|
493
|
-
this.destroyRequest();
|
|
494
|
-
|
|
495
|
-
this._request = req;
|
|
496
|
-
|
|
497
|
-
const barrier = req._renderBarrier;
|
|
498
|
-
if (barrier.isOpen()) {
|
|
499
|
-
throw new Error('render barrier is already open');
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
this._onRequest.trigger(req);
|
|
503
|
-
|
|
504
|
-
// route prepared
|
|
505
|
-
if (!req.disableLoadData) {
|
|
506
|
-
this.pageLoader.load(req, { changeHistory });
|
|
507
|
-
} else {
|
|
508
|
-
this.pageLoader.discard();
|
|
509
|
-
this._onNothingLoaded(req, { changeHistory });
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
private destroyRequest() {
|
|
514
|
-
if (!this._request) return;
|
|
515
|
-
|
|
516
|
-
this._request._renderBarrier.cancel();
|
|
517
|
-
this._request = null;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
private _onPreload(req: Request) {
|
|
521
|
-
this.pageLoader.preload(req);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// gets called by the pageLoader when teh loadData completes
|
|
525
|
-
private async _onLoaded(
|
|
526
|
-
resp: LoadResponse,
|
|
527
|
-
req: Request,
|
|
528
|
-
more: LoadedMore,
|
|
529
|
-
) {
|
|
530
|
-
// check if the render was cancelled
|
|
531
|
-
if (await req._renderBarrier.ready()) return;
|
|
532
|
-
|
|
533
|
-
// when the data is loaded let's update the route of the inner
|
|
534
|
-
// this will only happen if no other route has been requested
|
|
535
|
-
// in the meantime
|
|
536
|
-
more.changeHistory();
|
|
537
|
-
|
|
538
|
-
const route = req.toRoute();
|
|
539
|
-
|
|
540
|
-
// call the client or server saying we are ready for a new render
|
|
541
|
-
this._internal.onLoaded(resp.success, req, () => {
|
|
542
|
-
this.setNewRoute(route);
|
|
543
|
-
return resp.data;
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// this gets called if loadData is not called
|
|
548
|
-
private async _onNothingLoaded(req: Request, more: LoadedMore) {
|
|
549
|
-
// check if the render was cancelled
|
|
550
|
-
if (await req._renderBarrier.ready()) return;
|
|
551
|
-
|
|
552
|
-
// when the data is loaded let's update the route of the inner
|
|
553
|
-
// this is will only happen if no other route has been requested
|
|
554
|
-
// in the meantime
|
|
555
|
-
more.changeHistory();
|
|
556
|
-
|
|
557
|
-
const route = req.toRoute();
|
|
558
|
-
|
|
559
|
-
// call the client or server saying there was an update in the route
|
|
560
|
-
// but no new data was loaded so no render should happen
|
|
561
|
-
this._internal.onNothingLoaded(req, () => {
|
|
562
|
-
this.setNewRoute(route);
|
|
563
|
-
});
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// this is called by the pageLoader if we get a progress update
|
|
567
|
-
private _onProgress(loading: boolean, progress?: number): void {
|
|
568
|
-
if (this._loading.get() !== loading) this._loading.set(loading);
|
|
569
|
-
|
|
570
|
-
if (typeof progress === 'number') this._loadingProgress.set(progress);
|
|
571
|
-
}
|
|
572
|
-
|
|
573
306
|
/**
|
|
574
307
|
* Transforms a target to a request
|
|
575
308
|
*
|
|
@@ -578,32 +311,40 @@ export default class Router {
|
|
|
578
311
|
private targetOrUpdateToRequest(
|
|
579
312
|
target: string | URL | Route | Request | UpdateRequest,
|
|
580
313
|
opts: RequestOptions = {},
|
|
581
|
-
forcedOpts: RequestOptions = {},
|
|
582
314
|
): Request | null {
|
|
583
315
|
// we have an update request
|
|
584
316
|
if (typeof target === 'function') {
|
|
585
|
-
const
|
|
586
|
-
if (!
|
|
317
|
+
const source = this._request ?? this.route.get();
|
|
318
|
+
if (!source) {
|
|
319
|
+
// todo should we use the request here?
|
|
587
320
|
throw new Error(
|
|
588
321
|
'route to update missing in first loadData call. ' +
|
|
589
|
-
'Use cr.req.clone()
|
|
322
|
+
'Use `cr.router...` or `cr.req.clone()`',
|
|
590
323
|
);
|
|
591
324
|
}
|
|
592
325
|
|
|
593
326
|
// first get a req
|
|
594
|
-
const req = this.inner.targetToRequest(
|
|
327
|
+
const req = this.inner.targetToRequest(source, opts);
|
|
595
328
|
// check if the request was canceled by the update request
|
|
596
329
|
if (target(req) === false) return null;
|
|
597
330
|
|
|
598
|
-
// now we add the forcedOpts
|
|
599
|
-
req._updateOpts(forcedOpts);
|
|
600
|
-
|
|
601
331
|
return req;
|
|
602
332
|
}
|
|
603
333
|
|
|
604
|
-
return this.inner.targetToRequest(target,
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
334
|
+
return this.inner.targetToRequest(target, opts);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* @hidden
|
|
339
|
+
* call this after creating a CrelteRequest
|
|
340
|
+
*/
|
|
341
|
+
_toRequest(req: Request) {
|
|
342
|
+
const nRouter = new Router(this.inner);
|
|
343
|
+
nRouter._request = req;
|
|
344
|
+
return nRouter;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
_requestCompleted() {
|
|
348
|
+
this._request = null;
|
|
608
349
|
}
|
|
609
350
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import BaseRouter, { BaseRouterOptions } from './BaseRouter.js';
|
|
2
|
+
import { Request, RequestOptions } from './index.js';
|
|
3
|
+
import Route from './Route.js';
|
|
4
|
+
import Site, { SiteFromGraphQl } from './Site.js';
|
|
5
|
+
|
|
6
|
+
export default class ServerRouter extends BaseRouter {
|
|
7
|
+
acceptLang: string | null;
|
|
8
|
+
redirect: Request | null;
|
|
9
|
+
|
|
10
|
+
constructor(sites: SiteFromGraphQl[], opts: BaseRouterOptions) {
|
|
11
|
+
super(sites, opts);
|
|
12
|
+
|
|
13
|
+
this.acceptLang = null;
|
|
14
|
+
this.redirect = null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
defaultSite(): Site {
|
|
18
|
+
return this.siteByAcceptLang(this.acceptLang);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async openRequest(req: Request) {
|
|
22
|
+
// only handle the first redirect
|
|
23
|
+
// this makes the behaviour the same as client router
|
|
24
|
+
// not true
|
|
25
|
+
// todo: the client only instatly redirects if it belongs to another
|
|
26
|
+
// site (aka needs to use window.location.href)
|
|
27
|
+
if (this.redirect) return;
|
|
28
|
+
|
|
29
|
+
this.redirect = req;
|
|
30
|
+
this.cancelRequest();
|
|
31
|
+
|
|
32
|
+
// request was handled with a redirect so we don't have an entry
|
|
33
|
+
// templateData or anything else
|
|
34
|
+
// todo is that what we wan't to return. Because void would tell
|
|
35
|
+
// the user the request was cancelled
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async pushRequest(req: Request, _opts: RequestOptions = {}) {
|
|
39
|
+
// todo not sure if that is what we want?
|
|
40
|
+
return await this.openRequest(req);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async replaceRequest(req: Request, _opts: RequestOptions = {}) {
|
|
44
|
+
// todo not sure if that is what we want?
|
|
45
|
+
return await this.openRequest(req);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* This function always returns the request or a redirect one
|
|
50
|
+
*
|
|
51
|
+
* And then if no redirect happen the final route
|
|
52
|
+
*
|
|
53
|
+
* ## Throws
|
|
54
|
+
* If the request fails
|
|
55
|
+
*/
|
|
56
|
+
async init(
|
|
57
|
+
url: string,
|
|
58
|
+
acceptLang?: string,
|
|
59
|
+
): Promise<[Request, Route | null]> {
|
|
60
|
+
this.acceptLang = acceptLang ?? null;
|
|
61
|
+
|
|
62
|
+
const req = this.targetToRequest(url);
|
|
63
|
+
req.origin = 'init';
|
|
64
|
+
|
|
65
|
+
// throws if something goes wrong
|
|
66
|
+
const route = await this.handleRequest(req, () => {});
|
|
67
|
+
if (!route) {
|
|
68
|
+
if (!this.redirect)
|
|
69
|
+
throw new Error(
|
|
70
|
+
'if the request gets cancelled on the server there should be a redirect',
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return [this.redirect!, null];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return [req, route];
|
|
77
|
+
}
|
|
78
|
+
}
|