crelte 0.3.1 → 0.4.0
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.map +1 -1
- package/dist/CrelteRequest.d.ts.map +1 -1
- package/dist/blocks/Blocks.d.ts.map +1 -1
- package/dist/blocks/Blocks.svelte.d.ts.map +1 -1
- package/dist/blocks/index.d.ts.map +1 -1
- package/dist/cookies/ClientCookies.d.ts.map +1 -1
- package/dist/cookies/ServerCookies.d.ts.map +1 -1
- package/dist/cookies/index.d.ts.map +1 -1
- package/dist/cookies/internal.d.ts.map +1 -1
- package/dist/cookies/utils.d.ts.map +1 -1
- package/dist/entry/EntryRouter.d.ts +30 -0
- package/dist/entry/EntryRouter.d.ts.map +1 -0
- package/dist/entry/EntryRouter.js +45 -0
- package/dist/entry/index.d.ts +32 -0
- package/dist/entry/index.d.ts.map +1 -0
- package/dist/entry/index.js +31 -0
- package/dist/graphql/GraphQl.d.ts.map +1 -1
- package/dist/graphql/gql.test.d.ts.map +1 -1
- package/dist/graphql/index.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/init/client.d.ts +1 -1
- package/dist/init/client.d.ts.map +1 -1
- package/dist/init/client.js +4 -3
- package/dist/init/server.d.ts +3 -3
- package/dist/init/server.d.ts.map +1 -1
- package/dist/init/server.js +6 -46
- package/dist/init/shared.d.ts +3 -1
- package/dist/init/shared.d.ts.map +1 -1
- package/dist/init/shared.js +47 -26
- package/dist/loadData/Globals.d.ts.map +1 -1
- package/dist/loadData/index.d.ts.map +1 -1
- package/dist/plugins/Events.d.ts.map +1 -1
- package/dist/plugins/Plugins.d.ts.map +1 -1
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/routing/History.d.ts.map +1 -1
- package/dist/routing/InnerRouter.d.ts.map +1 -1
- package/dist/routing/PageLoader.d.ts.map +1 -1
- package/dist/routing/Request.d.ts.map +1 -1
- package/dist/routing/Route.d.ts +11 -0
- package/dist/routing/Route.d.ts.map +1 -1
- package/dist/routing/Route.js +13 -0
- package/dist/routing/Router.d.ts +47 -10
- package/dist/routing/Router.d.ts.map +1 -1
- package/dist/routing/Router.js +74 -17
- package/dist/routing/Site.d.ts.map +1 -1
- package/dist/routing/index.d.ts +2 -2
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/ssr/SsrCache.d.ts.map +1 -1
- package/dist/ssr/SsrComponents.d.ts.map +1 -1
- package/dist/ssr/index.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/package.json +9 -4
- package/src/entry/EntryRouter.ts +71 -0
- package/src/entry/index.ts +48 -0
- package/src/index.ts +2 -0
- package/src/init/client.ts +10 -3
- package/src/init/server.ts +15 -59
- package/src/init/shared.ts +78 -28
- package/src/routing/Route.ts +14 -0
- package/src/routing/Router.ts +102 -20
- package/src/routing/index.ts +2 -1
package/src/init/client.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { CrelteBuilder } from '../Crelte.js';
|
|
|
2
2
|
import CrelteRequest from '../CrelteRequest.js';
|
|
3
3
|
import { GraphQlQuery } from '../graphql/GraphQl.js';
|
|
4
4
|
import { SiteFromGraphQl } from '../routing/Site.js';
|
|
5
|
-
import {
|
|
5
|
+
import { pluginsBeforeRender, prepareLoadFn, setupPlugins } from './shared.js';
|
|
6
6
|
import { tick } from 'svelte';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -49,7 +49,7 @@ const mainDataDefault = {
|
|
|
49
49
|
* });
|
|
50
50
|
* ```
|
|
51
51
|
*/
|
|
52
|
-
export function main(data: MainData) {
|
|
52
|
+
export async function main(data: MainData) {
|
|
53
53
|
data = { ...mainDataDefault, ...data };
|
|
54
54
|
|
|
55
55
|
// rendering steps
|
|
@@ -97,11 +97,18 @@ export function main(data: MainData) {
|
|
|
97
97
|
// setup plugins
|
|
98
98
|
setupPlugins(crelte, data.app.plugins ?? []);
|
|
99
99
|
|
|
100
|
+
const loadFn = await prepareLoadFn(
|
|
101
|
+
crelte,
|
|
102
|
+
data.app,
|
|
103
|
+
data.entryQuery,
|
|
104
|
+
data.globalQuery,
|
|
105
|
+
);
|
|
106
|
+
|
|
100
107
|
// setup load Data
|
|
101
108
|
|
|
102
109
|
crelte.router._internal.onLoad = (req, opts) => {
|
|
103
110
|
const cr = new CrelteRequest(crelte, req);
|
|
104
|
-
return loadFn(cr,
|
|
111
|
+
return loadFn(cr, opts);
|
|
105
112
|
};
|
|
106
113
|
|
|
107
114
|
// render Space
|
package/src/init/server.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CrelteBuilder } from '../Crelte.js';
|
|
2
2
|
import { SiteFromGraphQl } from '../routing/Site.js';
|
|
3
|
-
import {
|
|
3
|
+
import { pluginsBeforeRender, prepareLoadFn, setupPlugins } from './shared.js';
|
|
4
4
|
import SsrComponents from '../ssr/SsrComponents.js';
|
|
5
5
|
import SsrCache from '../ssr/SsrCache.js';
|
|
6
6
|
import ServerCookies from '../cookies/ServerCookies.js';
|
|
7
7
|
import CrelteRequest from '../CrelteRequest.js';
|
|
8
|
-
import {
|
|
8
|
+
import { GraphQlQuery } from '../graphql/GraphQl.js';
|
|
9
9
|
|
|
10
10
|
export type ServerData = {
|
|
11
11
|
url: string;
|
|
@@ -15,9 +15,8 @@ export type ServerData = {
|
|
|
15
15
|
endpoint: string;
|
|
16
16
|
craftWeb: string;
|
|
17
17
|
viteEnv: Map<string, string>;
|
|
18
|
-
cookies
|
|
19
|
-
|
|
20
|
-
writeSitesCache?: (data: any) => Promise<void>;
|
|
18
|
+
cookies: string;
|
|
19
|
+
sites: SiteFromGraphQl[];
|
|
21
20
|
};
|
|
22
21
|
|
|
23
22
|
/**
|
|
@@ -76,20 +75,26 @@ export async function main(data: MainData): Promise<{
|
|
|
76
75
|
const cookies = data.serverData.cookies ?? '';
|
|
77
76
|
builder.setupCookies(cookies);
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
builder.
|
|
81
|
-
builder.setupRouter(csites);
|
|
78
|
+
builder.ssrCache.set('crelteSites', data.serverData.sites);
|
|
79
|
+
builder.setupRouter(data.serverData.sites);
|
|
82
80
|
|
|
83
81
|
const crelte = builder.build();
|
|
84
82
|
|
|
85
83
|
// setup plugins
|
|
86
84
|
setupPlugins(crelte, data.app.plugins ?? []);
|
|
87
85
|
|
|
86
|
+
const loadFn = await prepareLoadFn(
|
|
87
|
+
crelte,
|
|
88
|
+
data.app,
|
|
89
|
+
data.entryQuery,
|
|
90
|
+
data.globalQuery,
|
|
91
|
+
);
|
|
92
|
+
|
|
88
93
|
// setup load Data
|
|
89
94
|
|
|
90
95
|
crelte.router._internal.onLoad = req => {
|
|
91
96
|
const cr = new CrelteRequest(crelte, req);
|
|
92
|
-
return loadFn(cr
|
|
97
|
+
return loadFn(cr);
|
|
93
98
|
};
|
|
94
99
|
|
|
95
100
|
const { success, redirect, req, props } =
|
|
@@ -187,7 +192,7 @@ export async function mainError(
|
|
|
187
192
|
htmlTemplate = htmlTemplate.replace('<!--page-lang-->', 'de');
|
|
188
193
|
|
|
189
194
|
const finalHtml = htmlTemplate
|
|
190
|
-
.replace('
|
|
195
|
+
.replace('</head>', head + '\n\t</head>')
|
|
191
196
|
.replace('<!--ssr-body-->', html);
|
|
192
197
|
|
|
193
198
|
return {
|
|
@@ -195,52 +200,3 @@ export async function mainError(
|
|
|
195
200
|
html: finalHtml,
|
|
196
201
|
};
|
|
197
202
|
}
|
|
198
|
-
|
|
199
|
-
// requires, GraphQl, SsrCache
|
|
200
|
-
async function loadSites(
|
|
201
|
-
builder: CrelteBuilder,
|
|
202
|
-
serverData: ServerData,
|
|
203
|
-
): Promise<SiteFromGraphQl[]> {
|
|
204
|
-
if (!builder.graphQl) throw new Error();
|
|
205
|
-
|
|
206
|
-
if ('CRAFT_SITES_CACHED' in globalThis) {
|
|
207
|
-
return (globalThis as any)['CRAFT_SITES_CACHED'];
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if (import.meta.env.PROD && serverData.readSitesCache) {
|
|
211
|
-
try {
|
|
212
|
-
const sites =
|
|
213
|
-
(await serverData.readSitesCache()) as SiteFromGraphQl[];
|
|
214
|
-
// @ts-ignore
|
|
215
|
-
globalThis['CRAFT_SITES_CACHED'] = sites;
|
|
216
|
-
return sites;
|
|
217
|
-
} catch (_e: any) {
|
|
218
|
-
// ignore
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const resp = (await builder.graphQl.query(
|
|
223
|
-
gql`
|
|
224
|
-
query {
|
|
225
|
-
crelteSites {
|
|
226
|
-
id
|
|
227
|
-
baseUrl
|
|
228
|
-
language
|
|
229
|
-
name
|
|
230
|
-
handle
|
|
231
|
-
primary
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
`,
|
|
235
|
-
{},
|
|
236
|
-
// don't cache since we cache ourself
|
|
237
|
-
{ caching: false },
|
|
238
|
-
)) as { crelteSites: SiteFromGraphQl[] };
|
|
239
|
-
|
|
240
|
-
// @ts-ignore
|
|
241
|
-
globalThis['CRAFT_SITES_CACHED'] = resp.crelteSites;
|
|
242
|
-
if (import.meta.env.PROD && serverData.writeSitesCache) {
|
|
243
|
-
await serverData.writeSitesCache(resp.crelteSites);
|
|
244
|
-
}
|
|
245
|
-
return resp.crelteSites;
|
|
246
|
-
}
|
package/src/init/shared.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Crelte from '../Crelte.js';
|
|
2
2
|
import CrelteRequest from '../CrelteRequest.js';
|
|
3
|
+
import EntryRouter, { EntryRoutes } from '../entry/EntryRouter.js';
|
|
3
4
|
import { GraphQlQuery } from '../graphql/GraphQl.js';
|
|
4
5
|
import { LoadData, callLoadData } from '../loadData/index.js';
|
|
5
6
|
import { PluginCreator } from '../plugins/Plugins.js';
|
|
@@ -12,6 +13,8 @@ interface App<E, T> {
|
|
|
12
13
|
loadEntryData?: LoadData<any>;
|
|
13
14
|
|
|
14
15
|
templates?: Record<string, LazyTemplateModule<E, T>>;
|
|
16
|
+
|
|
17
|
+
entryRoutes?: EntryRoutes;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
interface TemplateModule<E, T> {
|
|
@@ -58,14 +61,43 @@ export function getEntry(page: any): any {
|
|
|
58
61
|
};
|
|
59
62
|
}
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
// todo it would be nice to call this only once per server start
|
|
65
|
+
export async function prepareLoadFn<E, T>(
|
|
66
|
+
crelte: Crelte,
|
|
67
|
+
app: App<E, T>,
|
|
68
|
+
entryQuery: GraphQlQuery,
|
|
69
|
+
globalQuery?: GraphQlQuery,
|
|
70
|
+
): Promise<(cr: CrelteRequest, loadOpts?: LoadOptions) => Promise<any>> {
|
|
71
|
+
const templateModules = prepareTemplates(app.templates ?? {});
|
|
72
|
+
let entryRouter: EntryRouter | null = null;
|
|
73
|
+
if (app.entryRoutes) {
|
|
74
|
+
entryRouter = new EntryRouter(crelte);
|
|
75
|
+
await app.entryRoutes(entryRouter);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return async (cr, loadOpts) => {
|
|
79
|
+
return await loadFn(
|
|
80
|
+
cr,
|
|
81
|
+
app,
|
|
82
|
+
templateModules,
|
|
83
|
+
entryRouter,
|
|
84
|
+
entryQuery,
|
|
85
|
+
globalQuery,
|
|
86
|
+
loadOpts,
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function loadFn<E, T>(
|
|
62
92
|
cr: CrelteRequest,
|
|
63
93
|
app: App<E, T>,
|
|
94
|
+
templateModules: Map<string, LazyTemplateModule<E, T>>,
|
|
95
|
+
entryRouter: EntryRouter | null,
|
|
64
96
|
entryQuery: GraphQlQuery,
|
|
65
97
|
globalQuery?: GraphQlQuery,
|
|
66
98
|
loadOpts?: LoadOptions,
|
|
67
99
|
): Promise<any> {
|
|
68
|
-
let dataProm: Promise<
|
|
100
|
+
let dataProm: Promise<any> | null = null;
|
|
69
101
|
// @ts-ignore
|
|
70
102
|
if (app.loadData) {
|
|
71
103
|
throw new Error(
|
|
@@ -93,43 +125,29 @@ export async function loadFn<D, E, T>(
|
|
|
93
125
|
})();
|
|
94
126
|
}
|
|
95
127
|
|
|
96
|
-
|
|
97
|
-
if (cr.req.siteMatches()) {
|
|
98
|
-
let uri = decodeURI(cr.req.uri);
|
|
99
|
-
if (uri.startsWith('/')) uri = uri.substring(1);
|
|
100
|
-
if (uri === '' || uri === '/') uri = '__home__';
|
|
101
|
-
|
|
102
|
-
pageProm = cr.query(entryQuery, {
|
|
103
|
-
uri,
|
|
104
|
-
siteId: cr.site.id,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
128
|
+
const entryProm = queryEntry(cr, app, entryRouter, entryQuery);
|
|
107
129
|
|
|
108
130
|
const pluginsLoadGlobalData = cr.events.trigger('loadGlobalData', cr);
|
|
109
131
|
|
|
110
132
|
// loading progress is at 20%
|
|
111
133
|
loadOpts?.setProgress(0.2);
|
|
112
134
|
|
|
113
|
-
const [data, global,
|
|
135
|
+
const [data, global, entry] = await Promise.all([
|
|
114
136
|
dataProm,
|
|
115
137
|
globalProm,
|
|
116
|
-
|
|
138
|
+
entryProm,
|
|
117
139
|
...pluginsLoadGlobalData,
|
|
118
140
|
]);
|
|
119
141
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
// so any waiters get's triggered
|
|
125
|
-
cr.globals._setData(cr.site.id, {});
|
|
142
|
+
// global is only set if !wasLoaded but we need to store something
|
|
143
|
+
// even if no globalQuery exists
|
|
144
|
+
if (global || !cr.globals._wasLoaded(cr.site.id)) {
|
|
145
|
+
cr.globals._setData(cr.site.id, global ?? {});
|
|
126
146
|
}
|
|
127
147
|
|
|
128
|
-
const entry = getEntry(page);
|
|
129
|
-
|
|
130
148
|
let template;
|
|
131
149
|
if (app.templates) {
|
|
132
|
-
template = await loadTemplate(
|
|
150
|
+
template = await loadTemplate(templateModules, entry);
|
|
133
151
|
} else {
|
|
134
152
|
throw new Error('App must have templates or loadTemplate method');
|
|
135
153
|
}
|
|
@@ -180,12 +198,39 @@ function parseFilename(path: string): [string, string] {
|
|
|
180
198
|
return [name, ext];
|
|
181
199
|
}
|
|
182
200
|
|
|
183
|
-
async function
|
|
201
|
+
async function queryEntry<E, T>(
|
|
202
|
+
cr: CrelteRequest,
|
|
203
|
+
app: App<E, T>,
|
|
204
|
+
entryRouter: EntryRouter | null,
|
|
205
|
+
entryQuery: GraphQlQuery,
|
|
206
|
+
): Promise<any | null> {
|
|
207
|
+
// check
|
|
208
|
+
if (entryRouter) {
|
|
209
|
+
const entry = await entryRouter._handle(cr);
|
|
210
|
+
if (entry) return entry;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (cr.req.siteMatches()) {
|
|
214
|
+
let uri = decodeURI(cr.req.uri);
|
|
215
|
+
if (uri.startsWith('/')) uri = uri.substring(1);
|
|
216
|
+
if (uri === '' || uri === '/') uri = '__home__';
|
|
217
|
+
|
|
218
|
+
const page = await cr.query(entryQuery, {
|
|
219
|
+
uri,
|
|
220
|
+
siteId: cr.site.id,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return getEntry(page);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function prepareTemplates<E, T>(
|
|
184
230
|
rawModules: Record<string, LazyTemplateModule<E, T>>,
|
|
185
|
-
|
|
186
|
-
): Promise<TemplateModule<E, T>> {
|
|
231
|
+
): Map<string, LazyTemplateModule<E, T>> {
|
|
187
232
|
// parse modules
|
|
188
|
-
|
|
233
|
+
return new Map(
|
|
189
234
|
Object.entries(rawModules)
|
|
190
235
|
.map(([path, mod]) => {
|
|
191
236
|
const [name, _ext] = parseFilename(path);
|
|
@@ -193,7 +238,12 @@ async function loadTemplate<E, T>(
|
|
|
193
238
|
})
|
|
194
239
|
.filter(([name, _mod]) => !!name),
|
|
195
240
|
);
|
|
241
|
+
}
|
|
196
242
|
|
|
243
|
+
async function loadTemplate<E, T>(
|
|
244
|
+
modules: Map<string, LazyTemplateModule<E, T>>,
|
|
245
|
+
entry: E,
|
|
246
|
+
): Promise<TemplateModule<E, T>> {
|
|
197
247
|
const entr = entry as any;
|
|
198
248
|
const handle = `${entr.sectionHandle}-${entr.typeHandle}`;
|
|
199
249
|
|
package/src/routing/Route.ts
CHANGED
|
@@ -187,6 +187,20 @@ export default class Route {
|
|
|
187
187
|
return this.url.hash;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Set the hash of the route
|
|
192
|
+
*
|
|
193
|
+
* ## Example
|
|
194
|
+
* ```
|
|
195
|
+
* const route = new Route('https://example.com/foo/bar/', null);
|
|
196
|
+
* route.hash = '#hash';
|
|
197
|
+
* console.log(route.url.href); // 'https://example.com/foo/bar/#hash'
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
set hash(hash: string) {
|
|
201
|
+
this.url.hash = hash;
|
|
202
|
+
}
|
|
203
|
+
|
|
190
204
|
/**
|
|
191
205
|
* Checks if there are previous routes which would allow it to go back
|
|
192
206
|
*/
|
package/src/routing/Router.ts
CHANGED
|
@@ -17,6 +17,18 @@ const defaultRouterOpts = {
|
|
|
17
17
|
debugTiming: false,
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Allows to easely modify a Request
|
|
22
|
+
*
|
|
23
|
+
* If you return `false` the request will be aborted
|
|
24
|
+
*
|
|
25
|
+
* ## Example
|
|
26
|
+
* ```
|
|
27
|
+
* router.replace(req => (req.hash = ''));
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export type UpdateRequest = (req: Request) => boolean | null | undefined | void;
|
|
31
|
+
|
|
20
32
|
type LoadedMore = {
|
|
21
33
|
changeHistory: () => void;
|
|
22
34
|
};
|
|
@@ -122,6 +134,8 @@ export default class Router {
|
|
|
122
134
|
|
|
123
135
|
this._onRequest = new Listeners();
|
|
124
136
|
|
|
137
|
+
// these functions are exposed to the init "module"
|
|
138
|
+
// but should not be used by anybody else
|
|
125
139
|
this._internal = {
|
|
126
140
|
onLoaded: () => {},
|
|
127
141
|
onNothingLoaded: () => {},
|
|
@@ -209,11 +223,15 @@ export default class Router {
|
|
|
209
223
|
* // the following page will be opened https://example.com/de/foo/bar
|
|
210
224
|
* ```
|
|
211
225
|
*/
|
|
212
|
-
open(
|
|
213
|
-
|
|
214
|
-
|
|
226
|
+
open(
|
|
227
|
+
target: string | URL | Route | Request | UpdateRequest,
|
|
228
|
+
opts: RequestOptions = {},
|
|
229
|
+
) {
|
|
230
|
+
const req = this.targetOrUpdateToRequest(target, opts, {
|
|
215
231
|
origin: 'manual',
|
|
216
232
|
});
|
|
233
|
+
if (!req) return;
|
|
234
|
+
|
|
217
235
|
this.inner.open(req);
|
|
218
236
|
}
|
|
219
237
|
|
|
@@ -228,7 +246,17 @@ export default class Router {
|
|
|
228
246
|
* And will clear the scrollY value if you not provide a new one via the `opts`
|
|
229
247
|
* This will disableLoadData by default if you not provide an override via the `opts`
|
|
230
248
|
*
|
|
231
|
-
* ## Example
|
|
249
|
+
* ## Example using the update function
|
|
250
|
+
* ```
|
|
251
|
+
* import { getRouter } from 'crelte';
|
|
252
|
+
*
|
|
253
|
+
* const router = getRouter();
|
|
254
|
+
*
|
|
255
|
+
* const page = 1;
|
|
256
|
+
* router.push(req => req.setSearchParam('page', page || null));
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* ## Example using the route object
|
|
232
260
|
* ```
|
|
233
261
|
* import { getRouter } from 'crelte';
|
|
234
262
|
*
|
|
@@ -240,15 +268,16 @@ export default class Router {
|
|
|
240
268
|
* router.push(route);
|
|
241
269
|
* ```
|
|
242
270
|
*/
|
|
243
|
-
push(route: Route | Request, opts: RequestOptions = {}) {
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
const req = this.
|
|
247
|
-
...opts,
|
|
271
|
+
push(route: Route | Request | UpdateRequest, opts: RequestOptions = {}) {
|
|
272
|
+
// theoretically string and URL also work but we might
|
|
273
|
+
// change that in the future
|
|
274
|
+
const req = this.targetOrUpdateToRequest(route, opts, {
|
|
248
275
|
origin: 'push',
|
|
249
276
|
scrollY: opts.scrollY ?? undefined,
|
|
250
277
|
disableLoadData: opts.disableLoadData ?? true,
|
|
251
278
|
});
|
|
279
|
+
if (!req) return;
|
|
280
|
+
|
|
252
281
|
this.inner.push(req);
|
|
253
282
|
}
|
|
254
283
|
|
|
@@ -261,16 +290,26 @@ export default class Router {
|
|
|
261
290
|
}
|
|
262
291
|
|
|
263
292
|
/**
|
|
264
|
-
* This replaces the state of the route without triggering
|
|
293
|
+
* This replaces the state of the route without triggering a new pageload
|
|
265
294
|
*
|
|
266
295
|
* You can use this when using some filters for example a search filter
|
|
267
296
|
*
|
|
268
297
|
* ## Note
|
|
269
298
|
* This will always set the origin to 'replace'
|
|
270
|
-
* And will clear the scrollY value if you
|
|
271
|
-
* This will disableLoadData by default if you
|
|
299
|
+
* And will clear the scrollY value if you don't provide a new one via the `opts`
|
|
300
|
+
* This will disableLoadData by default if you don't provide an override via the `opts`
|
|
272
301
|
*
|
|
273
|
-
* ## Example
|
|
302
|
+
* ## Example using the update function
|
|
303
|
+
* ```
|
|
304
|
+
* import { getRouter } from 'crelte';
|
|
305
|
+
*
|
|
306
|
+
* const router = getRouter();
|
|
307
|
+
*
|
|
308
|
+
* const search = 'foo';
|
|
309
|
+
* router.replace(req => req.setSearchParam('search', search));
|
|
310
|
+
* ```
|
|
311
|
+
*
|
|
312
|
+
* ## Example using the route object
|
|
274
313
|
* ```
|
|
275
314
|
* import { getRouter } from 'crelte';
|
|
276
315
|
*
|
|
@@ -278,18 +317,20 @@ export default class Router {
|
|
|
278
317
|
*
|
|
279
318
|
* const search = 'foo';
|
|
280
319
|
* const route = router.route.get();
|
|
281
|
-
* route.setSearchParam('search', search
|
|
282
|
-
* router.
|
|
320
|
+
* route.setSearchParam('search', search);
|
|
321
|
+
* router.replace(route);
|
|
283
322
|
* ```
|
|
284
323
|
*/
|
|
285
|
-
replace(route: Route | Request, opts: RequestOptions = {}) {
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
const req = this.
|
|
324
|
+
replace(route: Route | Request | UpdateRequest, opts: RequestOptions = {}) {
|
|
325
|
+
// theoretically string and URL also work but we might
|
|
326
|
+
// change that in the future
|
|
327
|
+
const req = this.targetOrUpdateToRequest(route, opts, {
|
|
289
328
|
origin: 'replace',
|
|
290
329
|
scrollY: opts.scrollY ?? undefined,
|
|
291
330
|
disableLoadData: opts.disableLoadData ?? true,
|
|
292
331
|
});
|
|
332
|
+
if (!req) return;
|
|
333
|
+
|
|
293
334
|
this.inner.replace(req);
|
|
294
335
|
}
|
|
295
336
|
|
|
@@ -434,6 +475,7 @@ export default class Router {
|
|
|
434
475
|
return resp;
|
|
435
476
|
}
|
|
436
477
|
|
|
478
|
+
// gets called by the InnerRouter when a new route is requested
|
|
437
479
|
private _onRoute(req: Request, changeHistory: () => void) {
|
|
438
480
|
this.destroyRequest();
|
|
439
481
|
|
|
@@ -450,6 +492,7 @@ export default class Router {
|
|
|
450
492
|
if (!req.disableLoadData) {
|
|
451
493
|
this.pageLoader.load(req, { changeHistory });
|
|
452
494
|
} else {
|
|
495
|
+
this.pageLoader.discard();
|
|
453
496
|
this._onNothingLoaded(req, { changeHistory });
|
|
454
497
|
}
|
|
455
498
|
}
|
|
@@ -465,6 +508,7 @@ export default class Router {
|
|
|
465
508
|
this.pageLoader.preload(req);
|
|
466
509
|
}
|
|
467
510
|
|
|
511
|
+
// gets called by the pageLoader when teh loadData completes
|
|
468
512
|
private async _onLoaded(
|
|
469
513
|
resp: LoadResponse,
|
|
470
514
|
req: Request,
|
|
@@ -474,7 +518,7 @@ export default class Router {
|
|
|
474
518
|
if (await req._renderBarrier.ready()) return;
|
|
475
519
|
|
|
476
520
|
// when the data is loaded let's update the route of the inner
|
|
477
|
-
// this
|
|
521
|
+
// this will only happen if no other route has been requested
|
|
478
522
|
// in the meantime
|
|
479
523
|
more.changeHistory();
|
|
480
524
|
|
|
@@ -487,6 +531,7 @@ export default class Router {
|
|
|
487
531
|
});
|
|
488
532
|
}
|
|
489
533
|
|
|
534
|
+
// this gets called if loadData is not called
|
|
490
535
|
private async _onNothingLoaded(req: Request, more: LoadedMore) {
|
|
491
536
|
// check if the render was cancelled
|
|
492
537
|
if (await req._renderBarrier.ready()) return;
|
|
@@ -505,9 +550,46 @@ export default class Router {
|
|
|
505
550
|
});
|
|
506
551
|
}
|
|
507
552
|
|
|
553
|
+
// this is called by the pageLoader if we get a progress update
|
|
508
554
|
private _onProgress(loading: boolean, progress?: number): void {
|
|
509
555
|
if (this._loading.get() !== loading) this._loading.set(loading);
|
|
510
556
|
|
|
511
557
|
if (typeof progress === 'number') this._loadingProgress.set(progress);
|
|
512
558
|
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Transforms a target to a request
|
|
562
|
+
*
|
|
563
|
+
* returns null if the request was canceled by the update request
|
|
564
|
+
*/
|
|
565
|
+
private targetOrUpdateToRequest(
|
|
566
|
+
target: string | URL | Route | Request | UpdateRequest,
|
|
567
|
+
opts: RequestOptions = {},
|
|
568
|
+
forcedOpts: RequestOptions = {},
|
|
569
|
+
): Request | null {
|
|
570
|
+
// we have an update request
|
|
571
|
+
if (typeof target === 'function') {
|
|
572
|
+
const route = this.route.get();
|
|
573
|
+
if (!route) {
|
|
574
|
+
throw new Error(
|
|
575
|
+
'route to update missing in first loadData call',
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// first get a req
|
|
580
|
+
const req = this.inner.targetToRequest(route, opts);
|
|
581
|
+
// check if the request was canceled by the update request
|
|
582
|
+
if (target(req) === false) return null;
|
|
583
|
+
|
|
584
|
+
// now we add the forcedOpts
|
|
585
|
+
req._updateOpts(forcedOpts);
|
|
586
|
+
|
|
587
|
+
return req;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return this.inner.targetToRequest(target, {
|
|
591
|
+
...opts,
|
|
592
|
+
...forcedOpts,
|
|
593
|
+
});
|
|
594
|
+
}
|
|
513
595
|
}
|
package/src/routing/index.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import Router from './Router.js';
|
|
1
|
+
import Router, { type UpdateRequest } from './Router.js';
|
|
2
2
|
import Route, { type RouteOptions } from './Route.js';
|
|
3
3
|
import Request, { type RequestOptions, type DelayRender } from './Request.js';
|
|
4
4
|
import Site from './Site.js';
|
|
5
5
|
|
|
6
6
|
export {
|
|
7
7
|
Router,
|
|
8
|
+
UpdateRequest,
|
|
8
9
|
Route,
|
|
9
10
|
RouteOptions,
|
|
10
11
|
Site,
|