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