Last active
September 21, 2024 21:00
-
-
Save rhyek/9f18008e88563b27c5feb252fcd3e185 to your computer and use it in GitHub Desktop.
Next.js 13 App Router file-based routing in Remix (with Vite)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { existsSync } from 'node:fs'; | |
import path from 'node:path'; | |
import { vitePlugin as remix } from '@remix-run/dev'; | |
import { DefineRoutesFunction } from '@remix-run/dev/dist/config/routes'; | |
import * as glob from 'glob'; | |
import { defineConfig } from 'vite'; | |
import tsconfigPaths from 'vite-tsconfig-paths'; | |
export default defineConfig({ | |
plugins: [ | |
remix({ | |
future: { | |
v3_fetcherPersist: true, | |
v3_relativeSplatPath: true, | |
v3_throwAbortReason: true, | |
}, | |
ignoredRouteFiles: ['**/*'], | |
routes() { | |
const manifest: ReturnType<DefineRoutesFunction> = {}; | |
const appFolder = path.resolve(__dirname, 'app'); | |
const files = globSync('routes/**/{layout,page,route}.{tsx,ts}', { | |
cwd: appFolder, | |
}).sort(); | |
for (const file of files) { | |
let currentPath = file; | |
let foundLayout: string | null = null; | |
while (currentPath && currentPath !== 'routes') { | |
currentPath = path.dirname(currentPath); | |
const possibleLayouts = [ | |
path.join(currentPath, 'layout.ts'), | |
path.join(currentPath, 'layout.tsx'), | |
]; | |
for (const possibleLayout of possibleLayouts) { | |
if ( | |
file !== possibleLayout && | |
existsSync(path.resolve(appFolder, possibleLayout)) | |
) { | |
foundLayout = possibleLayout; | |
break; | |
} | |
} | |
if (foundLayout) { | |
break; | |
} | |
} | |
const id = path.join(path.dirname(file), path.parse(file).name); | |
const parentId = foundLayout | |
? path.join(path.dirname(foundLayout), path.parse(foundLayout).name) | |
: 'root'; | |
const diff = ( | |
parentId === 'root' | |
? path.dirname(id) | |
: path.dirname(id).split(path.dirname(parentId))[1] | |
)?.replace(/^routes/, ''); | |
const _path = | |
diff | |
?.split('/') | |
.map((part) => { | |
if (part.startsWith('$')) { | |
return `:${part.slice(1)}`; | |
} | |
const bracketedMatch = part.match(/^\[(.+)\]$/); | |
if (bracketedMatch) { | |
return `:${bracketedMatch[1]}`; | |
} | |
if (part.startsWith('_') || part.match(/^\(.+\)$/)) { | |
return null; | |
} | |
return part; | |
}) | |
.filter(Boolean) | |
.join('/') || undefined; | |
const index = | |
['page', 'route'].includes(path.parse(file).name) && | |
files.some( | |
(f) => | |
path.dirname(f) === path.dirname(file) && | |
path.parse(f).name === 'layout', | |
); | |
manifest[id] = { | |
id, | |
file, | |
path: index | |
? undefined | |
: _path | |
? _path | |
: path.parse(file).name === 'layout' | |
? '/' | |
: undefined, | |
parentId, | |
index, | |
}; | |
} | |
return manifest; | |
}, | |
}), | |
tsconfigPaths(), | |
], | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment