Skip to content

Commit

Permalink
Add routes-option-adapter package
Browse files Browse the repository at this point in the history
  • Loading branch information
markdalgleish authored Oct 17, 2024
1 parent 3c413ff commit 7601e67
Show file tree
Hide file tree
Showing 18 changed files with 292 additions and 76 deletions.
3 changes: 2 additions & 1 deletion integration/helpers/node-template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
},
"devDependencies": {
"@remix-run/dev": "workspace:*",
"@remix-run/route-config": "workspace:*",
"@remix-run/fs-routes": "workspace:*",
"@remix-run/route-config": "workspace:*",
"@remix-run/routes-option-adapter": "workspace:*",
"@vanilla-extract/css": "^1.10.0",
"@vanilla-extract/vite-plugin": "^3.9.2",
"@types/react": "^18.2.20",
Expand Down
38 changes: 33 additions & 5 deletions integration/vite-fs-routes-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,22 @@ test.describe("fs-routes", () => {
"app/routes.ts": js`
import { type RouteConfig } from "@remix-run/route-config";
import { flatRoutes } from "@remix-run/fs-routes";
export const routes: RouteConfig = flatRoutes({
rootDirectory: "fs-routes",
ignoredRouteFiles: ["**/ignored-route.*"],
});
import { routesOptionAdapter } from "@remix-run/routes-option-adapter";
export const routes: RouteConfig = [
...await flatRoutes({
rootDirectory: "fs-routes",
ignoredRouteFiles: ["**/ignored-route.*"],
}),
// Ensure back compat layer works
...await routesOptionAdapter(async (defineRoutes) => {
// Ensure async routes work
return defineRoutes((route) => {
route("/routes/option/adapter/route", "routes-option-adapter-route.tsx")
});
})
];
`,
"app/root.tsx": js`
import { Links, Meta, Outlet, Scripts } from "@remix-run/react";
Expand Down Expand Up @@ -81,6 +92,12 @@ test.describe("fs-routes", () => {
}
`,

"app/routes-option-adapter-route.tsx": js`
export default function () {
return <h2>Routes Option Adapter Route</h2>;
}
`,

"app/fs-routes/.dotfile": `
DOTFILE SHOULD BE IGNORED
`,
Expand Down Expand Up @@ -176,6 +193,17 @@ test.describe("fs-routes", () => {
</div>`);
});

test("renders matching routes (routes option adapter)", async ({
page,
}) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/routes/option/adapter/route");
expect(await app.getHtml("#content")).toBe(`<div id="content">
<h1>Root</h1>
<h2>Routes Option Adapter Route</h2>
</div>`);
});

test("renders matching routes (route with escaped leading dot)", async ({
page,
}) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { route } from "@remix-run/route-config";

import { routeManifestToRouteConfig } from "../manifest";
import { type RouteConfig, routeManifestToRouteConfig } from "../config/routes";

const clean = (obj: any) => cleanUndefined(cleanIds(obj));

Expand Down Expand Up @@ -43,14 +41,27 @@ describe("routeManifestToRouteConfig", () => {
caseSensitive: true,
},
});
let routeConfig = [
route("/", "routes/home.js"),
route("inbox", "routes/inbox.js", [
route("/", "routes/inbox/index.js", { index: true }),
route(":messageId", "routes/inbox/$messageId.js", {
caseSensitive: true,
}),
]),
let routeConfig: RouteConfig = [
{
path: "/",
file: "routes/home.js",
},
{
path: "inbox",
file: "routes/inbox.js",
children: [
{
path: "/",
file: "routes/inbox/index.js",
index: true,
},
{
path: ":messageId",
file: "routes/inbox/$messageId.js",
caseSensitive: true,
},
],
},
];

expect(clean(routeManifestConfig)).toEqual(clean(routeConfig));
Expand Down
39 changes: 39 additions & 0 deletions packages/remix-dev/config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,45 @@ export interface RouteManifest {
[routeId: string]: RouteManifestEntry;
}

export function routeManifestToRouteConfig(
routeManifest: RouteManifest,
rootId = "root"
): RouteConfigEntry[] {
let routeConfigById: {
[id: string]: Omit<RouteConfigEntry, "id"> &
Required<Pick<RouteConfigEntry, "id">>;
} = {};

for (let id in routeManifest) {
let route = routeManifest[id];
routeConfigById[id] = {
id: route.id,
file: route.file,
path: route.path,
index: route.index,
caseSensitive: route.caseSensitive,
};
}

let routeConfig: RouteConfigEntry[] = [];

for (let id in routeConfigById) {
let route = routeConfigById[id];
let parentId = routeManifest[route.id].parentId;
if (parentId === rootId) {
routeConfig.push(route);
} else {
let parentRoute = parentId && routeConfigById[parentId];
if (parentRoute) {
parentRoute.children = parentRoute.children || [];
parentRoute.children.push(route);
}
}
}

return routeConfig;
}

/**
* Configuration for an individual route, for use within `routes.ts`. As a
* convenience, route config entries can be created with the {@link route},
Expand Down
9 changes: 8 additions & 1 deletion packages/remix-dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ export * as cli from "./cli/index";

export type { Manifest as AssetsManifest } from "./manifest";
export type {
DefineRoutesFunction as UNSAFE_DefineRoutesFunction,
RouteManifest as UNSAFE_RouteManifest,
RouteManifestEntry as UNSAFE_RouteManifestEntry,
RouteConfig as UNSAFE_RouteConfig,
RouteConfigEntry as UNSAFE_RouteConfigEntry,
} from "./config/routes";
export { getRouteConfigAppDirectory as UNSAFE_getRouteConfigAppDirectory } from "./config/routes";
export {
defineRoutes as UNSAFE_defineRoutes,
routeManifestToRouteConfig as UNSAFE_routeManifestToRouteConfig,
getRouteConfigAppDirectory as UNSAFE_getRouteConfigAppDirectory,
} from "./config/routes";
export { getDependenciesToBundle } from "./dependencies";
export type {
BuildManifest,
Expand Down
5 changes: 4 additions & 1 deletion packages/remix-fs-routes/flatRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import fs from "node:fs";
import path from "node:path";
import { makeRe } from "minimatch";
import type {
UNSAFE_RouteManifest as RouteManifest,
UNSAFE_RouteManifestEntry as RouteManifestEntry,
} from "@remix-run/dev";

import type { RouteManifest, RouteManifestEntry } from "./manifest";
import { normalizeSlashes } from "./normalizeSlashes";

export const routeModuleExts = [".js", ".jsx", ".ts", ".tsx", ".md", ".mdx"];
Expand Down
2 changes: 1 addition & 1 deletion packages/remix-fs-routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import fs from "node:fs";
import path from "node:path";
import { UNSAFE_routeManifestToRouteConfig as routeManifestToRouteConfig } from "@remix-run/dev";
import {
type RouteConfigEntry,
getAppDirectory,
} from "@remix-run/route-config";

import { routeManifestToRouteConfig } from "./manifest";
import { flatRoutes as flatRoutesImpl } from "./flatRoutes";
import { normalizeSlashes } from "./normalizeSlashes";

Expand Down
53 changes: 0 additions & 53 deletions packages/remix-fs-routes/manifest.ts

This file was deleted.

4 changes: 3 additions & 1 deletion packages/remix-fs-routes/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@remix-run/fs-routes",
"version": "2.13.1",
"description": "Config-based file system routing conventions for Remix",
"description": "Config-based file system routing conventions, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/remix/issues"
},
Expand All @@ -27,10 +27,12 @@
"minimatch": "^9.0.0"
},
"devDependencies": {
"@remix-run/dev": "workspace:*",
"@remix-run/route-config": "workspace:*",
"typescript": "^5.1.6"
},
"peerDependencies": {
"@remix-run/dev": "workspace:*",
"@remix-run/route-config": "workspace:*",
"typescript": "^5.1.0"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/remix-route-config/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"name": "@remix-run/route-config",
"version": "2.13.1",
"description": "Config-based routing for Remix",
"description": "Config-based routing utilities, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/remix/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/remix-run/remix",
"directory": "packages/remix-fs-routes"
"directory": "packages/remix-route-config"
},
"license": "MIT",
"main": "dist/index.js",
Expand Down
13 changes: 13 additions & 0 deletions packages/remix-routes-option-adapter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Welcome to Remix!

[Remix](https://remix.run) is a web framework that helps you build better websites with React.

To get started, open a new shell and run:

```sh
npx create-remix@latest
```

Then follow the prompts you see in your terminal.

For more information about Remix, [visit remix.run](https://remix.run)!
24 changes: 24 additions & 0 deletions packages/remix-routes-option-adapter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {
type UNSAFE_DefineRoutesFunction as DefineRoutesFunction,
UNSAFE_defineRoutes as defineRoutes,
UNSAFE_routeManifestToRouteConfig as routeManifestToRouteConfig,
} from "@remix-run/dev";
import { type RouteConfigEntry } from "@remix-run/route-config";

export type { DefineRoutesFunction };

/**
* Adapter for [Remix's `routes` config
* option](https://remix.run/docs/en/v2/file-conventions/vite-config#routes),
* for use within `routes.ts`.
*/
export async function routesOptionAdapter(
routes: (
defineRoutes: DefineRoutesFunction
) =>
| ReturnType<DefineRoutesFunction>
| Promise<ReturnType<DefineRoutesFunction>>
): Promise<RouteConfigEntry[]> {
let routeManifest = await routes(defineRoutes);
return routeManifestToRouteConfig(routeManifest);
}
53 changes: 53 additions & 0 deletions packages/remix-routes-option-adapter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "@remix-run/routes-option-adapter",
"version": "2.13.1",
"description": "Adapter for Remix's \"routes\" config option, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/remix/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/remix-run/remix",
"directory": "packages/remix-routes-option-adapter"
},
"license": "MIT",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./package.json": "./package.json"
},
"scripts": {
"tsc": "tsc"
},
"dependencies": {
"minimatch": "^9.0.0"
},
"devDependencies": {
"@remix-run/dev": "workspace:*",
"@remix-run/route-config": "workspace:*",
"typescript": "^5.1.6"
},
"peerDependencies": {
"@remix-run/dev": "workspace:*",
"@remix-run/route-config": "workspace:*",
"typescript": "^5.1.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
},
"engines": {
"node": ">=18.0.0"
},
"files": [
"dist/",
"CHANGELOG.md",
"LICENSE.md",
"README.md"
]
}
Loading

0 comments on commit 7601e67

Please sign in to comment.