Skip to content

Commit

Permalink
working in playground
Browse files Browse the repository at this point in the history
  • Loading branch information
pcattori committed Jun 6, 2024
1 parent 59ecf45 commit ba67e5a
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 17 deletions.
1 change: 1 addition & 0 deletions packages/react-router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,3 +405,4 @@ export {
decodeViaTurboStream as UNSAFE_decodeViaTurboStream,
SingleFetchRedirectSymbol as UNSAFE_SingleFetchRedirectSymbol,
} from "./lib/dom/ssr/single-fetch";
export { defineRoute } from "./lib/router/define-route";
5 changes: 4 additions & 1 deletion packages/react-router/lib/dom/ssr/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,10 @@ ${matches
.join("\n")}
window.__remixRouteModules = {${matches
.map(
(match, index) => `${JSON.stringify(match.route.id)}:route${index}`
(match, index) =>
`${JSON.stringify(
match.route.id
)}: { ...route${index}.default, default: route${index}.default.Component, Component: undefined}`
)
.join(",")}};
Expand Down
5 changes: 4 additions & 1 deletion packages/react-router/lib/dom/ssr/routeModules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,10 @@ export async function loadRouteModule(
}

try {
let routeModule = await import(/* webpackIgnore: true */ route.module);
let m = await import(/* webpackIgnore: true */ route.module);
console.log(m);
let { Component, ...routeModule } = m;
routeModule.default = Component;
routeModulesCache[route.id] = routeModule;
return routeModule;
} catch (error: unknown) {
Expand Down
30 changes: 27 additions & 3 deletions packages/react-router/lib/dom/ssr/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import { prefetchStyleLinks } from "./links";
import { RemixRootDefaultErrorBoundary } from "./errorBoundaries";
import { RemixRootDefaultHydrateFallback } from "./fallback";
import invariant from "./invariant";
import { useRouteError } from "../../hooks";
import {
useActionData,
useLoaderData,
useParams,
useRouteError,
} from "../../hooks";
import type { DataRouteObject } from "../../context";

export interface RouteManifest<Route> {
Expand Down Expand Up @@ -64,7 +69,22 @@ function getRouteComponents(
routeModule: RouteModule,
isSpaMode: boolean
) {
let Component = getRouteModuleComponent(routeModule);
let ComponentWithoutData = getRouteModuleComponent(routeModule);
let Component = ComponentWithoutData
? () => {
let params = useParams();
let data = useLoaderData();
let actionData = useActionData();
return (
<ComponentWithoutData
// @ts-expect-error
params={params}
data={data}
actionData={actionData}
/>
);
}
: undefined;
// HydrateFallback can only exist on the root route in SPA Mode
let HydrateFallback =
routeModule.HydrateFallback && (!isSpaMode || route.id === "root")
Expand Down Expand Up @@ -110,7 +130,11 @@ function getRouteComponents(
};
}

return { Component, ErrorBoundary, HydrateFallback };
return {
Component,
ErrorBoundary,
HydrateFallback,
};
}

export function createServerRoutes(
Expand Down
1 change: 1 addition & 0 deletions packages/react-router/lib/router/define-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type Component<P extends string, L extends Loader<P>> = (args: {
// loader -> data for component
// loader -> serverLoader for clientLoader -> data for component
// TODO: clientLoader and all the other route module export APIs (meta, handle, ErrorBoundary, etc.)
// TODO: `handle`, HydrateFallback, shouldRevalidate, Layout, meta, links
export const defineRoute = <
const P extends string,
L extends Loader<P>,
Expand Down
47 changes: 36 additions & 11 deletions packages/remix-dev/vite/define-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ function parseRoute(source: string) {
return ast;
}

// TODO: account for layout,
let fields = [
"meta",
"links",
"loader",
"clientLoader",
"action",
"clientAction",
"Component",
"ErrorBoundary",
"HydrateFallback",
"handle",
"shouldRevalidate",
] as const;

type Field = (typeof fields)[number];
Expand All @@ -42,7 +48,7 @@ function isField(field: string): field is Field {

type Analysis = Record<Field, FieldPath | null>;

export function parseRouteFields(source: string): string[] {
export function parseRouteFields(source: string): Field[] {
let ast = parseRoute(source);

let fieldNames: Field[] = [];
Expand Down Expand Up @@ -102,48 +108,63 @@ function analyzeRouteExport(
if (t.isCallExpression(route)) {
let routePath = path.get("declaration") as NodePath<t.CallExpression>;
if (!isDefineRoute(routePath)) {
return routePath.buildCodeFrameError("TODO");
return routePath.buildCodeFrameError(
"Default export of a route module must either be a literal object or a call to `defineRoute`"
);
}

if (routePath.node.arguments.length !== 1) {
return path.buildCodeFrameError(
`defineRoute must take exactly one argument`
"`defineRoute` must take exactly one argument"
);
}
let arg = routePath.node.arguments[0];
let argPath = path.get("arguments.0") as NodePath<t.ObjectExpression>;
let argPath = routePath.get("arguments.0") as NodePath<t.ObjectExpression>;
if (!t.isObjectExpression(arg)) {
return argPath.buildCodeFrameError(
"defineRoute argument must be a literal object"
"`defineRoute` argument must be a literal object"
);
}
return analyzeRoute(argPath);
}

return path.get("declaration").buildCodeFrameError("TODO");
return path
.get("declaration")
.buildCodeFrameError(
"Default export of a route module must be either a literal object or a call to `defineRoute`"
);
}

function analyzeRoute(path: NodePath<t.ObjectExpression>): Analysis {
let analysis: Analysis = {
meta: null,
links: null,
loader: null,
clientLoader: null,
action: null,
clientAction: null,
Component: null,
ErrorBoundary: null,
HydrateFallback: null,
handle: null,
shouldRevalidate: null,
};

for (let [i, property] of path.node.properties.entries()) {
if (!t.isObjectProperty(property) && !t.isObjectMethod(property)) {
let propertyPath = path.get(`properties.${i}`) as NodePath<t.Node>;
throw propertyPath.buildCodeFrameError("todo");
throw propertyPath.buildCodeFrameError(
"Route properties cannot have dynamically computed keys"
);
}

let propertyPath = path.get(`properties.${i}`) as NodePath<
t.ObjectProperty | t.ObjectMethod
>;
if (property.computed || !t.isIdentifier(property.key)) {
throw propertyPath.buildCodeFrameError("todo");
throw propertyPath.buildCodeFrameError(
"Route properties cannot have dynamically computed keys"
);
}

let key = property.key.name;
Expand All @@ -162,16 +183,20 @@ function analyzeRoute(path: NodePath<t.ObjectExpression>): Analysis {

function checkRouteParams(path: NodePath<t.ObjectProperty>) {
if (t.isObjectMethod(path.node)) {
throw path.buildCodeFrameError(`params must be statically analyzable`);
throw path.buildCodeFrameError(
"Route params must be a literal array of literal strings"
);
}
if (!t.isArrayExpression(path.node.value)) {
throw path.buildCodeFrameError(`params must be statically analyzable`);
throw path.buildCodeFrameError(
"Route params must be a literal array of literal strings"
);
}
for (let [i, element] of path.node.value.elements.entries()) {
if (!t.isStringLiteral(element)) {
let elementPath = path.get(`value.elements.${i}`) as NodePath<t.Node>;
throw elementPath.buildCodeFrameError(
`params must be statically analyzable`
"Route params must be a literal array of literal strings"
);
}
}
Expand Down
6 changes: 5 additions & 1 deletion packages/remix-dev/vite/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,11 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = (_config) => {
path: ${JSON.stringify(route.path)},
index: ${JSON.stringify(route.index)},
caseSensitive: ${JSON.stringify(route.caseSensitive)},
module: route${index}
module: {
...route${index}.default,
default: route${index}.default.Component,
Component: undefined,
}
}`;
})
.join(",\n ")}
Expand Down

0 comments on commit ba67e5a

Please sign in to comment.