Repository: dai-shi/waku
Pull request #1039 (2024-12-07 06:35:22)

chore(create-pages): replace createPages with new_createPages
Removes old version of createPages in favor of new_createPages 

vercel[bot]: [vc]: #ZYQJ6p9qmoJvD60dhImU5DGBTFIvi0tDfl8iUxuioeU=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ3YWt1Iiwicm9vdERpcmVjdG9yeSI6bnVsbCwiaW5zcGVjdG9yVXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL2RhaXNoaXMtcHJvamVjdHMvd2FrdS9GeUxKaXU2a2pOTDNYRGpLbjVQZFVhQ2ZXb2JZIiwicHJldmlld1VybCI6Indha3UtZ2l0LWZvcmstdHlsZXJzYXlzaGktY2hvcmUtdXBkYXRlLTU5ODlhOC1kYWlzaGlzLXByb2plY3RzLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiUEVORElORyJ9XX0=
**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/FyLJiu6kjNL3XDjKn5PdUaCfWobY)) | [Visit Preview](https://waku-git-fork-tylersayshi-chore-update-5989a8-daishis-projects.vercel.app) | Dec 7, 2024 6:35am |


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/1039/builds/568175) or the icon next to each commit SHA.

Patch:
diff --git a/examples/21_create-pages/src/entries.tsx b/examples/21_create-pages/src/entries.tsx
index 9dcdbe81..26b01e99 100644
--- a/examples/21_create-pages/src/entries.tsx
+++ b/examples/21_create-pages/src/entries.tsx
@@ -1,4 +1,4 @@
-import { new_createPages } from 'waku';
+import { createPages } from 'waku';
 import type { PathsForPages } from 'waku/router';
 
 import FooPage from './components/FooPage';
@@ -9,93 +9,91 @@ import NestedBazPage from './components/NestedBazPage';
 import NestedQuxPage from './components/NestedQuxPage';
 import Root from './components/Root';
 
-const pages = new_createPages(
-  async ({ createPage, createLayout, createRoot }) => [
-    createRoot({
-      render: 'static',
-      component: Root,
-    }),
+const pages = createPages(async ({ createPage, createLayout, createRoot }) => [
+  createRoot({
+    render: 'static',
+    component: Root,
+  }),
 
-    createLayout({
-      render: 'static',
-      path: '/',
-      component: HomeLayout,
-    }),
+  createLayout({
+    render: 'static',
+    path: '/',
+    component: HomeLayout,
+  }),
 
-    createPage({
-      render: 'static',
-      path: '/',
-      component: HomePage,
-    }),
+  createPage({
+    render: 'static',
+    path: '/',
+    component: HomePage,
+  }),
 
-    createPage({
-      render: 'static',
-      path: '/foo',
-      component: FooPage,
-    }),
+  createPage({
+    render: 'static',
+    path: '/foo',
+    component: FooPage,
+  }),
 
-    createPage({
-      render: 'static',
-      path: '/bar',
-      component: BarPage,
-    }),
+  createPage({
+    render: 'static',
+    path: '/bar',
+    component: BarPage,
+  }),
 
-    createPage({
-      render: 'dynamic',
-      path: '/baz',
-      // Inline component is also possible.
-      component: () => <h2>Dynamic: Baz</h2>,
-    }),
+  createPage({
+    render: 'dynamic',
+    path: '/baz',
+    // Inline component is also possible.
+    component: () => <h2>Dynamic: Baz</h2>,
+  }),
 
-    createPage({
-      render: 'dynamic',
-      path: '/nested/baz',
-      component: NestedBazPage,
-    }),
+  createPage({
+    render: 'dynamic',
+    path: '/nested/baz',
+    component: NestedBazPage,
+  }),
 
-    createPage({
-      render: 'static',
-      path: '/nested/qux',
-      component: NestedQuxPage,
-    }),
+  createPage({
+    render: 'static',
+    path: '/nested/qux',
+    component: NestedQuxPage,
+  }),
 
-    createPage({
-      render: 'static',
-      path: '/nested/[id]',
-      staticPaths: ['foo', 'bar'],
-      component: ({ id }) => (
-        <>
-          <h2>Nested</h2>
-          <h3>Static: {id}</h3>
-        </>
-      ),
-    }),
+  createPage({
+    render: 'static',
+    path: '/nested/[id]',
+    staticPaths: ['foo', 'bar'],
+    component: ({ id }) => (
+      <>
+        <h2>Nested</h2>
+        <h3>Static: {id}</h3>
+      </>
+    ),
+  }),
 
-    createPage({
-      render: 'dynamic',
-      path: '/nested/[id]',
-      component: ({ id }) => (
-        <>
-          <h2>Nested</h2>
-          <h3>Dynamic: {id}</h3>
-        </>
-      ),
-    }),
+  createPage({
+    render: 'dynamic',
+    path: '/nested/[id]',
+    component: ({ id }) => (
+      <>
+        <h2>Nested</h2>
+        <h3>Dynamic: {id}</h3>
+      </>
+    ),
+  }),
 
-    createPage({
-      render: 'dynamic',
-      path: '/any/[...all]',
-      component: ({ all }) => <h2>Catch-all: {all.join('/')}</h2>,
-    }),
+  createPage({
+    render: 'dynamic',
+    path: '/any/[...all]',
+    component: ({ all }) => <h2>Catch-all: {all.join('/')}</h2>,
+  }),
 
-    // Custom Not Found page
-    createPage({
-      render: 'static',
-      path: '/404',
-      component: () => <h2>Not Found</h2>,
-    }),
-  ],
-);
+  // Custom Not Found page
+  createPage({
+    render: 'static',
+    path: '/404',
+    component: () => <h2>Not Found</h2>,
+  }),
+]);
 
 declare module 'waku/router' {
   interface RouteConfig {
diff --git a/examples/42_react-tweet/src/entries.tsx b/examples/42_react-tweet/src/entries.tsx
index 37d1559b..055d9e6d 100644
--- a/examples/42_react-tweet/src/entries.tsx
+++ b/examples/42_react-tweet/src/entries.tsx
@@ -1,4 +1,4 @@
-import { new_createPages as createPages } from 'waku/router/server';
+import { createPages } from 'waku/router/server';
 
 import { RootLayout } from './templates/root-layout';
 import { HomePage } from './templates/home-page';
diff --git a/examples/43_weave-render/src/entries.tsx b/examples/43_weave-render/src/entries.tsx
index f756e371..46d027fe 100644
--- a/examples/43_weave-render/src/entries.tsx
+++ b/examples/43_weave-render/src/entries.tsx
@@ -1,4 +1,4 @@
-import { new_createPages as createPages } from 'waku/router/server';
+import { createPages } from 'waku/router/server';
 import type { PathsForPages } from 'waku/router';
 import FooPage from './components/FooPage';
 import BarPage from './components/BarPage';
diff --git a/packages/waku/src/main.react-server.ts b/packages/waku/src/main.react-server.ts
index ceecbfc4..f0e68761 100644
--- a/packages/waku/src/main.react-server.ts
+++ b/packages/waku/src/main.react-server.ts
@@ -1,5 +1,5 @@
 export { Link, useRouter_UNSTABLE } from 'waku/router/client';
 
-export { createPages, new_createPages } from 'waku/router/server';
+export { createPages } from 'waku/router/server';
 
 export { getEnv } from 'waku/server';
diff --git a/packages/waku/src/main.ts b/packages/waku/src/main.ts
index 43d69694..c93f57a0 100644
--- a/packages/waku/src/main.ts
+++ b/packages/waku/src/main.ts
@@ -2,7 +2,6 @@ export { Link, useRouter_UNSTABLE } from 'waku/router/client';
 
 import type {
   createPages as createPagesType,
-  new_createPages as new_createPagesType,
   getEnv as getEnvType,
 } from './main.react-server.js';
 
@@ -12,12 +11,6 @@ export const createPages: typeof createPagesType = () => {
   );
 };
 
-export const new_createPages: typeof new_createPagesType = () => {
-  throw new Error(
-    '`new_createPagesType` is only available in react-server environment',
-  );
-};
-
 export const getEnv: typeof getEnvType = () => {
   throw new Error('`getEnv` is only available in react-server environment');
 };
diff --git a/packages/waku/src/router/create-pages.ts b/packages/waku/src/router/create-pages.ts
index 37f855eb..2d6e1757 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, unstable_defineRouter } from './define-router.js';
+import { new_defineRouter } from './define-router.js';
 import type { RouteProps } from './common.js';
 import {
   joinPath,
@@ -17,19 +17,6 @@ import type {
 } from './create-pages-utils/inferred-path-types.js';
 import { Children, Slot, ThrowError_UNSTABLE } from '../minimal/client.js';
 
-const hasPathSpecPrefix = (prefix: PathSpec, path: PathSpec) => {
-  for (let i = 0; i < prefix.length; i++) {
-    if (
-      i >= path.length ||
-      prefix[i]!.type !== path[i]!.type ||
-      prefix[i]!.name !== path[i]!.name
-    ) {
-      return false;
-    }
-  }
-  return true;
-};
-
 const sanitizeSlug = (slug: string) =>
   slug.replace(/\./g, '').replace(/ /g, '-');
 
@@ -197,290 +184,7 @@ const createNestedElements = (
   );
 };
 
-export function createPages<
-  AllPages extends (AnyPage | ReturnType<CreateLayout>)[],
->(
-  fn: (fns: {
-    createPage: CreatePage;
-    createLayout: CreateLayout;
-    createRoot: CreateRoot;
-  }) => Promise<AllPages>,
-) {
-  let configured = false;
-
-  // TODO I think there's room for improvement to refactor these structures
-  const staticPathSet = new Set<[string, PathSpec]>();
-  const dynamicPagePathMap = new Map<
-    string,
-    [PathSpec, FunctionComponent<any>]
-  >();
-  const wildcardPagePathMap = new Map<
-    string,
-    [PathSpec, FunctionComponent<any>]
-  >();
-  const dynamicLayoutPathMap = new Map<
-    string,
-    [PathSpec, FunctionComponent<any>]
-  >();
-  const staticComponentMap = new Map<string, FunctionComponent<any>>();
-  let rootItem: RootItem | undefined = undefined;
-  const noSsrSet = new WeakSet<PathSpec>();
-
-  const registerStaticComponent = (
-    id: string,
-    component: FunctionComponent<any>,
-  ) => {
-    if (
-      staticComponentMap.has(id) &&
-      staticComponentMap.get(id) !== component
-    ) {
-      throw new Error(`Duplicated component for: ${id}`);
-    }
-    staticComponentMap.set(id, component);
-  };
-
-  const createPage: CreatePage = (page) => {
-    if (configured) {
-      throw new Error('createPage no longer available');
-    }
-    const pathSpec = parsePathWithSlug(page.path);
-    if (page.unstable_disableSSR) {
-      noSsrSet.add(pathSpec);
-    }
-    const { numSlugs, numWildcards } = (() => {
-      let numSlugs = 0;
-      let numWildcards = 0;
-      for (const slug of pathSpec) {
-        if (slug.type !== 'literal') {
-          numSlugs++;
-        }
-        if (slug.type === 'wildcard') {
-          numWildcards++;
-        }
-      }
-      return { numSlugs, numWildcards };
-    })();
-    if (page.render === 'static' && numSlugs === 0) {
-      staticPathSet.add([page.path, pathSpec]);
-      const id = joinPath(page.path, 'page').replace(/^\//, '');
-      registerStaticComponent(id, page.component);
-    } else if (
-      page.render === 'static' &&
-      numSlugs > 0 &&
-      'staticPaths' in page
-    ) {
-      const staticPaths = page.staticPaths.map((item) =>
-        (Array.isArray(item) ? item : [item]).map(sanitizeSlug),
-      );
-      for (const staticPath of staticPaths) {
-        if (staticPath.length !== numSlugs && numWildcards === 0) {
-          throw new Error('staticPaths does not match with slug pattern');
-        }
-        const mapping: Record<string, string | string[]> = {};
-        let slugIndex = 0;
-        const pathItems: string[] = [];
-        pathSpec.forEach(({ type, name }) => {
-          switch (type) {
-            case 'literal':
-              pathItems.push(name!);
-              break;
-            case 'wildcard':
-              mapping[name!] = staticPath.slice(slugIndex);
-              staticPath.slice(slugIndex++).forEach((slug) => {
-                pathItems.push(slug);
-              });
-              break;
-            case 'group':
-              pathItems.push(staticPath[slugIndex++]!);
-              mapping[name!] = pathItems[pathItems.length - 1]!;
-              break;
-          }
-        });
-        staticPathSet.add([
-          page.path,
-          pathItems.map((name) => ({ type: 'literal', name })),
-        ]);
-        const id = joinPath(...pathItems, 'page');
-        const WrappedComponent = (props: Record<string, unknown>) =>
-          createElement(page.component as any, { ...props, ...mapping });
-        registerStaticComponent(id, WrappedComponent);
-      }
-    } else if (page.render === 'dynamic' && numWildcards === 0) {
-      if (dynamicPagePathMap.has(page.path)) {
-        throw new Error(`Duplicated dynamic path: ${page.path}`);
-      }
-      dynamicPagePathMap.set(page.path, [pathSpec, page.component]);
-    } else if (page.render === 'dynamic' && numWildcards === 1) {
-      if (wildcardPagePathMap.has(page.path)) {
-        throw new Error(`Duplicated dynamic path: ${page.path}`);
-      }
-      wildcardPagePathMap.set(page.path, [pathSpec, page.component]);
-    } else {
-      throw new Error('Invalid page configuration');
-    }
-    return page as Exclude<typeof page, { path: never } | { render: never }>;
-  };
-
-  const createLayout: CreateLayout = (layout) => {
-    if (configured) {
-      throw new Error('createLayout no longer available');
-    }
-    if (layout.render === 'static') {
-      const id = joinPath(layout.path, 'layout').replace(/^\//, '');
-      registerStaticComponent(id, layout.component);
-    } else if (layout.render === 'dynamic') {
-      if (dynamicLayoutPathMap.has(layout.path)) {
-        throw new Error(`Duplicated dynamic path: ${layout.path}`);
-      }
-      const pathSpec = parsePathWithSlug(layout.path);
-      dynamicLayoutPathMap.set(layout.path, [pathSpec, layout.component]);
-    } else {
-      throw new Error('Invalid layout configuration');
-    }
-  };
-
-  const createRoot: CreateRoot = (root) => {
-    if (configured) {
-      throw new Error('createRoot no longer available');
-    }
-    if (rootItem) {
-      throw new Error(`Duplicated root component`);
-    }
-    if (root.render === 'static' || root.render === 'dynamic') {
-      rootItem = root;
-    } else {
-      throw new Error('Invalid root configuration');
-    }
-  };
-
-  let ready: Promise<AllPages | void> | undefined;
-  const configure = async () => {
-    if (!configured && !ready) {
-      ready = fn({ createPage, createLayout, createRoot });
-      await ready;
-      configured = true;
-    }
-    await ready;
-  };
-
-  const definedRouter = unstable_defineRouter(
-    async () => {
-      await configure();
-      const paths: {
-        pattern: string;
-        path: PathSpec;
-        isStatic: boolean;
-        noSsr: boolean;
-      }[] = [];
-      for (const [path, pathSpec] of staticPathSet) {
-        const noSsr = noSsrSet.has(pathSpec);
-        const isStatic = (() => {
-          for (const [_, [layoutPathSpec]] of dynamicLayoutPathMap) {
-            if (hasPathSpecPrefix(layoutPathSpec, pathSpec)) {
-              return false;
-            }
-          }
-          return true;
-        })();
-
-        paths.push({
-          pattern: path2regexp(parsePathWithSlug(path)),
-          path: pathSpec,
-          isStatic,
-          noSsr,
-        });
-      }
-      for (const [path, [pathSpec]] of dynamicPagePathMap) {
-        const noSsr = noSsrSet.has(pathSpec);
-        paths.push({
-          pattern: path2regexp(parsePathWithSlug(path)),
-          path: pathSpec,
-          isStatic: false,
-          noSsr,
-        });
-      }
-      for (const [path, [pathSpec]] of wildcardPagePathMap) {
-        const noSsr = noSsrSet.has(pathSpec);
-        paths.push({
-          pattern: path2regexp(parsePathWithSlug(path)),
-          path: pathSpec,
-          isStatic: false,
-          noSsr,
-        });
-      }
-      return paths;
-    },
-    async (id, { unstable_setShouldSkip }) => {
-      await configure();
-      if (id === 'root') {
-        if (rootItem?.render === 'dynamic') {
-          unstable_setShouldSkip();
-        } else {
-          unstable_setShouldSkip([]);
-        }
-        return rootItem?.component ?? DefaultRoot;
-      }
-      const staticComponent = staticComponentMap.get(id);
-      if (staticComponent) {
-        unstable_setShouldSkip([]);
-        return staticComponent;
-      }
-      for (const [_, [pathSpec, Component]] of dynamicPagePathMap) {
-        const mapping = getPathMapping(
-          [...pathSpec, { type: 'literal', name: 'page' }],
-          id,
-        );
-        if (mapping) {
-          if (Object.keys(mapping).length === 0) {
-            unstable_setShouldSkip();
-            return Component;
-          }
-          const WrappedComponent = (props: Record<string, unknown>) =>
-            createElement(Component, { ...props, ...mapping });
-          unstable_setShouldSkip();
-          return WrappedComponent;
-        }
-      }
-      for (const [_, [pathSpec, Component]] of wildcardPagePathMap) {
-        const mapping = getPathMapping(
-          [...pathSpec, { type: 'literal', name: 'page' }],
-          id,
-        );
-        if (mapping) {
-          const WrappedComponent = (props: Record<string, unknown>) =>
-            createElement(Component, { ...props, ...mapping });
-          unstable_setShouldSkip();
-          return WrappedComponent;
-        }
-      }
-      for (const [_, [pathSpec, Component]] of dynamicLayoutPathMap) {
-        const mapping = getPathMapping(
-          [...pathSpec, { type: 'literal', name: 'layout' }],
-          id,
-        );
-        if (mapping) {
-          if (Object.keys(mapping).length) {
-            throw new Error('[Bug] layout should not have slugs');
-          }
-          unstable_setShouldSkip();
-          return Component;
-        }
-      }
-      unstable_setShouldSkip([]); // negative cache
-      return null; // not found
-    },
-  );
-
-  return definedRouter as typeof definedRouter & {
-    /** This for type inference of the router only. We do not actually return anything for this type. */
-    DO_NOT_USE_pages: Exclude<
-      Exclude<Awaited<Exclude<typeof ready, undefined>>, void>[number],
-      void // createLayout returns void
-    >;
-  };
-}
-
-export const new_createPages = <
+export const createPages = <
   AllPages extends (AnyPage | ReturnType<CreateLayout>)[],
 >(
   fn: (fns: {
diff --git a/packages/waku/src/router/fs-router.ts b/packages/waku/src/router/fs-router.ts
index 46172123..a77ca891 100644
--- a/packages/waku/src/router/fs-router.ts
+++ b/packages/waku/src/router/fs-router.ts
@@ -1,5 +1,5 @@
 import { unstable_getPlatformObject } from '../server.js';
-import { new_createPages as createPages } from './create-pages.js';
+import { createPages } from './create-pages.js';
 
 import { EXTENSIONS } from '../lib/constants.js';
 
diff --git a/packages/waku/src/router/server.ts b/packages/waku/src/router/server.ts
index a18ee6dd..559f506e 100644
--- a/packages/waku/src/router/server.ts
+++ b/packages/waku/src/router/server.ts
@@ -3,5 +3,5 @@ export {
   unstable_rerenderRoute,
   new_defineRouter,
 } from './define-router.js';
-export { createPages, new_createPages } from './create-pages.js';
+export { createPages } from './create-pages.js';
 export { fsRouter } from './fs-router.js';


Test patch:
diff --git a/e2e/fixtures/render-type/src/entries.tsx b/e2e/fixtures/render-type/src/entries.tsx
index 27693e76..cee13f25 100644
--- a/e2e/fixtures/render-type/src/entries.tsx
+++ b/e2e/fixtures/render-type/src/entries.tsx
@@ -1,4 +1,4 @@
-import { new_createPages as createPages } from 'waku/router/server';
+import { createPages } from 'waku/router/server';
 
 import { ServerEcho } from './ServerEcho.js';
 import { ClientEcho } from './ClientEcho.js';
diff --git a/packages/waku/tests/create-pages.test.ts b/packages/waku/tests/create-pages.test.ts
index 60b781dd..012c1e87 100644
--- a/packages/waku/tests/create-pages.test.ts
+++ b/packages/waku/tests/create-pages.test.ts
@@ -1,6 +1,6 @@
 import { expect, vi, describe, it, beforeEach, assert } from 'vitest';
 import type { MockedFunction } from 'vitest';
-import { new_createPages as createPages } from '../src/router/create-pages.js';
+import { createPages } from '../src/router/create-pages.js';
 import type {
   CreateLayout,
   CreatePage,