Skip to content

Commit

Permalink
Add fs-routes and Remix adapter package (#11971)
Browse files Browse the repository at this point in the history
  • Loading branch information
markdalgleish authored Sep 11, 2024
1 parent aa37dd1 commit 6ccf92a
Show file tree
Hide file tree
Showing 38 changed files with 453 additions and 153 deletions.
12 changes: 6 additions & 6 deletions docs/start/routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ export const routes: RouteConfig = [

## File System Routes

If you prefer a file system routing convention, you can use the convention provided with Remix v2, but you can also make your own.
If you prefer a file system routing convention, the `@react-router/fs-routes` package provides support for [Remix-style flat routes.][route_file_naming]

```tsx filename=app/routes.ts
import { type RouteConfig } from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig = remixRoutes();
export const routes: RouteConfig = flatRoutes();
```

You can also mix routing conventions into a single array of routes.
Expand All @@ -52,11 +52,11 @@ import {
type RouteConfig,
route,
} from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig = [
// Provide Remix v2 file system routes
...(await remixRoutes()),
// Provide file system routes
...(await flatRoutes()),

// Then provide additional config routes
route("/can/still/add/more", "./more.tsx"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
let fixture: Fixture;
let appFixture: AppFixture;

test.describe("remix v2 routes", () => {
test.describe("fs-routes", () => {
test.beforeAll(async () => {
fixture = await createFixture({
files: {
Expand All @@ -27,17 +27,22 @@ test.describe("remix v2 routes", () => {
`,
"app/routes.ts": js`
import { type RouteConfig } from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";
import { remixConfigRoutes } from "@react-router/remix-config-routes-adapter";
export const routes: RouteConfig = remixRoutes({
ignoredRouteFiles: ["**/ignored-route.*"],
routes: async (defineRoutes) => {
export const routes: RouteConfig = [
...await flatRoutes({
ignoredRouteFiles: ["**/ignored-route.*"],
}),
// Ensure Remix back compat layer works
...await remixConfigRoutes(async (defineRoutes) => {
// Ensure async routes work
return defineRoutes((route) => {
route("/custom/route", "custom-route.tsx")
route("/remix/config/route", "remix-config-route.tsx")
});
}
});
})
];
`,
"app/root.tsx": js`
import { Links, Meta, Outlet, Scripts } from "react-router";
Expand Down Expand Up @@ -85,9 +90,9 @@ test.describe("remix v2 routes", () => {
}
`,

"app/custom-route.tsx": js`
"app/remix-config-route.tsx": js`
export default function () {
return <h2>Custom Route</h2>;
return <h2>Remix Config Route</h2>;
}
`,

Expand Down Expand Up @@ -186,12 +191,12 @@ test.describe("remix v2 routes", () => {
</div>`);
});

test("renders matching routes (custom route)", async ({ page }) => {
test("renders matching routes (Remix config route)", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/custom/route");
await app.goto("/remix/config/route");
expect(await app.getHtml("#content")).toBe(`<div id="content">
<h1>Root</h1>
<h2>Custom Route</h2>
<h2>Remix Config Route</h2>
</div>`);
});

Expand Down
4 changes: 2 additions & 2 deletions integration/helpers/node-template/app/routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type RouteConfig } from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig = remixRoutes();
export const routes: RouteConfig = flatRoutes();
3 changes: 2 additions & 1 deletion integration/helpers/node-template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
},
"devDependencies": {
"@react-router/dev": "workspace:*",
"@react-router/remix-v2-routes": "workspace:*",
"@react-router/fs-routes": "workspace:*",
"@react-router/remix-config-routes-adapter": "workspace:*",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"@vanilla-extract/css": "^1.10.0",
Expand Down
4 changes: 2 additions & 2 deletions integration/helpers/vite-cloudflare-template/app/routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type RouteConfig } from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig = remixRoutes();
export const routes: RouteConfig = flatRoutes();
3 changes: 2 additions & 1 deletion integration/helpers/vite-cloudflare-template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"devDependencies": {
"@cloudflare/workers-types": "^4.20230518.0",
"@react-router/dev": "workspace:*",
"@react-router/remix-v2-routes": "workspace:*",
"@react-router/fs-routes": "workspace:*",
"@react-router/remix-config-routes-adapter": "workspace:*",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"typescript": "^5.1.6",
Expand Down
4 changes: 2 additions & 2 deletions integration/helpers/vite-template/app/routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type RouteConfig } from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";

export const routes: RouteConfig = remixRoutes();
export const routes: RouteConfig = flatRoutes();
3 changes: 2 additions & 1 deletion integration/helpers/vite-template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
},
"devDependencies": {
"@react-router/dev": "workspace:*",
"@react-router/remix-v2-routes": "workspace:*",
"@react-router/fs-routes": "workspace:*",
"@react-router/remix-config-routes-adapter": "workspace:*",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"eslint": "^8.38.0",
Expand Down
8 changes: 4 additions & 4 deletions integration/vite-spa-mode-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,9 +504,9 @@ test.describe("SPA Mode", () => {
`,
"src/routes.ts": js`
import { type RouteConfig } from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";
export const routes: RouteConfig = remixRoutes();
export const routes: RouteConfig = flatRoutes();
`,
"src/root.tsx": js`
import {
Expand Down Expand Up @@ -593,9 +593,9 @@ test.describe("SPA Mode", () => {
`,
"src/routes.ts": js`
import { type RouteConfig } from "@react-router/dev/routes";
import { remixRoutes } from "@react-router/remix-v2-routes";
import { flatRoutes } from "@react-router/fs-routes";
export const routes: RouteConfig = remixRoutes();
export const routes: RouteConfig = flatRoutes();
`,
"src/root.tsx": js`
import {
Expand Down
7 changes: 7 additions & 0 deletions packages/react-router-fs-routes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# @react-router/fs-routes

File system routing conventions for [React Router.](https://github.com/remix-run/react-router)

```sh
npm i @react-router/fs-routes
```
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import path from "node:path";
import type { RouteManifestEntry } from "../manifest";

import {
fileRoutesUniversal,
flatRoutesUniversal,
getRoutePathConflictErrorMessage,
getRouteIdConflictErrorMessage,
getRouteSegments,
} from "../fileRoutes";
} from "../flatRoutes";
import { normalizeSlashes } from "../normalizeSlashes";

let APP_DIR = path.join("test", "root", "app");

describe("fileRoutes", () => {
describe("flatRoutes", () => {
describe("creates proper route paths", () => {
let tests: [string, string | undefined][] = [
["routes.$", "routes/*"],
Expand Down Expand Up @@ -81,7 +81,7 @@ describe("fileRoutes", () => {
["shop_.projects_.$id.roadmap", "shop/projects/:id/roadmap"],
];

let manifest = fileRoutesUniversal(
let manifest = flatRoutesUniversal(
APP_DIR,
tests.map((t) => path.join(APP_DIR, "routes", t[0] + ".tsx"))
);
Expand Down Expand Up @@ -631,7 +631,7 @@ describe("fileRoutes", () => {
}
);

let routeManifest = fileRoutesUniversal(
let routeManifest = flatRoutesUniversal(
APP_DIR,
files.map(([file]) => path.join(APP_DIR, file))
);
Expand Down Expand Up @@ -661,7 +661,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "sneakers.$sneakerId.tsx"),
];

let routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
let routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

let routes = Object.values(routeManifest);

Expand Down Expand Up @@ -691,7 +691,7 @@ describe("fileRoutes", () => {
// which uses the relative path from the app directory internally
let normalizedTestFiles = testFiles.map((file) => normalizeSlashes(file));

let routeManifest = fileRoutesUniversal(APP_DIR, fullPaths);
let routeManifest = flatRoutesUniversal(APP_DIR, fullPaths);

let routes = Object.values(routeManifest);

Expand All @@ -714,7 +714,7 @@ describe("fileRoutes", () => {
// which uses the relative path from the app directory internally
let normalizedTestFiles = testFiles.map((file) => normalizeSlashes(file));

let routeManifest = fileRoutesUniversal(APP_DIR, fullPaths);
let routeManifest = flatRoutesUniversal(APP_DIR, fullPaths);

let routes = Object.values(routeManifest);

Expand All @@ -727,22 +727,6 @@ describe("fileRoutes", () => {
);
});

test.skip("same path, different param name", () => {
let testFiles = [
path.join(APP_DIR, "routes", "products.$pid.tsx"),
path.join(APP_DIR, "routes", "products.$productId.tsx"),
];

let routeManifest = fileRoutesUniversal(APP_DIR, testFiles);

let routes = Object.values(routeManifest);

expect(routes).toHaveLength(1);
expect(consoleError).toHaveBeenCalledWith(
getRoutePathConflictErrorMessage("/products/:pid", testFiles)
);
});

test("pathless layouts should not collide", () => {
let testFiles = [
path.join(APP_DIR, "routes", "_a.tsx"),
Expand All @@ -752,7 +736,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "_b.b.tsx"),
];

let routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
let routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

let routes = Object.values(routeManifest);

Expand All @@ -768,7 +752,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "_b.b", "route.tsx"),
];

routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

routes = Object.values(routeManifest);

Expand All @@ -785,7 +769,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "nested._b.b.tsx"),
];

let routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
let routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

let routes = Object.values(routeManifest);

Expand All @@ -801,7 +785,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "nested._b.b", "route.tsx"),
];

routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

routes = Object.values(routeManifest);

Expand All @@ -817,7 +801,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "nested._b.a.tsx"),
];

let routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
let routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

let routes = Object.values(routeManifest);

Expand All @@ -838,7 +822,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "nested._b.a", "route.tsx"),
];

routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

routes = Object.values(routeManifest);

Expand All @@ -859,7 +843,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "nested._b._index.tsx"),
];

let routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
let routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

let routes = Object.values(routeManifest);

Expand All @@ -880,7 +864,7 @@ describe("fileRoutes", () => {
path.join(APP_DIR, "routes", "nested._b._index", "route.tsx"),
];

routeManifest = fileRoutesUniversal(APP_DIR, testFiles);
routeManifest = flatRoutesUniversal(APP_DIR, testFiles);

routes = Object.values(routeManifest);

Expand Down
Loading

0 comments on commit 6ccf92a

Please sign in to comment.