[READ-ONLY] Mirror of https://github.com/danielroe/roe.dev. This is the code and content for my personal website, built in Nuxt. roe.dev
0

Configure Feed

Select the types of activity you want to include in your feed.

roe.dev / modules / router / index.ts
3.4 kB 128 lines
1import { statSync } from 'node:fs' 2import fsp from 'node:fs/promises' 3 4import { join, relative } from 'pathe' 5import { 6 genSafeVariableName, 7 genArrayFromRaw, 8 genDynamicImport, 9 genString, 10 genImport, 11} from 'knitwork' 12import { 13 addComponent, 14 addImports, 15 addTemplate, 16 addRouteMiddleware, 17 createResolver, 18 defineNuxtModule, 19 useNuxt, 20} from 'nuxt/kit' 21import { withLeadingSlash } from 'ufo' 22 23import { pageMeta } from '../shared/page-meta' 24 25export default defineNuxtModule({ 26 meta: { 27 name: 'custom-router', 28 }, 29 setup () { 30 const nuxt = useNuxt() 31 const resolver = createResolver(import.meta.url) 32 nuxt.options.pages = false 33 34 addImports({ 35 name: 'definePageMeta', 36 from: resolver.resolve('./runtime/route-composables'), 37 priority: 20, 38 }) 39 40 addImports({ 41 name: 'useRoute', 42 from: resolver.resolve('./runtime/route-composables'), 43 priority: 20, 44 }) 45 46 addImports({ 47 name: 'handleNavigationClicks', 48 from: resolver.resolve('./runtime/route-composables'), 49 }) 50 51 addComponent({ 52 filePath: resolver.resolve('./runtime/nuxt-link'), 53 name: 'NuxtLink', 54 priority: 20, 55 }) 56 57 addComponent({ 58 filePath: resolver.resolve('./runtime/NuxtPage.vue'), 59 name: 'NuxtPage', 60 priority: 20, 61 }) 62 63 addRouteMiddleware({ 64 name: 'path-params', 65 global: true, 66 path: resolver.resolve('./runtime/path.global.ts'), 67 }) 68 69 const pagesDir = resolver.resolve('../../app/pages') 70 const isAdminFile = (f: string) => 71 relative(pagesDir, f).split('/')[0] === 'admin' 72 73 addTemplate({ 74 filename: 'routes.mjs', 75 write: true, 76 async getContents () { 77 const files = await readRecursive(pagesDir) 78 const staticImports = files.filter(f => !isAdminFile(f)) 79 const componentNames = Object.fromEntries( 80 staticImports.map(f => [f, genSafeVariableName(f)]), 81 ) 82 const routes = files.map(f => { 83 const path = withLeadingSlash( 84 relative(pagesDir, f).replace( 85 /(\/?index)?\.vue$/, 86 '', 87 ), 88 ) 89 const isDynamic = path.includes('[') 90 return { 91 path: isDynamic 92 ? `/${path 93 .replace(/\[(.*)\]/g, '(?<$1>.+)') 94 .replace(/\//g, '\\/')}/` 95 : genString(path), 96 component: isAdminFile(f) 97 ? `defineAsyncComponent(${genDynamicImport(f, { interopDefault: true })})` 98 : componentNames[f], 99 meta: JSON.stringify(pageMeta[path] || {}), 100 _isDynamic: isDynamic, 101 } 102 }) 103 .sort((a, b) => Number(a._isDynamic) - Number(b._isDynamic)) 104 .map(({ _isDynamic, ...rest }) => rest) 105 106 return ` 107 import { defineAsyncComponent } from 'vue' 108 ${Object.entries(componentNames).map(([path, name]) => genImport(path, { name })).join('\n')} 109 export default ${genArrayFromRaw(routes)}` 110 }, 111 }) 112 }, 113}) 114 115async function readRecursive (dir: string) { 116 const files = await fsp.readdir(dir) 117 const result: string[] = [] 118 for (const file of files) { 119 const path = join(dir, file) 120 if (statSync(path).isDirectory()) { 121 result.push(...(await readRecursive(path))) 122 } 123 else { 124 result.push(path) 125 } 126 } 127 return result 128}