Skip to content

Commit

Permalink
feat: named imports (#594)
Browse files Browse the repository at this point in the history
* Update react.tsx

Allow named imports

* Update react.tsx

* Update lazy.md

* Update code-splitting.md

* Update code-splitting.md

* Create TestComponent.tsx

* Update createRoutes.test.ts
  • Loading branch information
orangeswim committed Jul 6, 2023
1 parent d8fe718 commit 99957c1
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 9 deletions.
9 changes: 8 additions & 1 deletion docs/api/react/lazy.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ export const expensiveRoute = new Route({
path: 'expensive',
component: lazy(() => import('./Expensive')),
})

export const expensiveNamedRoute = new Route({
getParentRoute: () => rootRoute,
path: 'expensive',
component: lazy(() => import('./Expensive'), "Expensive"),
})
```

**Options**

- `importer: () => Promise<{ default: SyncRouteComponent }>`
- `importer: () => Promise<T>`
- **Required**
- `namedImport: key of T = "default"`

**Returns**

Expand Down
12 changes: 12 additions & 0 deletions docs/guide/code-splitting.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ const route = new Route({

The `lazy` wrapper not only implements `React.lazy()`, but automatically sets up the component with a preload method and promise management for you.

### Handling Named exports with `lazy`

The `lazy` wrapper also allows you to easily load components that are named exports from a module. To use this functionality, you just need to provide the name of the exported component as a second argument to the lazy function:

```tsx
const route = new Route({
component: lazy(() => import('./MyComponent'), 'NamedExport'),
})
```

Type safety ensures that you are only able to provide valid named exports from the module, which helps to prevent runtime errors.

## Data Loader Splitting

Regardless of which data loading library you decide to go with, you may end up with a lot of data loaders that could potentially contribute to a large bundle size. If this is the case, you can code split your data loading logic using the Route's `loader` option:
Expand Down
12 changes: 12 additions & 0 deletions packages/router/__tests__/TestComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// TestComponent.tsx
import React from 'react';

const TestComponent: React.FC = () => {
return <div>Hello from TestComponent (default export)</div>;
};

export default TestComponent;

export const NamedComponent: React.FC = () => {
return <div>Hello from NamedComponent (named export)</div>;
};
8 changes: 8 additions & 0 deletions packages/router/__tests__/createRoutes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
AnyRoute,
Values,
Router,
lazy
} from '../src'

// Write a test
Expand Down Expand Up @@ -143,6 +144,12 @@ describe('everything', () => {
component: () => 'layout-b',
})

const testRoute = new Route({
getParentRout: () => rootRoute,
path: 'testPath',
component: lazy(() => import('./TestComponent'), 'NamedComponent'),
})

const routeTree = rootRoute.addChildren([
indexRoute,
testRoute,
Expand All @@ -153,6 +160,7 @@ describe('everything', () => {
]),
authenticatedRoute.addChildren([authenticatedIndexRoute]),
layoutRoute.addChildren([layoutARoute, layoutBRoute]),
testRoute,
])

type MyRoutesInfo = RoutesInfo<typeof routeTree>
Expand Down
22 changes: 14 additions & 8 deletions packages/router/src/react.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,27 @@ export type RouteComponent<TProps = {}> = SyncRouteComponent<TProps> & {
preload?: () => Promise<void>
}

export function lazy(
importer: () => Promise<{ default: SyncRouteComponent }>,
function lazy<T extends Record<string, SyncRouteComponent>>(
importer: () => Promise<T>,
exportName: keyof T = "default"
): RouteComponent {
const lazyComp = React.lazy(importer as any)
let preloaded: Promise<SyncRouteComponent>
const lazyComp = React.lazy(async () => {
const moduleExports = await importer();
const component = moduleExports[exportName];
return { default: component };
});

const finalComp = lazyComp as unknown as RouteComponent
let preloaded: Promise<SyncRouteComponent>;

const finalComp = lazyComp as unknown as RouteComponent;

finalComp.preload = async () => {
if (!preloaded) {
await importer()
await importer();
}
}
};

return finalComp
return finalComp;
}

export type LinkPropsOptions<
Expand Down

0 comments on commit 99957c1

Please sign in to comment.