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/init/shared.ts
CHANGED
|
@@ -1,34 +1,13 @@
|
|
|
1
1
|
import Crelte from '../Crelte.js';
|
|
2
2
|
import CrelteRequest from '../CrelteRequest.js';
|
|
3
|
-
import
|
|
4
|
-
import { EntryQueryVars } from '../entry/index.js';
|
|
5
|
-
import { GraphQlQuery } from '../graphql/GraphQl.js';
|
|
3
|
+
import { GraphQlQuery, isGraphQlQuery } from '../graphql/GraphQl.js';
|
|
6
4
|
import { Entry } from '../index.js';
|
|
7
|
-
import {
|
|
5
|
+
import { callLoadData } from '../loadData/index.js';
|
|
8
6
|
import { PluginCreator } from '../plugins/Plugins.js';
|
|
9
|
-
import { LoadOptions } from '../routing/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// todo: add a generic
|
|
15
|
-
loadEntryData?: LoadData<Entry>;
|
|
16
|
-
|
|
17
|
-
templates?: Record<string, LazyTemplateModule>;
|
|
18
|
-
|
|
19
|
-
entryRoutes?: EntryRoutes;
|
|
20
|
-
|
|
21
|
-
init?: (crelte: Crelte) => void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface TemplateModule {
|
|
25
|
-
// svelte component
|
|
26
|
-
default: any;
|
|
27
|
-
|
|
28
|
-
loadData?: LoadData<Entry>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
type LazyTemplateModule = (() => Promise<TemplateModule>) | TemplateModule;
|
|
7
|
+
import { LoadOptions } from '../routing/LoadRunner.js';
|
|
8
|
+
import { isPromise } from '../utils.js';
|
|
9
|
+
import InternalApp, { TemplateModule } from './InternalApp.js';
|
|
10
|
+
import Route from '../routing/Route.js';
|
|
32
11
|
|
|
33
12
|
export function setupPlugins(crelte: Crelte, plugins: PluginCreator[]) {
|
|
34
13
|
for (const plugin of plugins) {
|
|
@@ -37,124 +16,94 @@ export function setupPlugins(crelte: Crelte, plugins: PluginCreator[]) {
|
|
|
37
16
|
}
|
|
38
17
|
}
|
|
39
18
|
|
|
40
|
-
export function
|
|
41
|
-
cr.events.trigger('
|
|
19
|
+
export function pluginsBeforeRequest(cr: CrelteRequest): Promise<void> | void {
|
|
20
|
+
const res = cr.events.trigger('beforeRequest', cr);
|
|
21
|
+
// if one of them is a promise we need to wait for it
|
|
22
|
+
if (res.some(isPromise)) {
|
|
23
|
+
return Promise.all(res).then();
|
|
24
|
+
}
|
|
42
25
|
}
|
|
43
26
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
typeHandle: '404',
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Get the entry from the page
|
|
51
|
-
*
|
|
52
|
-
* entries should export sectionHandle and typeHandle
|
|
53
|
-
*
|
|
54
|
-
* products should alias productTypeHandle with typeHandle,
|
|
55
|
-
* sectionHandle will be automatically set to product
|
|
56
|
-
*/
|
|
57
|
-
function getEntry(page: any): Entry | null {
|
|
58
|
-
if (page?.entry) return { ...page.entry };
|
|
59
|
-
if (page?.product)
|
|
60
|
-
return {
|
|
61
|
-
sectionHandle: 'product',
|
|
62
|
-
...page.product,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
return null;
|
|
27
|
+
export function pluginsBeforeRender(cr: CrelteRequest, route: Route): void {
|
|
28
|
+
cr.events.trigger('beforeRender', cr, route);
|
|
66
29
|
}
|
|
67
30
|
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
entryQuery: GraphQlQuery,
|
|
73
|
-
globalQuery?: GraphQlQuery,
|
|
74
|
-
): Promise<(cr: CrelteRequest, loadOpts?: LoadOptions) => Promise<any>> {
|
|
75
|
-
const templateModules = prepareTemplates(app.templates ?? {});
|
|
76
|
-
let entryRouter: EntryRouter | null = null;
|
|
77
|
-
if (app.entryRoutes) {
|
|
78
|
-
entryRouter = new EntryRouter(crelte);
|
|
79
|
-
await app.entryRoutes(entryRouter);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return async (cr, loadOpts) => {
|
|
83
|
-
return await loadFn(
|
|
84
|
-
cr,
|
|
85
|
-
app,
|
|
86
|
-
templateModules,
|
|
87
|
-
entryRouter,
|
|
88
|
-
entryQuery,
|
|
89
|
-
globalQuery,
|
|
90
|
-
loadOpts,
|
|
91
|
-
);
|
|
92
|
-
};
|
|
93
|
-
}
|
|
31
|
+
// This should be onRequest or handleRequest
|
|
32
|
+
//
|
|
33
|
+
// it should also handle the site redirect and stuff like that
|
|
34
|
+
// we should have a onRequest
|
|
94
35
|
|
|
95
|
-
async function loadFn(
|
|
36
|
+
export async function loadFn(
|
|
96
37
|
cr: CrelteRequest,
|
|
97
|
-
app:
|
|
98
|
-
templateModules: Map<string, LazyTemplateModule>,
|
|
99
|
-
entryRouter: EntryRouter | null,
|
|
100
|
-
entryQuery: GraphQlQuery,
|
|
101
|
-
globalQuery?: GraphQlQuery,
|
|
38
|
+
app: InternalApp,
|
|
102
39
|
loadOpts?: LoadOptions,
|
|
103
|
-
): Promise<
|
|
104
|
-
|
|
105
|
-
// @ts-ignore
|
|
106
|
-
if (app.loadData) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
'loadData is ambigous, choose loadGlobalData or ' +
|
|
109
|
-
'loadEntryData depending on if you need access to entry or not?',
|
|
110
|
-
);
|
|
111
|
-
}
|
|
40
|
+
): Promise<void> {
|
|
41
|
+
const isCanceled = () => !!loadOpts?.isCanceled();
|
|
112
42
|
|
|
113
|
-
|
|
114
|
-
dataProm = callLoadData(app.loadGlobalData, cr, null) as any;
|
|
115
|
-
}
|
|
43
|
+
// loadGlobalData phase
|
|
116
44
|
|
|
117
45
|
let globalProm: Promise<any> | null = null;
|
|
118
|
-
|
|
46
|
+
|
|
47
|
+
if (app.loadGlobalData) {
|
|
48
|
+
// we need to set the globals as soon as loadGlobalData completes
|
|
49
|
+
// because other loadGlobalData functions might wait on the result
|
|
119
50
|
globalProm = (async () => {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
51
|
+
// todo theoretically we could if the loadData is a an LoadObject
|
|
52
|
+
// assign each to the global as soon as we have it. Which might
|
|
53
|
+
// prevent some deadlocks but i don't think this will happen
|
|
54
|
+
// often
|
|
55
|
+
const globals = await callLoadData(app.loadGlobalData, cr, null);
|
|
56
|
+
if (!globals) return globals;
|
|
57
|
+
|
|
58
|
+
if (typeof globals !== 'object') {
|
|
59
|
+
throw new Error(
|
|
60
|
+
'loadGlobalData needs to return an object or nothing',
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
for (const [k, v] of Object.entries(globals)) {
|
|
65
|
+
cr.globals.set(k, v);
|
|
66
|
+
}
|
|
129
67
|
})();
|
|
130
68
|
}
|
|
131
69
|
|
|
132
|
-
|
|
70
|
+
// todo maybe each setting of the property on the request should be
|
|
71
|
+
// checked to be empty before doing it
|
|
72
|
+
const entryProm = (async () => {
|
|
73
|
+
let loadEntry = app.loadEntry;
|
|
74
|
+
if (isGraphQlQuery(loadEntry)) {
|
|
75
|
+
const entryQuery = loadEntry;
|
|
76
|
+
loadEntry = cr => queryEntry(cr, entryQuery);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let entry: Entry = await callLoadData(loadEntry, cr, null);
|
|
80
|
+
if (isCanceled()) return [];
|
|
81
|
+
cr.req.entry = entry;
|
|
82
|
+
|
|
83
|
+
await Promise.all(cr.events.trigger('afterLoadEntry', cr));
|
|
84
|
+
if (isCanceled()) return [];
|
|
85
|
+
entry = cr.req.entry;
|
|
86
|
+
|
|
87
|
+
const template = await app.loadTemplate(entry);
|
|
88
|
+
if (isCanceled()) return [];
|
|
89
|
+
cr.req.template = template;
|
|
90
|
+
|
|
91
|
+
return [entry, template] as [Entry, TemplateModule];
|
|
92
|
+
})();
|
|
133
93
|
|
|
134
94
|
const pluginsLoadGlobalData = cr.events.trigger('loadGlobalData', cr);
|
|
135
95
|
|
|
136
96
|
// loading progress is at 20%
|
|
137
97
|
loadOpts?.setProgress(0.2);
|
|
138
98
|
|
|
139
|
-
const [
|
|
140
|
-
dataProm,
|
|
99
|
+
const [_global, [entry, template]] = await Promise.all([
|
|
141
100
|
globalProm,
|
|
142
101
|
entryProm,
|
|
143
102
|
...pluginsLoadGlobalData,
|
|
144
103
|
]);
|
|
104
|
+
if (isCanceled()) return;
|
|
145
105
|
|
|
146
|
-
|
|
147
|
-
// even if no globalQuery exists
|
|
148
|
-
if (global || !cr.globals._wasLoaded(cr.site.id)) {
|
|
149
|
-
cr.globals._setData(cr.site.id, global ?? {});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
let template;
|
|
153
|
-
if (app.templates) {
|
|
154
|
-
template = await loadTemplate(templateModules, entry);
|
|
155
|
-
} else {
|
|
156
|
-
throw new Error('App must export some templates');
|
|
157
|
-
}
|
|
106
|
+
cr.globals._globalsLoaded();
|
|
158
107
|
|
|
159
108
|
// loading progress is at 60%
|
|
160
109
|
loadOpts?.setProgress(0.6);
|
|
@@ -168,7 +117,7 @@ async function loadFn(
|
|
|
168
117
|
|
|
169
118
|
let entryDataProm: Promise<any> | null = null;
|
|
170
119
|
if (app.loadEntryData) {
|
|
171
|
-
entryDataProm = callLoadData(app.loadEntryData, cr, entry)
|
|
120
|
+
entryDataProm = callLoadData(app.loadEntryData, cr, entry);
|
|
172
121
|
}
|
|
173
122
|
|
|
174
123
|
const [templateData, entryData] = await Promise.all([
|
|
@@ -177,126 +126,57 @@ async function loadFn(
|
|
|
177
126
|
...pluginsLoadData,
|
|
178
127
|
]);
|
|
179
128
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
...data,
|
|
129
|
+
cr.req.loadedData = {
|
|
130
|
+
...templateData,
|
|
185
131
|
...entryData,
|
|
186
|
-
entry,
|
|
187
|
-
template: template.default,
|
|
188
|
-
templateData: templateData! as any,
|
|
189
132
|
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function parseFilename(path: string): [string, string] {
|
|
193
|
-
// get filename with extension
|
|
194
|
-
const slash = path.lastIndexOf('/');
|
|
195
|
-
const filename = path.substring(slash + 1);
|
|
196
133
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const name = filename.substring(0, extPos);
|
|
200
|
-
const ext = filename.substring(extPos + 1);
|
|
201
|
-
|
|
202
|
-
return [name, ext];
|
|
134
|
+
// loading progress is at 100%
|
|
135
|
+
loadOpts?.setProgress(1);
|
|
203
136
|
}
|
|
204
137
|
|
|
205
|
-
async function queryEntry(
|
|
138
|
+
export async function queryEntry(
|
|
206
139
|
cr: CrelteRequest,
|
|
207
|
-
app: App,
|
|
208
|
-
entryRouter: EntryRouter | null,
|
|
209
140
|
entryQuery: GraphQlQuery,
|
|
210
141
|
): Promise<Entry> {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (uri.startsWith('/')) uri = uri.substring(1);
|
|
216
|
-
if (uri === '' || uri === '/') uri = '__home__';
|
|
217
|
-
|
|
218
|
-
vars = {
|
|
219
|
-
uri,
|
|
220
|
-
siteId: cr.site.id,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (vars) {
|
|
225
|
-
await Promise.all(cr.events.trigger('beforeQueryEntry', cr, vars));
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// basic query function
|
|
229
|
-
let loadFn = async (vars: EntryQueryVars | null) => {
|
|
230
|
-
if (entryRouter) {
|
|
231
|
-
const entry = await entryRouter._handle(cr);
|
|
232
|
-
if (entry) return entry;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (vars) {
|
|
236
|
-
const page = await cr.query(entryQuery, vars);
|
|
142
|
+
if (!cr.req.siteMatches())
|
|
143
|
+
throw new Error(
|
|
144
|
+
'to run the entryQuery the request needs to have a matching site',
|
|
145
|
+
);
|
|
237
146
|
|
|
238
|
-
|
|
239
|
-
|
|
147
|
+
let uri = decodeURI(cr.req.uri);
|
|
148
|
+
if (uri.startsWith('/')) uri = uri.substring(1);
|
|
149
|
+
if (uri === '' || uri === '/') uri = '__home__';
|
|
240
150
|
|
|
241
|
-
|
|
151
|
+
const vars = {
|
|
152
|
+
uri,
|
|
153
|
+
siteId: cr.site.id,
|
|
242
154
|
};
|
|
243
155
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
for (const fn of fns) {
|
|
247
|
-
const prevLoadFn = loadFn;
|
|
248
|
-
loadFn = async vars => {
|
|
249
|
-
return await fn(cr, vars, prevLoadFn);
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const entry = (await loadFn(vars)) ?? ERROR_404_ENTRY;
|
|
254
|
-
|
|
255
|
-
await Promise.all(cr.events.trigger('afterQueryEntry', cr, entry));
|
|
256
|
-
|
|
257
|
-
return entry;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function prepareTemplates(
|
|
261
|
-
rawModules: Record<string, LazyTemplateModule>,
|
|
262
|
-
): Map<string, LazyTemplateModule> {
|
|
263
|
-
// parse modules
|
|
264
|
-
return new Map(
|
|
265
|
-
Object.entries(rawModules)
|
|
266
|
-
.map(([path, mod]) => {
|
|
267
|
-
const [name, _ext] = parseFilename(path);
|
|
268
|
-
return [name, mod] as [string, LazyTemplateModule];
|
|
269
|
-
})
|
|
270
|
-
.filter(([name, _mod]) => !!name),
|
|
271
|
-
);
|
|
156
|
+
const page = await cr.query(entryQuery, vars);
|
|
157
|
+
return getEntry(page) ?? ERROR_404_ENTRY;
|
|
272
158
|
}
|
|
273
159
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
const entr = entry as any;
|
|
279
|
-
const handle = `${entr.sectionHandle}-${entr.typeHandle}`;
|
|
280
|
-
|
|
281
|
-
if (
|
|
282
|
-
// @ts-ignore
|
|
283
|
-
import.meta.env.DEV &&
|
|
284
|
-
!modules.has(handle) &&
|
|
285
|
-
!modules.has(entr.sectionHandle)
|
|
286
|
-
) {
|
|
287
|
-
console.error(
|
|
288
|
-
`Template not found: <${handle}>, expecting file: ${handle}.svelte or ${entr.sectionHandle}.svelte`,
|
|
289
|
-
);
|
|
290
|
-
}
|
|
160
|
+
const ERROR_404_ENTRY: Entry = {
|
|
161
|
+
sectionHandle: 'error',
|
|
162
|
+
typeHandle: '404',
|
|
163
|
+
};
|
|
291
164
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Get the entry from the page
|
|
167
|
+
*
|
|
168
|
+
* entries should export sectionHandle and typeHandle
|
|
169
|
+
*
|
|
170
|
+
* products should alias productTypeHandle with typeHandle,
|
|
171
|
+
* sectionHandle will be automatically set to product
|
|
172
|
+
*/
|
|
173
|
+
function getEntry(page: any): Entry | null {
|
|
174
|
+
if (page?.entry) return { ...page.entry };
|
|
175
|
+
if (page?.product)
|
|
176
|
+
return {
|
|
177
|
+
sectionHandle: 'product',
|
|
178
|
+
...page.product,
|
|
179
|
+
};
|
|
297
180
|
|
|
298
|
-
|
|
299
|
-
return await loadMod();
|
|
300
|
-
}
|
|
301
|
-
return loadMod;
|
|
181
|
+
return null;
|
|
302
182
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
internalSvelteMount,
|
|
3
|
+
internalSvelteRender,
|
|
4
|
+
} from 'crelte-vite-plugin/svelteComponents.js';
|
|
5
|
+
|
|
6
|
+
export function svelteMount(comp: any, options: any): any {
|
|
7
|
+
return internalSvelteMount(comp, options);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function svelteRender(comp: any, options: any): any {
|
|
11
|
+
return internalSvelteRender(comp, options);
|
|
12
|
+
}
|
package/src/loadData/Globals.ts
CHANGED
|
@@ -7,27 +7,63 @@ cr.getGlobal('emergency')
|
|
|
7
7
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { Writable } from 'crelte-std/stores';
|
|
10
|
+
import { Readable, Writable } from 'crelte-std/stores';
|
|
11
11
|
|
|
12
|
-
export type GlobalWaiters<T> =
|
|
12
|
+
export type GlobalWaiters<T> = ((g: T | null) => void)[];
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Globals is sort of a queue
|
|
16
|
+
*
|
|
17
|
+
* each time a new request get's started
|
|
18
|
+
* a copy of globals is created which references some properties of the original one
|
|
19
|
+
*
|
|
20
|
+
* then if everything is loaded th original globals is "overriden" with the new one
|
|
21
|
+
* and we get a new state
|
|
22
|
+
*/
|
|
14
23
|
export default class Globals {
|
|
15
24
|
// while the globals are not loaded if somebody calls
|
|
16
25
|
// getAsync then we need to store the waiters
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
private
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
// this get's created as soon as a request was started
|
|
27
|
+
// and get's deleted as soon as all globals are loaded
|
|
28
|
+
private waiters: Map<string, GlobalWaiters<any>> | null;
|
|
29
|
+
|
|
30
|
+
// this get's created as soon as a request was started
|
|
31
|
+
// and deleted once they are synced to the stores
|
|
32
|
+
private newData: Map<string, any> | null;
|
|
33
|
+
|
|
34
|
+
// contains the current active globals
|
|
35
|
+
private stores: Map<string, Writable<any>>;
|
|
36
|
+
|
|
37
|
+
constructor(stores?: Map<string, Writable<any>>) {
|
|
38
|
+
this.waiters = null;
|
|
39
|
+
this.newData = null;
|
|
40
|
+
this.stores = stores ?? new Map();
|
|
27
41
|
}
|
|
28
42
|
|
|
29
|
-
|
|
30
|
-
|
|
43
|
+
/**
|
|
44
|
+
* returns a globalValue
|
|
45
|
+
*
|
|
46
|
+
* ## Note
|
|
47
|
+
* This only works in loadData, in loadGlobalData this will
|
|
48
|
+
* throw an error. In that context you should use `.getAsync`
|
|
49
|
+
*/
|
|
50
|
+
get<T = any>(name: string): T | null {
|
|
51
|
+
if (this.waiters)
|
|
52
|
+
throw new Error(
|
|
53
|
+
'calling get in loadGlobalData will not work. call getAsync',
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
if (!this.newData) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
'calling get outside of a loadData is forbidden. use getStore',
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// todo do we wan't to allow this?
|
|
62
|
+
// isn't it just a footgun?
|
|
63
|
+
// return this.getStore(name)?.get() ?? null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return this.newData.get(name) ?? null;
|
|
31
67
|
}
|
|
32
68
|
|
|
33
69
|
/**
|
|
@@ -38,8 +74,8 @@ export default class Globals {
|
|
|
38
74
|
* always return null. In that context you should use
|
|
39
75
|
* `.getAsync`
|
|
40
76
|
*/
|
|
41
|
-
getStore<T = any>(name: string):
|
|
42
|
-
return this.stores.get(name) ?? null;
|
|
77
|
+
getStore<T = any>(name: string): Readable<T> | null {
|
|
78
|
+
return this.stores.get(name)?.readonly() ?? null;
|
|
43
79
|
}
|
|
44
80
|
|
|
45
81
|
/**
|
|
@@ -47,83 +83,34 @@ export default class Globals {
|
|
|
47
83
|
*
|
|
48
84
|
* ## Note
|
|
49
85
|
* This is only useful in loadGlobalData in all other cases
|
|
50
|
-
* you can use `.
|
|
86
|
+
* you can use `.get` which does not return a Promise
|
|
51
87
|
*/
|
|
52
|
-
getAsync<T = any>(name: string
|
|
53
|
-
if (this.
|
|
54
|
-
return Promise.resolve(this.get(name, siteId));
|
|
88
|
+
getAsync<T = any>(name: string): Promise<T | null> | T | null {
|
|
89
|
+
if (this.newData) return this.newData.get(name) ?? null;
|
|
55
90
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
91
|
+
if (!this.waiters)
|
|
92
|
+
throw new Error(
|
|
93
|
+
'calling getAsync in non loadGlobalData contexts is pointless. Use getStore instead',
|
|
94
|
+
);
|
|
61
95
|
|
|
62
|
-
let
|
|
63
|
-
if (!
|
|
64
|
-
|
|
65
|
-
|
|
96
|
+
let listeners = this.waiters.get(name);
|
|
97
|
+
if (!listeners) {
|
|
98
|
+
listeners = [];
|
|
99
|
+
this.waiters.set(name, listeners);
|
|
66
100
|
}
|
|
67
101
|
|
|
68
|
-
return new Promise(resolve =>
|
|
69
|
-
waiter!.push(resolve);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** @hidden */
|
|
74
|
-
_wasLoaded(siteId: number): boolean {
|
|
75
|
-
return this.data.has(siteId);
|
|
102
|
+
return new Promise(resolve => listeners.push(resolve));
|
|
76
103
|
}
|
|
77
104
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
this.waiters.get(siteId)?.forEach((waiters, key) => {
|
|
88
|
-
waiters.forEach(waiter => waiter(map.get(key)));
|
|
89
|
-
});
|
|
90
|
-
this.waiters.delete(siteId);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** @hidden */
|
|
94
|
-
_updateSiteId(siteId: number) {
|
|
95
|
-
if (this.currentSiteId === siteId) return;
|
|
96
|
-
|
|
97
|
-
const data = this.data.get(siteId) ?? new Map();
|
|
98
|
-
|
|
99
|
-
// we set all global data to null via setSilent
|
|
100
|
-
// then set them all with the new data
|
|
101
|
-
// and update all of them
|
|
102
|
-
|
|
103
|
-
this.stores.forEach(global => global._setSilent(null));
|
|
104
|
-
|
|
105
|
-
data.forEach((value, key) => {
|
|
106
|
-
let global = this.stores.get(key);
|
|
107
|
-
if (global) {
|
|
108
|
-
global._setSilent(value);
|
|
109
|
-
} else {
|
|
110
|
-
global = new Global(key, value);
|
|
111
|
-
this.stores.set(key, global);
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
this.stores.forEach(global => global._notify());
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* A globalSet store
|
|
121
|
-
*/
|
|
122
|
-
export class Global<T = any> {
|
|
123
|
-
/** @hidden */
|
|
124
|
-
private inner: Writable<T>;
|
|
105
|
+
/**
|
|
106
|
+
* can only be called in loadGlobalData contexts
|
|
107
|
+
*/
|
|
108
|
+
set<T>(name: string, data: T) {
|
|
109
|
+
if (!this.newData) {
|
|
110
|
+
// this is not strictly necessary but
|
|
111
|
+
throw new Error('can only be called in loadGlobalData contexts');
|
|
112
|
+
}
|
|
125
113
|
|
|
126
|
-
constructor(name: string, data: T) {
|
|
127
114
|
// todo remove in v1.0
|
|
128
115
|
// In v0.2, we queried the global data for all sites.
|
|
129
116
|
// We now check if the siteId is present and notify the user to remove it.
|
|
@@ -137,33 +124,65 @@ export class Global<T = any> {
|
|
|
137
124
|
);
|
|
138
125
|
}
|
|
139
126
|
|
|
140
|
-
this.
|
|
127
|
+
this.newData?.set(name, data);
|
|
128
|
+
|
|
129
|
+
const listeners = this.waiters?.get(name);
|
|
130
|
+
if (listeners) {
|
|
131
|
+
this.waiters!.delete(name);
|
|
132
|
+
listeners.forEach(fn => fn(data));
|
|
133
|
+
}
|
|
141
134
|
}
|
|
142
135
|
|
|
143
136
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* @return a function which should be called to unsubscribe
|
|
137
|
+
* @hidden
|
|
138
|
+
* call this before starting the loadGlobalData phase
|
|
148
139
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
_toRequest() {
|
|
141
|
+
const nGlobals = new Globals(this.stores);
|
|
142
|
+
nGlobals.waiters = new Map();
|
|
143
|
+
nGlobals.newData = new Map();
|
|
144
|
+
|
|
145
|
+
return nGlobals;
|
|
151
146
|
}
|
|
152
147
|
|
|
153
148
|
/**
|
|
154
|
-
*
|
|
149
|
+
* @hidden
|
|
150
|
+
* call this after the loadGlobalData phase
|
|
155
151
|
*/
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
_globalsLoaded() {
|
|
153
|
+
// todo should we check if there are still waiters?
|
|
154
|
+
// theoretically this should never happen
|
|
155
|
+
this.waiters = null;
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
/**
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
158
|
+
/**
|
|
159
|
+
* @hidden
|
|
160
|
+
* call this after the loadData phase once the CrelteRequest
|
|
161
|
+
* gets completed
|
|
162
|
+
*/
|
|
163
|
+
_syncToStores() {
|
|
164
|
+
const setToNull = new Set(this.stores.keys());
|
|
165
|
+
|
|
166
|
+
for (const [name, data] of this.newData!.entries()) {
|
|
167
|
+
setToNull.delete(name);
|
|
168
|
+
|
|
169
|
+
const store = this.stores.get(name);
|
|
170
|
+
if (store) {
|
|
171
|
+
// todo should we do this check always?
|
|
172
|
+
if (store.get() !== data) store.set(data);
|
|
173
|
+
} else {
|
|
174
|
+
this.stores.set(name, new Writable(data));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
for (const name of setToNull) {
|
|
179
|
+
console.warn(
|
|
180
|
+
`global ${name} was not modified setting to null and removing it`,
|
|
181
|
+
);
|
|
182
|
+
this.stores.get(name)!.set(null);
|
|
183
|
+
this.stores.delete(name);
|
|
184
|
+
}
|
|
164
185
|
|
|
165
|
-
|
|
166
|
-
_notify() {
|
|
167
|
-
this.inner.notify();
|
|
186
|
+
this.newData = null;
|
|
168
187
|
}
|
|
169
188
|
}
|