Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental support for disabling SSR for waku/router #569

Merged
merged 4 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createElement } from 'react';
import type { FunctionComponent, ReactNode } from 'react';

import { defineRouter } from './defineRouter.js';
import { unstable_defineRouter as defineRouter } from './define-router.js';
import type { RouteProps } from './common.js';
import {
joinPath,
Expand Down Expand Up @@ -52,7 +52,7 @@ type CreatePage = <
SlugKey extends string,
WildSlugKey extends string,
>(
page:
page: (
| {
render: 'static';
path: PathWithoutSlug<Path>;
Expand All @@ -75,7 +75,8 @@ type CreatePage = <
component: FunctionComponent<
RouteProps & Record<SlugKey, string> & Record<WildSlugKey, string[]>
>;
},
}
) & { unstable_disableSSR?: boolean },
) => void;

type CreateLayout = <T extends string>(layout: {
Expand All @@ -91,10 +92,14 @@ export function createPages(
}) => Promise<void>,
) {
let configured = false;

// TODO I think there's room for improvement to refactor these structures
const staticPathSet = new Set<PathSpec>();
const dynamicPathMap = new Map<string, [PathSpec, FunctionComponent<any>]>();
const wildcardPathMap = new Map<string, [PathSpec, FunctionComponent<any>]>();
const staticComponentMap = new Map<string, FunctionComponent<any>>();
const noSsrSet = new WeakSet<PathSpec>();

const registerStaticComponent = (
id: string,
component: FunctionComponent<any>,
Expand All @@ -113,6 +118,9 @@ export function createPages(
throw new Error('no longer available');
}
const pathSpec = parsePathWithSlug(page.path);
if (page.unstable_disableSSR) {
noSsrSet.add(pathSpec);
}
const numSlugs = pathSpec.filter(({ type }) => type !== 'literal').length;
const numWildcards = pathSpec.filter(
({ type }) => type === 'wildcard',
Expand Down Expand Up @@ -179,23 +187,26 @@ export function createPages(
return defineRouter(
async () => {
await ready;
const paths: { path: PathSpec; isStatic: boolean }[] = [];
const paths: { path: PathSpec; isStatic: boolean; noSsr: boolean }[] = [];
for (const pathSpec of staticPathSet) {
paths.push({ path: pathSpec, isStatic: true });
const noSsr = noSsrSet.has(pathSpec);
paths.push({ path: pathSpec, isStatic: true, noSsr });
}
for (const [pathSpec] of dynamicPathMap.values()) {
paths.push({ path: pathSpec, isStatic: false });
const noSsr = noSsrSet.has(pathSpec);
paths.push({ path: pathSpec, isStatic: false, noSsr });
}
for (const [pathSpec] of wildcardPathMap.values()) {
paths.push({ path: pathSpec, isStatic: false });
const noSsr = noSsrSet.has(pathSpec);
paths.push({ path: pathSpec, isStatic: false, noSsr });
}
return paths;
},
async (id, unstable_setShouldSkip) => {
async (id, setShouldSkip) => {
await ready;
const staticComponent = staticComponentMap.get(id);
if (staticComponent) {
unstable_setShouldSkip({});
setShouldSkip({});
return staticComponent;
}
for (const [pathSpec, Component] of dynamicPathMap.values()) {
Expand All @@ -205,12 +216,12 @@ export function createPages(
);
if (mapping) {
if (Object.keys(mapping).length === 0) {
unstable_setShouldSkip();
setShouldSkip();
return Component;
}
const WrappedComponent = (props: Record<string, unknown>) =>
createElement(Component, { ...props, ...mapping });
unstable_setShouldSkip();
setShouldSkip();
return WrappedComponent;
}
}
Expand All @@ -222,11 +233,11 @@ export function createPages(
if (mapping) {
const WrappedComponent = (props: Record<string, unknown>) =>
createElement(Component, { ...props, ...mapping });
unstable_setShouldSkip();
setShouldSkip();
return WrappedComponent;
}
}
unstable_setShouldSkip({}); // negative cache
setShouldSkip({}); // negative cache
return null; // not found
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,23 @@ import { getPathMapping } from '../lib/utils/path.js';
import type { PathSpec } from '../lib/utils/path.js';
import { ServerRouter } from './client.js';

// TODO revisit shouldSkip API
const ShoudSkipComponent = ({ shouldSkip }: { shouldSkip: ShouldSkip }) =>
createElement('meta', {
name: 'waku-should-skip',
content: JSON.stringify(shouldSkip),
});

export function defineRouter(
export function unstable_defineRouter(
getPathConfig: () => Promise<
Iterable<{ path: PathSpec; isStatic?: boolean }>
Iterable<{ path: PathSpec; isStatic?: boolean; noSsr?: boolean }>
>,
getComponent: (
componentId: string, // "**/layout" or "**/page"
unstable_setShouldSkip: (val?: ShouldSkip[string]) => void,
/**
* HACK setShouldSkip API is too hard to understand
*/
setShouldSkip: (val?: ShouldSkip[string]) => void,
) => Promise<
| FunctionComponent<RouteProps>
| FunctionComponent<RouteProps & { children: ReactNode }>
Expand All @@ -49,11 +53,14 @@ export function defineRouter(
const has404Promise = pathConfigPromise.then((pathConfig) =>
pathConfig.some(({ is404 }) => is404),
);
const existsPath = async (pathname: string) => {
const existsPath = async (
pathname: string,
): Promise<false | true | 'NO_SSR'> => {
const pathConfig = await pathConfigPromise;
return pathConfig.some(({ path: pathSpec }) =>
const found = pathConfig.find(({ path: pathSpec }) =>
getPathMapping(pathSpec, pathname),
);
return found ? (found.noSsr ? 'NO_SSR' : true) : false;
};
const shouldSkip: ShouldSkip = {};

Expand Down Expand Up @@ -144,7 +151,11 @@ globalThis.__WAKU_ROUTER_PREFETCH__ = (path) => {
};

const getSsrConfig: GetSsrConfig = async (pathname, { searchParams }) => {
if (!(await existsPath(pathname))) {
const found = await existsPath(pathname);
if (found === 'NO_SSR') {
return null;
}
if (!found) {
if (await has404Promise) {
pathname = '/404';
} else {
Expand Down
4 changes: 2 additions & 2 deletions packages/waku/src/router/server.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { defineRouter as unstable_defineRouter } from './defineRouter.js';
export { createPages } from './createPages.js';
export { unstable_defineRouter } from './define-router.js';
export { createPages } from './create-pages.js';
Loading