Skip to content

Commit 1bec18d

Browse files
handle 404 pages and 500 pages with nesting layout
1 parent 824a3cc commit 1bec18d

File tree

6 files changed

+62
-119
lines changed

6 files changed

+62
-119
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
21+
SOFTWARE.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-router-filebased",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"description": "",
55
"main": "./dist/cjs/index.js",
66
"module": "./dist/esm/index.js",

react-router-filebased-1.0.1.tgz

8.85 KB
Binary file not shown.

src/components/Provider/index.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import React from 'react'
2-
import { RouteObject, RouterProvider, createBrowserRouter } from 'react-router-dom'
2+
import { RouterProvider, createBrowserRouter } from 'react-router-dom'
33
import collectedRoutes from '../../utils/routesCollector'
44

5-
const router = createBrowserRouter(collectedRoutes as RouteObject[])
6-
5+
const routes = collectedRoutes()
6+
const router = createBrowserRouter(routes)
77
const FileBasedProvider = () => {
88
return <RouterProvider router={router} />
99
}
1010

11-
// const domNode = document.getElementById('root');
12-
// const root = createRoot(domNode);
13-
// root.render(<FileBasedProvider/>)
1411
export default FileBasedProvider

src/pages/index.jsx

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/utils/routesCollector.tsx

Lines changed: 57 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -7,132 +7,80 @@ type RouteConfig = {
77
element: ReactElement<any, string | JSXElementConstructor<any>>
88
}
99

10-
type LayoutMetaData = {
11-
[key: string]: ReactNode
10+
type LayoutRoutes = {
11+
[key: string]: { el: ReactNode; pathLength: number }
1212
}
1313

14-
type NotFoundMetaData = {
15-
[key: string]: ReactNode
14+
type NotFoundRoutes = {
15+
[key: string]: { el: ReactNode; pathLength: number }
1616
}
17-
type ErrorMetaData = {
18-
[key: string]: ReactNode
17+
type ErrorRoutes = {
18+
[key: string]: { el: ReactNode; pathLength: number }
1919
}
20-
21-
type NestedRoute = {
22-
errorElement?: ReactNode
23-
path: string
24-
key: string
25-
element: ReactNode | null
26-
children?: NestedRoute[]
27-
index?: boolean
28-
}
29-
30-
function getRoutes(r: any): RouteConfig[] {
31-
// console.log(r.keys(), 'routes')
20+
const getRoutes = (r: any): RouteConfig[] => {
3221
return r.keys().map((route: string) => {
3322
const path = route
3423
.substr(1)
3524
.replace(/\/src\/pages|index|\.(js|jsx|ts|tsx)$/g, '')
3625
.replace(/\[\.{3}.+\]/, '*')
3726
.replace(/\[(.+)\]/, ':$1')
38-
console.log({ React })
27+
3928
const Element = React.lazy(() => r(route))
4029

41-
return {
42-
path,
43-
element: <Element />,
44-
}
30+
return { path, element: <Element /> }
4531
})
4632
}
4733

48-
function getMetaData(key: string, routes: RouteConfig[]): LayoutMetaData | NotFoundMetaData {
49-
const data: LayoutMetaData | NotFoundMetaData = {}
50-
// debugger
34+
function getMetaData(key: string, routes: RouteConfig[]): LayoutRoutes | NotFoundRoutes {
35+
const data: LayoutRoutes | NotFoundRoutes = {}
5136

5237
routes
5338
.filter((route) => route.path.includes(key))
5439
.forEach((route) => {
5540
const splitied = route.path.split('/')
5641
const indexoF = splitied.indexOf(key)
57-
if (key === 'layout') {
58-
const newElement = cloneElement(route.element, {
59-
children: <Outlet />,
60-
})
61-
data[splitied[indexoF - 1]] = newElement
62-
} else {
63-
data[splitied[indexoF - 1]] = route.element
42+
const newElement = key === 'layout' ? cloneElement(route.element, { children: <Outlet /> }) : route.element
43+
44+
data[splitied[indexoF - 1]] = {
45+
el: newElement,
46+
pathLength: splitied.length,
6447
}
6548
})
49+
6650
return data
6751
}
6852

69-
const filterRoutes = (route: RouteConfig): boolean => !route.path.includes('layout') && !route.path.includes('layout')
70-
function nestedRoutes(routes: RouteConfig[]): NestedRoute[] {
71-
const layoutMetaData = getMetaData('layout', routes) as LayoutMetaData
72-
const errorMetaData = getMetaData('500', routes) as ErrorMetaData
73-
const notFoundMetaData = getMetaData('404', routes) as NotFoundMetaData
74-
const routesWithoutinfoPages = routes.filter(filterRoutes)
75-
const nested: NestedRoute[] | null = []
76-
routesWithoutinfoPages.forEach((route) => {
77-
console.log('2', route)
78-
53+
function nestedRoutes(mainRoutes: RouteConfig[], layoutRoutes: LayoutRoutes, errorRoutes: ErrorRoutes): RouteObject[] {
54+
const Loading = (
55+
<div className='h-screen w-full flex place-items-center justify-center'>
56+
<Loader />
57+
</div>
58+
)
59+
const nested: RouteObject[] | null = []
60+
mainRoutes.forEach((route) => {
7961
let currentNode = nested
8062
const splittedPath = route.path.split('/')
8163
splittedPath.forEach((part, i) => {
82-
let childNode = currentNode?.find((node) => node.path === part)
64+
const isLastCild = i === splittedPath.length - 1
8365

66+
let childNode = currentNode?.find((node) => node.path === part)
8467
if (!childNode) {
8568
childNode = {
86-
key: part,
8769
path: part === '404' ? '*' : part,
88-
element:
89-
i === splittedPath.length - 1 ? (
90-
<React.Suspense
91-
fallback={
92-
<div className='h-screen w-full flex place-items-center justify-center'>
93-
{' '}
94-
<Loader />{' '}
95-
</div>
96-
}
97-
>
98-
{' '}
99-
{route.element}
100-
</React.Suspense>
101-
) : layoutMetaData[part] ? (
102-
<React.Suspense
103-
fallback={
104-
<div className='h-screen w-full flex place-items-center justify-center'>
105-
{' '}
106-
<Loader />{' '}
107-
</div>
108-
}
109-
>
110-
{layoutMetaData[part]}
111-
</React.Suspense>
112-
) : (
113-
''
114-
),
115-
children: i === splittedPath.length - 1 ? undefined : [],
116-
}
117-
118-
if (notFoundMetaData[part]) {
119-
// childNode.errorElement = notFoundMetaData[part];
120-
if (!childNode.element) {
121-
childNode.element = notFoundMetaData[part]
122-
}
123-
}
124-
125-
if (errorMetaData[part]) {
126-
childNode.errorElement = errorMetaData[part]
127-
}
128-
129-
if (part === '' && i !== 0) {
130-
childNode.index = true
131-
// childNode.children=null
132-
}
133-
134-
if (i === 0) nested.push(childNode)
135-
else {
70+
element: isLastCild ? (
71+
<React.Suspense fallback={Loading}>{route.element}</React.Suspense>
72+
) : layoutRoutes[part] ? (
73+
<React.Suspense fallback={Loading}>{layoutRoutes[part].el}</React.Suspense>
74+
) : (
75+
''
76+
),
77+
children: isLastCild ? undefined : [],
78+
errorElement: Object.values(errorRoutes).find((e) => e.pathLength === splittedPath.length)?.el,
79+
} as RouteObject
80+
81+
if (i === 0) {
82+
nested.push(childNode)
83+
} else {
13684
currentNode.push(childNode)
13785
}
13886
}
@@ -143,13 +91,20 @@ function nestedRoutes(routes: RouteConfig[]): NestedRoute[] {
14391
})
14492
return nested
14593
}
146-
const requireAll = (require as any).context(
147-
'./../../../../../src/pages',
148-
true,
149-
/^\.\/(?!pages\/)[\w\/\[\]\-_]+\.(tsx|jsx)?$/,
150-
'lazy',
151-
)
15294

153-
const paths = getRoutes(requireAll)
154-
const collectedRoutes = nestedRoutes(paths) as RouteObject[]
155-
export default collectedRoutes
95+
export default function collectedRoutes(): RouteObject[] {
96+
const requireAll = (require as any).context(
97+
'./../../../../../src/pages',
98+
true,
99+
/^\.\/(?!pages\/)[\w\/\[\]\-_]+\.(tsx|jsx)?$/,
100+
'lazy',
101+
)
102+
const routes = getRoutes(requireAll)
103+
const layoutRoutes = getMetaData('layout', routes)
104+
const errorRoutes = getMetaData('500', routes)
105+
const mainRoutes = routes.filter(
106+
(route: RouteConfig): boolean => !route.path.includes('layout') && !route.path.includes('500'),
107+
)
108+
109+
return nestedRoutes(mainRoutes, layoutRoutes, errorRoutes) as RouteObject[]
110+
}

0 commit comments

Comments
 (0)