Repository: dai-shi/waku
Pull request #1040 (2024-12-07 08:03:57)

chore(router): replace unstable_defineRouter and Router with new versions
will come after #1039 

- `new_defineRouter` 👉 `unstable_defineRouter`
- `NewRouter` 👉 `Router`

vercel[bot]: [vc]: #NXcyioD+waABo2J/HopJ3l1SvaMHPCnR3e8Ef6/uQWA=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ3YWt1Iiwicm9vdERpcmVjdG9yeSI6bnVsbCwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2RhaXNoaXMtcHJvamVjdHMvd2FrdS80d3lkUExMNDFRS050cUNLeWlCNlhhTEhpbkFRIiwicHJldmlld1VybCI6Indha3UtZ2l0LWZvcmstdHlsZXJzYXlzaGktY2hvcmUtdXBkYXRlLTdjZDNhOC1kYWlzaGlzLXByb2plY3RzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiUEVORElORyJ9XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Updated (UTC) |
| :--- | :----- | :------ | :------ |
| **waku** | 🔄 Building ([Inspect](https://vercel.com/daishis-projects/waku/4wydPLL41QKNtqCKyiB6XaLHinAQ)) | [Visit Preview](https://waku-git-fork-tylersayshi-chore-update-7cd3a8-daishis-projects.vercel.app) | Dec 7, 2024 8:04am |


codesandbox-ci[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/dai-shi/waku/pr/1040/builds/568190) or the icon next to each commit SHA.

Patch:
diff --git a/examples/11_fs-router/src/main.tsx b/examples/11_fs-router/src/main.tsx
index 354c5d2f..bddb502d 100644
--- a/examples/11_fs-router/src/main.tsx
+++ b/examples/11_fs-router/src/main.tsx
@@ -1,6 +1,6 @@
 import { StrictMode } from 'react';
 import { createRoot, hydrateRoot } from 'react-dom/client';
-import { NewRouter as Router } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = (
   <StrictMode>
diff --git a/examples/21_create-pages/src/main.tsx b/examples/21_create-pages/src/main.tsx
index 6d204e3a..bddb502d 100644
--- a/examples/21_create-pages/src/main.tsx
+++ b/examples/21_create-pages/src/main.tsx
@@ -1,10 +1,10 @@
 import { StrictMode } from 'react';
 import { createRoot, hydrateRoot } from 'react-dom/client';
-import { NewRouter } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = (
   <StrictMode>
-    <NewRouter />
+    <Router />
   </StrictMode>
 );
 
diff --git a/examples/22_define-router/src/entries.tsx b/examples/22_define-router/src/entries.tsx
index 10b7e865..4fd7ab79 100644
--- a/examples/22_define-router/src/entries.tsx
+++ b/examples/22_define-router/src/entries.tsx
@@ -1,4 +1,4 @@
-import { new_defineRouter } from 'waku/router/server';
+import { unstable_defineRouter } from 'waku/router/server';
 import { Slot, Children } from 'waku/minimal/client';
 
 import Root from './components/Root';
@@ -8,7 +8,7 @@ import FooPage from './components/FooPage';
 import BarPage from './components/BarPage';
 import NestedBazPage from './components/NestedBazPage';
 
-export default new_defineRouter({
+export default unstable_defineRouter({
   getPathConfig: async () => {
     return [
       {
diff --git a/examples/22_define-router/src/main.tsx b/examples/22_define-router/src/main.tsx
index 6d204e3a..bddb502d 100644
--- a/examples/22_define-router/src/main.tsx
+++ b/examples/22_define-router/src/main.tsx
@@ -1,10 +1,10 @@
 import { StrictMode } from 'react';
 import { createRoot, hydrateRoot } from 'react-dom/client';
-import { NewRouter } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = (
   <StrictMode>
-    <NewRouter />
+    <Router />
   </StrictMode>
 );
 
diff --git a/examples/42_react-tweet/src/main.tsx b/examples/42_react-tweet/src/main.tsx
index 354c5d2f..bddb502d 100644
--- a/examples/42_react-tweet/src/main.tsx
+++ b/examples/42_react-tweet/src/main.tsx
@@ -1,6 +1,6 @@
 import { StrictMode } from 'react';
 import { createRoot, hydrateRoot } from 'react-dom/client';
-import { NewRouter as Router } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = (
   <StrictMode>
diff --git a/examples/43_weave-render/src/main.tsx b/examples/43_weave-render/src/main.tsx
index 354c5d2f..bddb502d 100644
--- a/examples/43_weave-render/src/main.tsx
+++ b/examples/43_weave-render/src/main.tsx
@@ -1,6 +1,6 @@
 import { StrictMode } from 'react';
 import { createRoot, hydrateRoot } from 'react-dom/client';
-import { NewRouter as Router } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = (
   <StrictMode>
diff --git a/packages/waku/src/lib/plugins/vite-plugin-rsc-managed.ts b/packages/waku/src/lib/plugins/vite-plugin-rsc-managed.ts
index b99c6059..9c03e28b 100644
--- a/packages/waku/src/lib/plugins/vite-plugin-rsc-managed.ts
+++ b/packages/waku/src/lib/plugins/vite-plugin-rsc-managed.ts
@@ -22,7 +22,7 @@ export default fsRouter(
 const getManagedMain = () => `
 import { StrictMode, createElement } from 'react';
 import { createRoot, hydrateRoot } from 'react-dom/client';
-import { NewRouter as Router } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = createElement(StrictMode, null, createElement(Router));
 
diff --git a/packages/waku/src/router/client.ts b/packages/waku/src/router/client.ts
index 02d1c2f3..e9ddec9e 100644
--- a/packages/waku/src/router/client.ts
+++ b/packages/waku/src/router/client.ts
@@ -16,7 +16,6 @@ import {
 import type {
   ComponentProps,
   FunctionComponent,
-  MutableRefObject,
   ReactNode,
   AnchorHTMLAttributes,
   ReactElement,
@@ -31,14 +30,12 @@ import {
   useRefetch,
 } from '../minimal/client.js';
 import {
-  getComponentIds,
   encodeRoutePath,
-  SHOULD_SKIP_ID,
   ROUTE_ID,
   IS_STATIC_ID,
   HAS404_ID,
 } from './common.js';
-import type { RouteProps, ShouldSkip } from './common.js';
+import type { RouteProps } from './common.js';
 import type { RouteConfig } from './base-types.js';
 
 type InferredPaths = RouteConfig extends {
@@ -271,336 +268,10 @@ export function Link({
   return ele;
 }
 
-const getSkipList = (
-  shouldSkip: ShouldSkip | undefined,
-  componentIds: readonly string[],
-  route: RouteProps,
-  cached: Record<string, RouteProps>,
-): string[] => {
-  const shouldSkipObj = Object.fromEntries(shouldSkip || []);
-  return componentIds.filter((id) => {
-    const prevProps = cached[id];
-    if (!prevProps) {
-      return false;
-    }
-    const shouldCheck = shouldSkipObj[id];
-    if (!shouldCheck) {
-      return false;
-    }
-    if (shouldCheck[0] && route.path !== prevProps.path) {
-      return false;
-    }
-    if (shouldCheck[1] && route.query !== prevProps.query) {
-      return false;
-    }
-    return true;
-  });
-};
-
-const equalRouteProps = (a: RouteProps, b: RouteProps) => {
-  if (a.path !== b.path) {
-    return false;
-  }
-  if (a.query !== b.query) {
-    return false;
-  }
-  return true;
-};
-
-const RouterSlot = ({
-  route,
-  routerData,
-  cachedRef,
-  id,
-  fallback,
-  children,
-}: {
-  route: RouteProps;
-  routerData: RouterData;
-  cachedRef: MutableRefObject<Record<string, RouteProps>>;
-  id: string;
-  fallback?: ReactNode;
-  children?: ReactNode;
-}) => {
-  const unstable_shouldRenderPrev = () => {
-    const shouldSkip = routerData[0];
-    const skip = getSkipList(shouldSkip, [id], route, cachedRef.current);
-    return skip.length > 0;
-  };
-  return createElement(
-    Slot,
-    { id, fallback, unstable_shouldRenderPrev },
-    children,
-  );
-};
-
-const InnerRouter = ({ routerData }: { routerData: RouterData }) => {
-  const refetch = useRefetch();
-
-  const initialRouteRef = useRef<RouteProps>();
-  if (!initialRouteRef.current) {
-    initialRouteRef.current = parseRouteFromLocation();
-  }
-  const [route, setRoute] = useState(() => ({
-    // This is the first initialization of the route, and it has
-    // to ignore the hash, because on server side there is none.
-    // Otherwise there will be a hydration error.
-    // The client side route, including the hash, will be updated in the effect below.
-    ...initialRouteRef.current!,
-    hash: '',
-  }));
-  // Update the route post-load to include the current hash.
-  useEffect(() => {
-    const initialRoute = initialRouteRef.current!;
-    setRoute((prev) => {
-      if (
-        prev.path === initialRoute.path &&
-        prev.query === initialRoute.query &&
-        prev.hash === initialRoute.hash
-      ) {
-        return prev;
-      }
-      return initialRoute;
-    });
-  }, []);
-
-  const componentIds = getComponentIds(route.path);
-
-  const [cached, setCached] = useState<Record<string, RouteProps>>(() => {
-    return Object.fromEntries(componentIds.map((id) => [id, route]));
-  });
-  const cachedRef = useRef(cached);
-  useEffect(() => {
-    cachedRef.current = cached;
-  }, [cached]);
-
-  const changeRoute: ChangeRoute = useCallback(
-    (route, options) => {
-      const { checkCache, skipRefetch } = options || {};
-      startTransition(() => {
-        setRoute(route);
-      });
-      const componentIds = getComponentIds(route.path);
-      if (
-        checkCache &&
-        componentIds.every((id) => {
-          const cachedLoc = cachedRef.current[id];
-          return cachedLoc && equalRouteProps(cachedLoc, route);
-        })
-      ) {
-        return; // everything is cached
-      }
-      const shouldSkip = routerData[0];
-      const skip = getSkipList(
-        shouldSkip,
-        componentIds,
-        route,
-        cachedRef.current,
-      );
-      if (componentIds.every((id) => skip.includes(id))) {
-        return; // everything is skipped
-      }
-      if (!skipRefetch) {
-        const rscPath = encodeRoutePath(route.path);
-        const rscParams = createRscParams(route.query, skip);
-        refetch(rscPath, rscParams);
-      }
-      startTransition(() => {
-        setCached((prev) => ({
-          ...prev,
-          ...Object.fromEntries(
-            componentIds.flatMap((id) =>
-              skip.includes(id) ? [] : [[id, route]],
-            ),
-          ),
-        }));
-      });
-    },
-    [refetch, routerData],
-  );
-
-  const prefetchRoute: PrefetchRoute = useCallback(
-    (route) => {
-      const componentIds = getComponentIds(route.path);
-      const shouldSkip = routerData[0];
-      const skip = getSkipList(
-        shouldSkip,
-        componentIds,
-        route,
-        cachedRef.current,
-      );
-      if (componentIds.every((id) => skip.includes(id))) {
-        return; // everything is cached
-      }
-      const rscPath = encodeRoutePath(route.path);
-      const rscParams = createRscParams(route.query, skip);
-      prefetchRsc(rscPath, rscParams);
-      (globalThis as any).__WAKU_ROUTER_PREFETCH__?.(route.path);
-    },
-    [routerData],
-  );
-
-  useEffect(() => {
-    const callback = () => {
-      const route = parseRoute(new URL(window.location.href));
-      changeRoute(route, { checkCache: true });
-    };
-    window.addEventListener('popstate', callback);
-    return () => {
-      window.removeEventListener('popstate', callback);
-    };
-  }, [changeRoute]);
-
-  useEffect(() => {
-    const callback = (path: string, query: string) => {
-      const url = new URL(window.location.href);
-      url.pathname = path;
-      url.search = query;
-      url.hash = '';
-      if (path !== '/404') {
-        window.history.pushState(
-          {
-            ...window.history.state,
-            waku_new_path: url.pathname !== window.location.pathname,
-          },
-          '',
-          url,
-        );
-      }
-      changeRoute(parseRoute(url), { skipRefetch: true });
-    };
-    const listeners = (routerData[1] ||= new Set());
-    listeners.add(callback);
-    return () => {
-      listeners.delete(callback);
-    };
-  }, [changeRoute, routerData]);
-
-  useEffect(() => {
-    const { hash } = window.location;
-    const { state } = window.history;
-    const element = hash && document.getElementById(hash.slice(1));
-    window.scrollTo({
-      left: 0,
-      top: element ? element.getBoundingClientRect().top + window.scrollY : 0,
-      behavior: state?.waku_new_path ? 'instant' : 'auto',
-    });
-  });
-
-  const children = componentIds.reduceRight(
-    (acc: ReactNode, id) =>
-      createElement(
-        RouterSlot,
-        { route, routerData, cachedRef, id, fallback: acc },
-        acc,
-      ),
-    null,
-  );
-
-  return createElement(
-    RouterContext.Provider,
-    { value: { route, changeRoute, prefetchRoute } },
-    children,
-  );
-};
-
-// Note: The router data must be a stable mutable object (array).
-type RouterData = [
-  shouldSkip?: ShouldSkip,
-  locationListners?: Set<(path: string, query: string) => void>,
-  has404?: boolean,
-];
-
-const DEFAULT_ROUTER_DATA: RouterData = [];
-
-export function Router({ routerData = DEFAULT_ROUTER_DATA }) {
-  const route = parseRouteFromLocation();
-  const initialRscPath = encodeRoutePath(route.path);
-  const unstable_enhanceCreateData =
-    (
-      createData: (
-        responsePromise: Promise<Response>,
-      ) => Promise<Record<string, ReactNode>>,
-    ) =>
-    async (responsePromise: Promise<Response>) => {
-      const response = await responsePromise;
-      const has404 = routerData[2];
-      if (response.status === 404 && has404) {
-        // HACK this is still an experimental logic. It's very fragile.
-        // FIXME we should cache it if 404.txt is static.
-        return fetchRsc(encodeRoutePath('/404'));
-      }
-      const data = createData(responsePromise);
-      Promise.resolve(data)
-        .then((data) => {
-          if (data && typeof data === 'object') {
-            // We need to process SHOULD_SKIP_ID before LOCATION_ID
-            if (SHOULD_SKIP_ID in data) {
-              // TODO replacing the whole array is not ideal
-              routerData[0] = data[SHOULD_SKIP_ID] as ShouldSkip;
-            }
-            if (ROUTE_ID in data) {
-              const [path, query] = data[ROUTE_ID] as [string, string];
-              // FIXME this check here seems ad-hoc (less readable code)
-              if (
-                window.location.pathname !== path ||
-                window.location.search.replace(/^\?/, '') !== query
-              ) {
-                routerData[1]?.forEach((listener) => listener(path, query));
-              }
-            }
-            if (HAS404_ID in data) {
-              routerData[2] = true;
-            }
-          }
-        })
-        .catch(() => {});
-      return data;
-    };
-  const initialRscParams = createRscParams(route.query, []);
-  return createElement(
-    ErrorBoundary,
-    null,
-    createElement(
-      Root as FunctionComponent<Omit<ComponentProps<typeof Root>, 'children'>>,
-      { initialRscPath, initialRscParams, unstable_enhanceCreateData },
-      createElement(InnerRouter, { routerData }),
-    ),
-  );
-}
-
 const notAvailableInServer = (name: string) => () => {
   throw new Error(`${name} is not in the server`);
 };
 
-/**
- * ServerRouter for SSR
- * This is not a public API.
- */
-export function ServerRouter({
-  children,
-  route,
-}: {
-  children: ReactNode;
-  route: RouteProps;
-}) {
-  return createElement(
-    Fragment,
-    null,
-    createElement(
-      RouterContext.Provider,
-      {
-        value: {
-          route,
-          changeRoute: notAvailableInServer('changeRoute'),
-          prefetchRoute: notAvailableInServer('prefetchRoute'),
-        },
-      },
-      children,
-    ),
-  );
-}
-
 function renderError(message: string) {
   return createElement(
     'html',
@@ -635,7 +306,7 @@ class ErrorBoundary extends Component<
 }
 
 // -----------------------------------------------------
-// For new_defineRouter
+// For unstable_defineRouter
 // Eventually replaces Router and so on
 // -----------------------------------------------------
 
@@ -648,11 +319,11 @@ type NewChangeRoute = (
 
 const getRouteSlotId = (path: string) => 'route:' + path;
 
-const NewInnerRouter = ({
+const InnerRouter = ({
   routerData,
   initialRoute,
 }: {
-  routerData: Required<NewRouterData>;
+  routerData: Required<RouterData>;
   initialRoute: RouteProps;
 }) => {
   const [cachedIdSet, staticPathSet, locationListeners] = routerData;
@@ -777,17 +448,17 @@ const NewInnerRouter = ({
 };
 
 // Note: The router data must be a stable mutable object (array).
-type NewRouterData = [
+type RouterData = [
   cachedIdSet?: Set<string>,
   staticPathSet?: Set<string>,
   locationListeners?: Set<(path: string, query: string) => void>,
   has404?: boolean,
 ];
 
-const DEFAULT_NEW_ROUTER_DATA: NewRouterData = [];
+const DEFAULT_ROUTER_DATA: RouterData = [];
 
-export function NewRouter({
-  routerData = DEFAULT_NEW_ROUTER_DATA,
+export function Router({
+  routerData = DEFAULT_ROUTER_DATA,
   initialRoute = parseRouteFromLocation(),
 }) {
   const initialRscPath = encodeRoutePath(initialRoute.path);
@@ -850,8 +521,8 @@ export function NewRouter({
     createElement(
       Root as FunctionComponent<Omit<ComponentProps<typeof Root>, 'children'>>,
       { initialRscPath, initialRscParams, unstable_enhanceCreateData },
-      createElement(NewInnerRouter, {
-        routerData: routerData as Required<NewRouterData>,
+      createElement(InnerRouter, {
+        routerData: routerData as Required<RouterData>,
         initialRoute,
       }),
     ),
@@ -862,7 +533,7 @@ export function NewRouter({
  * ServerRouter for SSR
  * This is not a public API.
  */
-export function NewServerRouter({ route }: { route: RouteProps }) {
+export function ServerRouter({ route }: { route: RouteProps }) {
   const routeElement = createElement(Slot, { id: getRouteSlotId(route.path) });
   return createElement(
     Fragment,
diff --git a/packages/waku/src/router/create-pages.ts b/packages/waku/src/router/create-pages.ts
index 2d6e1757..eb541a01 100644
--- a/packages/waku/src/router/create-pages.ts
+++ b/packages/waku/src/router/create-pages.ts
@@ -1,7 +1,7 @@
 import { createElement } from 'react';
 import type { FunctionComponent, ReactNode } from 'react';
 
-import { new_defineRouter } from './define-router.js';
+import { unstable_defineRouter } from './define-router.js';
 import type { RouteProps } from './common.js';
 import {
   joinPath,
@@ -389,7 +389,7 @@ export const createPages = <
     );
   };
 
-  const definedRouter = new_defineRouter({
+  const definedRouter = unstable_defineRouter({
     getPathConfig: async () => {
       await configure();
       const paths: {
diff --git a/packages/waku/src/router/define-router.ts b/packages/waku/src/router/define-router.ts
index 71600bfc..edaa0c74 100644
--- a/packages/waku/src/router/define-router.ts
+++ b/packages/waku/src/router/define-router.ts
@@ -1,5 +1,5 @@
 import { createElement } from 'react';
-import type { ComponentProps, FunctionComponent, ReactNode } from 'react';
+import type { ReactNode } from 'react';
 
 import {
   defineEntries,
@@ -12,26 +12,16 @@ import type {
   GetBuildConfig,
   GetSsrConfig,
 } from '../minimal/server.js';
-import { Children, Slot } from '../minimal/client.js';
 import {
-  getComponentIds,
   encodeRoutePath,
   decodeRoutePath,
-  SHOULD_SKIP_ID,
   ROUTE_ID,
   IS_STATIC_ID,
   HAS404_ID,
 } from './common.js';
-import type { RouteProps, ShouldSkip } from './common.js';
 import { getPathMapping } from '../lib/utils/path.js';
 import type { PathSpec } from '../lib/utils/path.js';
-import { ServerRouter, NewServerRouter } from './client.js';
-
-type RoutePropsForLayout = Omit<RouteProps, 'query'> & {
-  children: ReactNode;
-};
-
-type ShouldSkipValue = ShouldSkip[number][1];
+import { ServerRouter } from './client.js';
 
 const isStringArray = (x: unknown): x is string[] =>
   Array.isArray(x) && x.every((y) => typeof y === 'string');
@@ -56,216 +46,6 @@ const parseRscParams = (
   return { query, skip };
 };
 
-export function unstable_defineRouter(
-  getPathConfig: () => Promise<
-    Iterable<{
-      pattern: string;
-      path: PathSpec;
-      isStatic?: boolean;
-      noSsr?: boolean;
-    }>
-  >,
-  getComponent: (
-    componentId: string, // "**/layout" or "**/page" or "root"
-    options: {
-      // TODO setShouldSkip API is too hard to understand
-      unstable_setShouldSkip: (val?: ShouldSkipValue) => void;
-    },
-  ) => Promise<
-    | FunctionComponent<RouteProps>
-    | FunctionComponent<RoutePropsForLayout>
-    | FunctionComponent<{ children: ReactNode }>
-    | null
-  >,
-): ReturnType<typeof defineEntries> {
-  const platformObject = unstable_getPlatformObject();
-  type MyPathConfig = {
-    pattern: string;
-    pathname: PathSpec;
-    isStatic?: boolean | undefined;
-    specs: { noSsr?: boolean; is404: boolean };
-  }[];
-  let cachedPathConfig: MyPathConfig | undefined;
-  const getMyPathConfig = async (): Promise<MyPathConfig> => {
-    const pathConfig = platformObject.buildData?.defineRouterPathConfigs;
-    if (pathConfig) {
-      return pathConfig as MyPathConfig;
-    }
-    if (!cachedPathConfig) {
-      cachedPathConfig = Array.from(await getPathConfig()).map((item) => {
-        const is404 =
-          item.path.length === 1 &&
-          item.path[0]!.type === 'literal' &&
-          item.path[0]!.name === '404';
-        return {
-          pattern: item.pattern,
-          pathname: item.path,
-          isStatic: item.isStatic,
-          specs: { is404, noSsr: !!item.noSsr },
-        };
-      });
-    }
-    return cachedPathConfig;
-  };
-  const existsPath = async (
-    pathname: string,
-  ): Promise<{
-    found: boolean;
-    has404: boolean;
-    noSsr?: boolean;
-  }> => {
-    const pathConfig = await getMyPathConfig();
-    const found = pathConfig.find(({ pathname: pathSpec }) =>
-      getPathMapping(pathSpec, pathname),
-    );
-    const has404 = pathConfig.some(({ specs: { is404 } }) => is404);
-    return found
-      ? {
-          found: true,
-          has404,
-          noSsr: !!found.specs.noSsr,
-        }
-      : {
-          found: false,
-          has404,
-        };
-  };
-  const renderEntries: RenderEntries = async (rscPath, { rscParams }) => {
-    const pathname = decodeRoutePath(rscPath);
-    const pathStatus = await existsPath(pathname);
-    if (!pathStatus.found) {
-      return null;
-    }
-    const shouldSkipObj: {
-      [componentId: ShouldSkip[number][0]]: ShouldSkip[number][1];
-    } = {};
-
-    const { query, skip } = parseRscParams(rscParams);
-    const componentIds = getComponentIds(pathname);
-    const entries: (readonly [string, ReactNode])[] = (
-      await Promise.all(
-        componentIds.map(async (id) => {
-          if (skip?.includes(id)) {
-            return [];
-          }
-          const setShouldSkip = (val?: ShouldSkipValue) => {
-            if (val) {
-              shouldSkipObj[id] = val;
-            } else {
-              delete shouldSkipObj[id];
-            }
-          };
-          const component = await getComponent(id, {
-            unstable_setShouldSkip: setShouldSkip,
-          });
-          if (!component) {
-            return [];
-          }
-          const element = createElement(
-            component as FunctionComponent<{
-              path: string;
-              query?: string;
-            }>,
-            id.endsWith('/layout')
-              ? { path: pathname }
-              : { path: pathname, query },
-            createElement(Children),
-          );
-          return [[id, element]] as const;
-        }),
-      )
-    ).flat();
-    entries.push([SHOULD_SKIP_ID, Object.entries(shouldSkipObj)]);
-    entries.push([ROUTE_ID, [pathname, query]]);
-    if (pathStatus.has404) {
-      entries.push([HAS404_ID, true]);
-    }
-    return Object.fromEntries(entries);
-  };
-
-  const getBuildConfig: GetBuildConfig = async (
-    unstable_collectClientModules,
-  ) => {
-    const pathConfig = await getMyPathConfig();
-    const path2moduleIds: Record<string, string[]> = {};
-
-    await Promise.all(
-      pathConfig.map(async ({ pathname: pathSpec, pattern }) => {
-        if (pathSpec.some(({ type }) => type !== 'literal')) {
-          return;
-        }
-        const pathname = '/' + pathSpec.map(({ name }) => name).join('/');
-        const rscPath = encodeRoutePath(pathname);
-        path2moduleIds[pattern] = await unstable_collectClientModules(rscPath);
-      }),
-    );
-
-    const customCode = `
-globalThis.__WAKU_ROUTER_PREFETCH__ = (path) => {
-  const path2ids = ${JSON.stringify(path2moduleIds)};
-  const pattern = Object.keys(path2ids).find((key) => new RegExp(key).test(path));
-  if (pattern && path2ids[pattern]) {
-    for (const id of path2ids[pattern] || []) {
-      import(id);
-    }
-  }
-};`;
-    const buildConfig: BuildConfig = [];
-    for (const { pathname: pathSpec, isStatic, specs } of pathConfig) {
-      const entries: BuildConfig[number]['entries'] = [];
-      if (pathSpec.every(({ type }) => type === 'literal')) {
-        const pathname = '/' + pathSpec.map(({ name }) => name).join('/');
-        const rscPath = encodeRoutePath(pathname);
-        entries.push({ rscPath, isStatic });
-      }
-      buildConfig.push({
-        pathname: pathSpec,
-        isStatic,
-        entries,
-        customCode:
-          customCode +
-          (specs.is404 ? 'globalThis.__WAKU_ROUTER_404__ = true;' : ''),
-      });
-    }
-    platformObject.buildData ||= {};
-    platformObject.buildData.defineRouterPathConfigs = pathConfig;
-    return buildConfig;
-  };
-
-  const getSsrConfig: GetSsrConfig = async (pathname, { searchParams }) => {
-    const pathStatus = await existsPath(pathname);
-    if (pathStatus.noSsr) {
-      return null;
-    }
-    if (!pathStatus.found) {
-      if (pathStatus.has404) {
-        pathname = '/404';
-      } else {
-        return null;
-      }
-    }
-    const componentIds = getComponentIds(pathname);
-    const rscPath = encodeRoutePath(pathname);
-    const html = createElement(
-      ServerRouter as FunctionComponent<
-        Omit<ComponentProps<typeof ServerRouter>, 'children'>
-      >,
-      { route: { path: pathname, query: searchParams.toString(), hash: '' } },
-      componentIds.reduceRight(
-        (acc: ReactNode, id) => createElement(Slot, { id, fallback: acc }, acc),
-        null,
-      ),
-    );
-    return {
-      rscPath,
-      rscParams: JSON.stringify({ query: searchParams.toString() }),
-      html,
-    };
-  };
-
-  return { renderEntries, getBuildConfig, getSsrConfig };
-}
-
 export function unstable_rerenderRoute(
   pathname: string,
   query?: string,
@@ -275,16 +55,11 @@ export function unstable_rerenderRoute(
   rerender(rscPath, { query, skip });
 }
 
-// -----------------------------------------------------
-// new_defineRouter
-// Eventually replaces unstable_defineRouter
-// -----------------------------------------------------
-
 type SlotId = string;
 
 const ROUTE_SLOT_ID_PREFIX = 'route:';
 
-export function new_defineRouter(fns: {
+export function unstable_defineRouter(fns: {
   getPathConfig: () => Promise<
     Iterable<{
       pattern: string; // TODO we should probably remove this and use path2regexp internally
@@ -482,7 +257,7 @@ globalThis.__WAKU_ROUTER_PREFETCH__ = (path) => {
       }
     }
     const rscPath = encodeRoutePath(pathname);
-    const html = createElement(NewServerRouter, {
+    const html = createElement(ServerRouter, {
       route: { path: pathname, query: searchParams.toString(), hash: '' },
     });
     return {
diff --git a/packages/waku/src/router/server.ts b/packages/waku/src/router/server.ts
index 559f506e..6c220c01 100644
--- a/packages/waku/src/router/server.ts
+++ b/packages/waku/src/router/server.ts
@@ -1,7 +1,6 @@
 export {
   unstable_defineRouter,
   unstable_rerenderRoute,
-  new_defineRouter,
 } from './define-router.js';
 export { createPages } from './create-pages.js';
 export { fsRouter } from './fs-router.js';


Test patch:
diff --git a/e2e/fixtures/render-type/src/main.tsx b/e2e/fixtures/render-type/src/main.tsx
index 403e67cd..c79446e7 100644
--- a/e2e/fixtures/render-type/src/main.tsx
+++ b/e2e/fixtures/render-type/src/main.tsx
@@ -1,6 +1,6 @@
 import { StrictMode } from 'react';
 import { createRoot, hydrateRoot } from 'react-dom/client';
-import { NewRouter as Router } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = (
   <StrictMode>
diff --git a/e2e/fixtures/rsc-router/src/entries.tsx b/e2e/fixtures/rsc-router/src/entries.tsx
index 36947834..300f9ce6 100644
--- a/e2e/fixtures/rsc-router/src/entries.tsx
+++ b/e2e/fixtures/rsc-router/src/entries.tsx
@@ -1,5 +1,5 @@
 import type { ReactNode } from 'react';
-import { new_defineRouter } from 'waku/router/server';
+import { unstable_defineRouter } from 'waku/router/server';
 import { Slot, Children } from 'waku/minimal/client';
 
 import Layout from './routes/layout.js';
@@ -12,7 +12,7 @@ const PATH_PAGE: Record<string, ReactNode> = {
   '/foo': <FooPage />,
 };
 
-export default new_defineRouter({
+export default unstable_defineRouter({
   getPathConfig: async () =>
     STATIC_PATHS.map((path) => ({
       pattern: `^${path}$`,
diff --git a/e2e/fixtures/rsc-router/src/main.tsx b/e2e/fixtures/rsc-router/src/main.tsx
index 89205e73..61bd5ec5 100644
--- a/e2e/fixtures/rsc-router/src/main.tsx
+++ b/e2e/fixtures/rsc-router/src/main.tsx
@@ -1,6 +1,6 @@
 import { StrictMode } from 'react';
 import { createRoot } from 'react-dom/client';
-import { NewRouter as Router } from 'waku/router/client';
+import { Router } from 'waku/router/client';
 
 const rootElement = (
   <StrictMode>
diff --git a/packages/waku/tests/create-pages.test.ts b/packages/waku/tests/create-pages.test.ts
index 012c1e87..0aff363e 100644
--- a/packages/waku/tests/create-pages.test.ts
+++ b/packages/waku/tests/create-pages.test.ts
@@ -12,7 +12,7 @@ import type {
   PathWithWildcard,
   StaticSlugRoutePathsTuple,
 } from '../src/router/create-pages.js';
-import { new_defineRouter } from '../src/router/define-router.js';
+import { unstable_defineRouter } from '../src/router/define-router.js';
 import type { PropsWithChildren } from 'react';
 import { expectType } from 'ts-expect';
 import type { TypeEqual } from 'ts-expect';
@@ -398,12 +398,12 @@ describe('type tests', () => {
   });
 });
 
-const defineRouterMock = new_defineRouter as MockedFunction<
-  typeof new_defineRouter
+const defineRouterMock = unstable_defineRouter as MockedFunction<
+  typeof unstable_defineRouter
 >;
 
 vi.mock('../src/router/define-router.js', () => ({
-  new_defineRouter: vi.fn(),
+  unstable_defineRouter: vi.fn(),
 }));
 
 beforeEach(() => {