Skip to content

Commit

Permalink
feat: add support for retrieving request headers from Qwik City
Browse files Browse the repository at this point in the history
  • Loading branch information
mhevery committed Oct 5, 2022
1 parent 3ac5665 commit f740a61
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 6 deletions.
3 changes: 2 additions & 1 deletion packages/qwik-city/buildtime/vite/dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export function ssrDevMiddleware(ctx: BuildContext, server: ViteDevServer) {
return async (req: Connect.IncomingMessage, res: ServerResponse, next: Connect.NextFunction) => {
try {
const url = new URL(req.originalUrl!, `http://${req.headers.host}`);
const requestHeaders: Record<string, string> = req.headers as any;

if (skipRequest(url.pathname) || isVitePing(url.pathname, req.headers)) {
next();
Expand Down Expand Up @@ -115,7 +116,7 @@ export function ssrDevMiddleware(ctx: BuildContext, server: ViteDevServer) {

// qwik city vite plugin should handle dev ssr rendering
// but add the qwik city user context to the response object
const envData = getQwikCityEnvData(userResponse);
const envData = getQwikCityEnvData(requestHeaders, userResponse);
if (ctx.isDevServerClientOnly) {
// because we stringify this content for the client only
// dev server, there's some potential stringify issues
Expand Down
33 changes: 29 additions & 4 deletions packages/qwik-city/middleware/request-handler/page-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import type { QwikManifest } from '@builder.io/qwik/optimizer';
import type {
PrefetchResource,
Render,
RenderOptions,
RenderResult,
RenderToStringResult,
} from '@builder.io/qwik/server';
import type { ClientPageData, QwikCityEnvData } from '../../runtime/src/library/types';
import type {
ClientPageData,
QwikCityEnvData,
RequestContext,
} from '../../runtime/src/library/types';
import { getErrorHtml } from './error-handler';
import { HttpStatus } from './http-status-codes';
import type { QwikCityRequestContext, QwikCityRequestOptions, UserResponseContext } from './types';
Expand All @@ -21,6 +26,8 @@ export function pageHandler<T = any>(
const { status, headers } = userResponse;
const { response } = requestCtx;
const isPageData = userResponse.type === 'pagedata';
const requestHeaders: Record<string, string> = {};
requestCtx.request.headers.forEach((value, key) => (requestHeaders[key] = value));

if (isPageData) {
// page data should always be json
Expand All @@ -35,8 +42,8 @@ export function pageHandler<T = any>(
try {
const result = await render({
stream: isPageData ? noopStream : stream,
envData: getQwikCityEnvData(userResponse),
...opts,
envData: getQwikCityEnvData(requestHeaders, userResponse),
...normalizeOptions(opts, requestCtx.request),
});

if (isPageData) {
Expand Down Expand Up @@ -64,6 +71,19 @@ export function pageHandler<T = any>(
});
}

function normalizeOptions(
opts: QwikCityRequestOptions | undefined,
request: RequestContext
): RenderOptions | undefined {
if (opts && typeof opts.base === 'function') {
return {
...opts,
base: opts.base({ request }),
};
}
return opts as RenderOptions;
}

async function getClientPageData(
userResponse: UserResponseContext,
result: RenderResult,
Expand Down Expand Up @@ -130,13 +150,18 @@ function getPrefetchBundleNames(result: RenderResult, routeBundleNames: string[]
return bundleNames;
}

export function getQwikCityEnvData(userResponse: UserResponseContext): {
export function getQwikCityEnvData(
requestHeaders: Record<string, string>,
userResponse: UserResponseContext
): {
url: string;
requestHeaders: Record<string, string>;
qwikcity: QwikCityEnvData;
} {
const { url, params, pendingBody, resolvedBody, status } = userResponse;
return {
url: url.href,
requestHeaders: requestHeaders,
qwikcity: {
params: { ...params },
response: {
Expand Down
4 changes: 3 additions & 1 deletion packages/qwik-city/middleware/request-handler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ export interface UserResponseContext {
aborted: boolean;
}

export interface QwikCityRequestOptions extends RenderOptions {}
export interface QwikCityRequestOptions extends Omit<RenderOptions, 'base'> {
base?: string | ((args: { request: RequestContext }) => string);
}
3 changes: 3 additions & 0 deletions packages/qwik/src/core/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ export const inlinedQrl: <T>(symbol: T, symbolName: string, lexicalScopeCapture?
// @internal (undocumented)
export const inlinedQrlDEV: <T = any>(symbol: T, symbolName: string, opts: QRLDev, lexicalScopeCapture?: any[]) => QRL<T>;

// @alpha
export const isInUseContext: () => boolean;

// @public (undocumented)
const jsx: <T extends string | FunctionComponent<any>>(type: T, props: T extends FunctionComponent<infer PROPS> ? PROPS : Record<string, any>, key?: string | number | null) => JSXNode<T>;
export { jsx }
Expand Down
1 change: 1 addition & 0 deletions packages/qwik/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export { useEnvData, useUserContext } from './use/use-env-data';
export { useStylesQrl, useStyles$, useStylesScopedQrl, useStylesScoped$ } from './use/use-styles';
export { useOn, useOnDocument, useOnWindow, useCleanupQrl, useCleanup$ } from './use/use-on';
export { useSignal } from './use/use-signal';
export { isInUseContext } from './use/use-core';

export type { UseSignal } from './use/use-signal';
export type { Context } from './use/use-context';
Expand Down
7 changes: 7 additions & 0 deletions packages/qwik/src/core/use/use-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ export interface InvokeContext {

let _context: InvokeContext | undefined;

/**
* Returns `true` if `use*` functions are safe to be invoked in this location.
*
* @alpha
*/
export const isInUseContext = () => !!_context;

export const tryGetInvokeContext = (): InvokeContext | undefined => {
if (!_context) {
const context = typeof document !== 'undefined' && document && document.__q_context__;
Expand Down

0 comments on commit f740a61

Please sign in to comment.