Skip to content

Commit

Permalink
feat(v2): new server$, actions and loaders serialization (#6763)
Browse files Browse the repository at this point in the history
* add server side deserialization

* add server side serialization

* change to the new serialization for server$

* change deserialize method

* fix some e2e tests

* fix loaders

* add js comments

* update api

* add more serialization tests
  • Loading branch information
Varixo authored Aug 5, 2024
1 parent 5ed507e commit 8800555
Show file tree
Hide file tree
Showing 22 changed files with 301 additions and 72 deletions.
5 changes: 3 additions & 2 deletions packages/qwik-city/buildtime/vite/dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
} from '../../middleware/request-handler/resolve-request-handlers';
import { formatError } from './format-error';
import { matchRoute } from '../../runtime/src/route-matcher';
import type { QwikSerializer } from 'packages/qwik-city/middleware/request-handler/types';

export function ssrDevMiddleware(ctx: BuildContext, server: ViteDevServer) {
const matchRouteRequest = (pathname: string) => {
Expand Down Expand Up @@ -215,9 +216,9 @@ export function ssrDevMiddleware(ctx: BuildContext, server: ViteDevServer) {
version: '1',
};

const { _deserializeData, _serializeData, _verifySerializable } =
const { _deserialize, _serialize, _verifySerializable } =
await server.ssrLoadModule('@qwik-serializer');
const qwikSerializer = { _deserializeData, _serializeData, _verifySerializable };
const qwikSerializer: QwikSerializer = { _deserialize, _serialize, _verifySerializable };

const { completion, requestEv } = runQwikCity(
serverRequestEv,
Expand Down
2 changes: 1 addition & 1 deletion packages/qwik-city/buildtime/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ function qwikCityPlugin(userOpts?: QwikCityVitePluginOptions): any {
const isSwRegister = id.endsWith(QWIK_CITY_SW_REGISTER);

if (isSerializer) {
return `export {_deserializeData, _serializeData, _verifySerializable} from '@builder.io/qwik'`;
return `export {_deserialize, _serialize, _verifySerializable} from '@builder.io/qwik'`;
}
if (isCityPlan || isSwRegister) {
if (!ctx.isDevServer && ctx.isDirty) {
Expand Down
9 changes: 5 additions & 4 deletions packages/qwik-city/middleware/azure-swa/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import type {
ServerRequestEvent,
} from '@builder.io/qwik-city/middleware/request-handler';
import { getNotFound } from '@qwik-city-not-found-paths';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';
import { parseString } from 'set-cookie-parser';
import { isStaticPath } from '@qwik-city-static-paths';
import type { QwikSerializer } from '../request-handler/types';

// @builder.io/qwik-city/middleware/azure-swa

Expand Down Expand Up @@ -49,9 +50,9 @@ interface AzureCookie {

/** @public */
export function createQwikCity(opts: QwikCityAzureOptions): AzureFunction {
const qwikSerializer = {
_deserializeData,
_serializeData,
const qwikSerializer: QwikSerializer = {
_deserialize,
_serialize,
_verifySerializable,
};
if (opts.manifest) {
Expand Down
9 changes: 5 additions & 4 deletions packages/qwik-city/middleware/bun/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ import {
} from '@builder.io/qwik-city/middleware/request-handler';
import { getNotFound } from '@qwik-city-not-found-paths';
import { isStaticPath } from '@qwik-city-static-paths';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';
import { setServerPlatform } from '@builder.io/qwik/server';
import { MIME_TYPES } from '../request-handler/mime-types';
import { join, extname } from 'node:path';
import type { QwikSerializer } from '../request-handler/types';

/** @public */
export function createQwikCity(opts: QwikCityBunOptions) {
// @builder.io/qwik-city/middleware/bun
// still missing from bun: last check was bun version 1.1.8
globalThis.TextEncoderStream ||= _TextEncoderStream_polyfill;

const qwikSerializer = {
_deserializeData,
_serializeData,
const qwikSerializer: QwikSerializer = {
_deserialize,
_serialize,
_verifySerializable,
};
if (opts.manifest) {
Expand Down
9 changes: 5 additions & 4 deletions packages/qwik-city/middleware/cloudflare-pages/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import {
} from '@builder.io/qwik-city/middleware/request-handler';
import { getNotFound } from '@qwik-city-not-found-paths';
import { isStaticPath } from '@qwik-city-static-paths';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';
import { setServerPlatform } from '@builder.io/qwik/server';
import type { QwikSerializer } from '../request-handler/types';

// @builder.io/qwik-city/middleware/cloudflare-pages

Expand All @@ -24,9 +25,9 @@ export function createQwikCity(opts: QwikCityCloudflarePagesOptions) {
// @ts-ignore
globalThis.TextEncoderStream = _TextEncoderStream_polyfill2;
}
const qwikSerializer = {
_deserializeData,
_serializeData,
const qwikSerializer: QwikSerializer = {
_deserialize,
_serialize,
_verifySerializable,
};
if (opts.manifest) {
Expand Down
9 changes: 5 additions & 4 deletions packages/qwik-city/middleware/deno/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import {
} from '@builder.io/qwik-city/middleware/request-handler';
import { getNotFound } from '@qwik-city-not-found-paths';
import { isStaticPath } from '@qwik-city-static-paths';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';
import { setServerPlatform } from '@builder.io/qwik/server';
import { MIME_TYPES } from '../request-handler/mime-types';
// @ts-ignore
import { extname, fromFileUrl, join } from 'https://deno.land/std/path/mod.ts';
import type { QwikSerializer } from '../request-handler/types';

// @builder.io/qwik-city/middleware/deno

Expand All @@ -31,9 +32,9 @@ export interface ServeHandlerInfo {

/** @public */
export function createQwikCity(opts: QwikCityDenoOptions) {
const qwikSerializer = {
_deserializeData,
_serializeData,
const qwikSerializer: QwikSerializer = {
_deserialize,
_serialize,
_verifySerializable,
};
if (opts.manifest) {
Expand Down
9 changes: 5 additions & 4 deletions packages/qwik-city/middleware/netlify-edge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@ import {
} from '@builder.io/qwik-city/middleware/request-handler';
import { getNotFound } from '@qwik-city-not-found-paths';
import { isStaticPath } from '@qwik-city-static-paths';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';
import { setServerPlatform } from '@builder.io/qwik/server';
import type { QwikSerializer } from '../request-handler/types';

// @builder.io/qwik-city/middleware/netlify-edge

declare const Deno: any;
/** @public */
export function createQwikCity(opts: QwikCityNetlifyOptions) {
const qwikSerializer = {
_deserializeData,
_serializeData,
const qwikSerializer: QwikSerializer = {
_deserialize,
_serialize,
_verifySerializable,
};
if (opts.manifest) {
Expand Down
9 changes: 5 additions & 4 deletions packages/qwik-city/middleware/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ import { extname, join, basename } from 'node:path';
import { fileURLToPath } from 'node:url';
import { computeOrigin, fromNodeHttp, getUrl } from './http';
import { MIME_TYPES } from '../request-handler/mime-types';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';
import type { Http2ServerRequest } from 'node:http2';
import type { QwikSerializer } from '../request-handler/types';

// @builder.io/qwik-city/middleware/node

/** @public */
export function createQwikCity(opts: QwikCityNodeRequestOptions) {
const qwikSerializer = {
_deserializeData,
_serializeData,
const qwikSerializer: QwikSerializer = {
_deserialize,
_serialize,
_verifySerializable,
};
if (opts.manifest) {
Expand Down
4 changes: 2 additions & 2 deletions packages/qwik-city/middleware/request-handler/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
```ts

import type { Action } from '@builder.io/qwik-city';
import type { _deserializeData } from '@builder.io/qwik';
import type { _deserialize } from '@builder.io/qwik';
import type { EnvGetter as EnvGetter_2 } from '@builder.io/qwik-city/middleware/request-handler';
import type { FailReturn } from '@builder.io/qwik-city';
import type { Loader as Loader_2 } from '@builder.io/qwik-city';
Expand All @@ -16,7 +16,7 @@ import type { RenderOptions } from '@builder.io/qwik/server';
import type { RequestEvent as RequestEvent_2 } from '@builder.io/qwik-city';
import type { RequestHandler as RequestHandler_2 } from '@builder.io/qwik-city/middleware/request-handler';
import type { ResolveSyncValue as ResolveSyncValue_2 } from '@builder.io/qwik-city/middleware/request-handler';
import type { _serializeData } from '@builder.io/qwik';
import type { _serialize } from '@builder.io/qwik';
import type { ValueOrPromise } from '@builder.io/qwik';
import type { _verifySerializable } from '@builder.io/qwik';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,13 +331,13 @@ const parseRequest = async (
const data = query.get(QDATA_KEY);
if (data) {
try {
return qwikSerializer._deserializeData(decodeURIComponent(data));
return qwikSerializer._deserialize(decodeURIComponent(data)) as JSONValue | undefined;
} catch (err) {
//
}
}
}
return qwikSerializer._deserializeData(await request.text());
return qwikSerializer._deserialize(await request.text()) as JSONValue | undefined;
}
return undefined;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { QACTION_KEY, QFN_KEY } from '../../runtime/src/constants';
import { IsQData, QDATA_JSON } from './user-response';
import { HttpStatus } from './http-status-codes';
import type { Render, RenderToStringResult } from '@builder.io/qwik/server';
import type { QRL, _deserializeData, _serializeData } from '@builder.io/qwik';
import type { QRL, _deserialize, _serialize } from '@builder.io/qwik';
import { getQwikCityServerData } from './response-page';
import { RedirectMessage } from './redirect-handler';
import { ServerError } from './error-handler';
Expand Down Expand Up @@ -311,11 +311,11 @@ async function pureServerFunction(ev: RequestEvent) {
} catch (err) {
if (err instanceof ServerError) {
ev.headers.set('Content-Type', 'application/qwik-json');
ev.send(err.status, await qwikSerializer._serializeData(err.data, true));
ev.send(err.status, await qwikSerializer._serialize([err.data]));
return;
}
ev.headers.set('Content-Type', 'application/qwik-json');
ev.send(500, await qwikSerializer._serializeData(err, true));
ev.send(500, await qwikSerializer._serialize([err]));
return;
}
if (isAsyncIterator(result)) {
Expand All @@ -326,7 +326,7 @@ async function pureServerFunction(ev: RequestEvent) {
if (isDev) {
verifySerializable(qwikSerializer, item, qrl);
}
const message = await qwikSerializer._serializeData(item, true);
const message = await qwikSerializer._serialize([item]);
if (ev.signal.aborted) {
break;
}
Expand All @@ -336,7 +336,7 @@ async function pureServerFunction(ev: RequestEvent) {
} else {
verifySerializable(qwikSerializer, result, qrl);
ev.headers.set('Content-Type', 'application/qwik-json');
const message = await qwikSerializer._serializeData(result, true);
const message = await qwikSerializer._serialize([result]);
ev.send(200, message);
}
return;
Expand Down Expand Up @@ -542,7 +542,7 @@ export async function renderQData(requestEv: RequestEvent) {
const writer = requestEv.getWritableStream().getWriter();
const qwikSerializer = (requestEv as RequestEventInternal)[RequestEvQwikSerializer];
// write just the page json data to the response body
const data = await qwikSerializer._serializeData(qData, true);
const data = await qwikSerializer._serialize([qData]);
writer.write(encoder.encode(data));
requestEv.sharedMap.set('qData', qData);

Expand Down
6 changes: 3 additions & 3 deletions packages/qwik-city/middleware/request-handler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { QwikCityPlan, FailReturn, Action, Loader } from '@builder.io/qwik-
import type { ErrorResponse } from './error-handler';
import type { AbortMessage, RedirectMessage } from './redirect-handler';
import type { RequestEventInternal } from './request-event';
import type { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import type { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';

/** @public */
export interface EnvGetter {
Expand Down Expand Up @@ -563,8 +563,8 @@ export interface CookieValue {

/** @public */
export interface QwikSerializer {
_deserializeData: typeof _deserializeData;
_serializeData: typeof _serializeData;
_deserialize: typeof _deserialize;
_serialize: typeof _serialize;
_verifySerializable: typeof _verifySerializable;
}

Expand Down
9 changes: 5 additions & 4 deletions packages/qwik-city/middleware/vercel-edge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {
} from '@builder.io/qwik-city/middleware/request-handler';
import { getNotFound } from '@qwik-city-not-found-paths';
import { isStaticPath } from '@qwik-city-static-paths';
import { _deserializeData, _serializeData, _verifySerializable } from '@builder.io/qwik';
import { _deserialize, _serialize, _verifySerializable } from '@builder.io/qwik';
import { setServerPlatform } from '@builder.io/qwik/server';
import type { QwikSerializer } from '../request-handler/types';

// @builder.io/qwik-city/middleware/vercel-edge
const COUNTRY_HEADER_NAME = 'x-vercel-ip-country';
Expand All @@ -21,9 +22,9 @@ const BASE_URL = 'BASE_URL';

/** @public */
export function createQwikCity(opts: QwikCityVercelEdgeOptions) {
const qwikSerializer = {
_deserializeData,
_serializeData,
const qwikSerializer: QwikSerializer = {
_deserialize,
_serialize,
_verifySerializable,
};
if (opts.manifest) {
Expand Down
16 changes: 10 additions & 6 deletions packages/qwik-city/runtime/src/server-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
useContext,
type ValueOrPromise,
useStore,
_serializeData,
_deserializeData,
_serialize,
_deserialize,
_getContextElement,
_getContextEvent,
_wrapProp,
Expand Down Expand Up @@ -243,7 +243,10 @@ export const zodQrl = ((
return z.object(obj);
}
});
const data = inputData ?? (await ev.parseBody());
let data = inputData;
if (!data) {
data = await ev.parseBody();
}
const result = await (await schema).safeParseAsync(data);
if (result.success) {
return result;
Expand Down Expand Up @@ -348,7 +351,7 @@ export const serverQrl = <T extends ServerFunction>(
},
signal,
};
const body = await _serializeData([qrl, ...filtered], false);
const body = await _serialize([qrl, ...filtered]);
if (method === 'GET') {
query += `&${QDATA_KEY}=${encodeURIComponent(body)}`;
} else {
Expand Down Expand Up @@ -376,7 +379,7 @@ export const serverQrl = <T extends ServerFunction>(
})();
} else if (contentType === 'application/qwik-json') {
const str = await res.text();
const obj = await _deserializeData(str, ctxElm ?? document.documentElement);
const [obj] = _deserialize(str, ctxElm ?? document.documentElement);
if (res.status === 500) {
throw obj;
}
Expand Down Expand Up @@ -456,7 +459,8 @@ const deserializeStream = async function* (
const lines = buffer.split(/\n/);
buffer = lines.pop()!;
for (const line of lines) {
yield await _deserializeData(line, ctxElm);
const [deserializedData] = _deserialize(line, ctxElm);
yield deserializedData;
}
}
} finally {
Expand Down
4 changes: 2 additions & 2 deletions packages/qwik-city/runtime/src/use-endpoint.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getClientDataPath } from './utils';
import { CLIENT_DATA_CACHE } from './constants';
import type { ClientPageData, RouteActionValue } from './types';
import { _deserializeData } from '@builder.io/qwik';
import { _deserialize } from '@builder.io/qwik';
import { prefetchSymbols } from './client-navigate';

export const loadClientData = async (
Expand Down Expand Up @@ -42,7 +42,7 @@ export const loadClientData = async (
if ((rsp.headers.get('content-type') || '').includes('json')) {
// we are safe we are reading a q-data.json
return rsp.text().then((text) => {
const clientData = _deserializeData(text, element) as ClientPageData | null;
const [clientData] = _deserialize(text, element) as [ClientPageData];
if (!clientData) {
location.href = url.href;
return;
Expand Down
Loading

0 comments on commit 8800555

Please sign in to comment.