Repository: remix-run/remix
Pull request #1347 (2022-01-04 19:12:40)

fix: sibling __layout routes conflict


Patch:
diff --git a/fixtures/gists-app/app/routes/__layout2.tsx b/fixtures/gists-app/app/routes/__layout2.tsx
new file mode 100644
index 000000000..96e61bf46
--- /dev/null
+++ b/fixtures/gists-app/app/routes/__layout2.tsx
@@ -0,0 +1,10 @@
+import { Outlet } from "remix";
+
+export default function LayoutTest2() {
+  return (
+    <div data-test-id="_layout">
+      <h1>Layout Test 2</h1>
+      <Outlet />
+    </div>
+  );
+}
diff --git a/fixtures/gists-app/app/routes/__layout2/with-layout2.tsx b/fixtures/gists-app/app/routes/__layout2/with-layout2.tsx
new file mode 100644
index 000000000..fa24fc879
--- /dev/null
+++ b/fixtures/gists-app/app/routes/__layout2/with-layout2.tsx
@@ -0,0 +1,7 @@
+export default function WithLayout() {
+  return (
+    <div>
+      <h1>Page inside layout</h1>
+    </div>
+  );
+}
diff --git a/packages/remix-dev/config/routesConvention.ts b/packages/remix-dev/config/routesConvention.ts
index b096a4093..2ff0143af 100644
--- a/packages/remix-dev/config/routesConvention.ts
+++ b/packages/remix-dev/config/routesConvention.ts
@@ -70,7 +70,7 @@ export function defineConventionalRoutes(
       let fullPath = createRoutePath(routeId.slice("routes".length + 1));
       let uniqueRouteId = (fullPath || "") + (isIndexRoute ? "?index" : "");
 
-      if (typeof uniqueRouteId !== "undefined") {
+      if (uniqueRouteId) {
         if (uniqueRoutes.has(uniqueRouteId)) {
           throw new Error(
             `Path ${JSON.stringify(fullPath)} defined by route ${JSON.stringify(
diff --git a/packages/remix-react/components.tsx b/packages/remix-react/components.tsx
index 3c5f96839..36dd4ae95 100644
--- a/packages/remix-react/components.tsx
+++ b/packages/remix-react/components.tsx
@@ -1182,10 +1182,13 @@ export function useMatches() {
   return matches.map(match => {
     let { pathname, params } = match;
     return {
+      id: match.route.id,
       pathname,
       params,
       data: routeData[match.route.id],
-      handle: routeModules[match.route.id].handle
+      // if the module fails to load or an error/response is thrown, the module
+      // won't be defined.
+      handle: routeModules[match.route.id]?.handle
     };
   });
 }


Test patch:
diff --git a/packages/remix-dev/__tests__/readConfig-test.ts b/packages/remix-dev/__tests__/readConfig-test.ts
index dad28fe42..0081ebb8a 100644
--- a/packages/remix-dev/__tests__/readConfig-test.ts
+++ b/packages/remix-dev/__tests__/readConfig-test.ts
@@ -86,6 +86,22 @@ describe("readConfig", () => {
             "parentId": "routes/__layout",
             "path": "with-layout",
           },
+          "routes/__layout2": Object {
+            "caseSensitive": undefined,
+            "file": "routes/__layout2.tsx",
+            "id": "routes/__layout2",
+            "index": undefined,
+            "parentId": "root",
+            "path": undefined,
+          },
+          "routes/__layout2/with-layout2": Object {
+            "caseSensitive": undefined,
+            "file": "routes/__layout2/with-layout2.tsx",
+            "id": "routes/__layout2/with-layout2",
+            "index": undefined,
+            "parentId": "routes/__layout2",
+            "path": "with-layout2",
+          },
           "routes/action-catches": Object {
             "caseSensitive": undefined,
             "file": "routes/action-catches.jsx",