mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
refactor(builder): split pages logic
This commit is contained in:
parent
d14d695190
commit
349fb37bda
@ -1,13 +1,6 @@
|
||||
import { resolve } from 'path'
|
||||
import globby from 'globby'
|
||||
import { Builder } from './builder'
|
||||
|
||||
export interface NuxtRoute {
|
||||
name?: string
|
||||
path: string
|
||||
component: string
|
||||
children?: NuxtRoute[]
|
||||
}
|
||||
import { NuxtRoute, resolvePagesRoutes } from './pages'
|
||||
|
||||
export interface NuxtApp {
|
||||
srcDir: string
|
||||
@ -18,122 +11,21 @@ export interface NuxtApp {
|
||||
// Scan project structure
|
||||
export async function resolveApp (builder: Builder, srcDir: string): Promise<NuxtApp> {
|
||||
const { nuxt } = builder
|
||||
// resolve App.vue
|
||||
const main = nuxt.resolver.tryResolvePath('~/App') ||
|
||||
|
||||
// Create base app object
|
||||
const app: NuxtApp = {
|
||||
srcDir,
|
||||
main: '',
|
||||
routes: []
|
||||
}
|
||||
|
||||
// Resolve App.vue
|
||||
app.main = nuxt.resolver.tryResolvePath('~/App') ||
|
||||
nuxt.resolver.tryResolvePath('~/app') ||
|
||||
resolve(nuxt.options.appDir, 'app.vue')
|
||||
|
||||
const pagesPattern = `${nuxt.options.dir.pages}/**/*.{${nuxt.options.extensions.join(',')}}`
|
||||
const pages = await resolveFiles(builder, pagesPattern, srcDir)
|
||||
const routes = buildRoutes(pages, srcDir, nuxt.options.dir.pages, nuxt.options.extensions)
|
||||
// Resolve pages/
|
||||
app.routes.push(...await resolvePagesRoutes(builder, app))
|
||||
|
||||
console.log('routes', routes)
|
||||
// TODO: Read pages/ and create routes
|
||||
// TODO: Detect store
|
||||
// Use hooks?
|
||||
// routes can be resolved with @nuxt/pages module to scan pages/ using a hook
|
||||
// Import plugins
|
||||
// Middleware
|
||||
// Layouts
|
||||
// etc.
|
||||
|
||||
return {
|
||||
srcDir,
|
||||
main,
|
||||
routes: []
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveFiles (builder: Builder, pattern: string, srcDir: string) {
|
||||
const { nuxt } = builder
|
||||
|
||||
return builder.ignore.filter(await globby(pattern, {
|
||||
cwd: srcDir,
|
||||
followSymbolicLinks: nuxt.options.build.followSymlinks
|
||||
}))
|
||||
}
|
||||
|
||||
const isDynamicRoute = (s: string) => /^\[.+\]$/.test(s)
|
||||
|
||||
export function buildRoutes (
|
||||
files: string[],
|
||||
srcDir: string,
|
||||
pagesDir: string,
|
||||
extensions: string[]
|
||||
) {
|
||||
const routes: NuxtRoute[] = []
|
||||
|
||||
for (const file of files) {
|
||||
const pathParts = file
|
||||
.replace(new RegExp(`^${pagesDir}`), '')
|
||||
.replace(new RegExp(`\\.(${extensions.join('|')})$`), '')
|
||||
.split('/')
|
||||
.slice(1) // removing the pagesDir means that the path begins with a '/'
|
||||
|
||||
const route: NuxtRoute = {
|
||||
name: '',
|
||||
path: '',
|
||||
component: resolve(srcDir, file)
|
||||
}
|
||||
|
||||
let parent = routes
|
||||
|
||||
for (let i = 0; i < pathParts.length; i++) {
|
||||
const part = pathParts[i]
|
||||
// Remove square brackets at the start and end.
|
||||
const isDynamicPart = isDynamicRoute(part)
|
||||
const normalizedPart = (isDynamicPart
|
||||
? part.replace(/^\[(\.{3})?/, '').replace(/\]$/, '')
|
||||
: part
|
||||
).toLowerCase()
|
||||
|
||||
route.name += route.name ? `-${normalizedPart}` : normalizedPart
|
||||
|
||||
const child = parent.find(
|
||||
parentRoute => parentRoute.name === route.name
|
||||
)
|
||||
if (child) {
|
||||
child.children = child.children || []
|
||||
parent = child.children
|
||||
route.path = ''
|
||||
} else if (normalizedPart === 'index' && !route.path) {
|
||||
route.path += '/'
|
||||
} else if (normalizedPart !== 'index') {
|
||||
if (isDynamicPart) {
|
||||
route.path += `/:${normalizedPart}`
|
||||
|
||||
// Catch-all route
|
||||
if (/^\[\.{3}/.test(part)) {
|
||||
route.path += '(.*)'
|
||||
} else if (i === pathParts.length - 1) {
|
||||
route.path += '?'
|
||||
}
|
||||
} else {
|
||||
route.path += `/${normalizedPart}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent.push(route)
|
||||
}
|
||||
|
||||
return prepareRoutes(routes)
|
||||
}
|
||||
|
||||
function prepareRoutes (routes: NuxtRoute[], hasParent = false) {
|
||||
for (const route of routes) {
|
||||
if (route.name) {
|
||||
route.name = route.name.replace(/-index$/, '')
|
||||
}
|
||||
|
||||
if (hasParent) {
|
||||
route.path = route.path.replace(/^\//, '').replace(/\?$/, '')
|
||||
}
|
||||
|
||||
if (route.children) {
|
||||
delete route.name
|
||||
route.children = prepareRoutes(route.children, true)
|
||||
}
|
||||
}
|
||||
return routes
|
||||
return app
|
||||
}
|
||||
|
98
packages/nuxt3/src/builder/pages.ts
Normal file
98
packages/nuxt3/src/builder/pages.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { resolve, extname, relative } from 'path'
|
||||
import { NuxtApp } from './app'
|
||||
import { resolveFiles } from './utils'
|
||||
|
||||
const isDynamicRoute = (s: string) => /^\[.+\]$/.test(s)
|
||||
|
||||
export interface NuxtRoute {
|
||||
name?: string
|
||||
path: string
|
||||
file: string
|
||||
children?: NuxtRoute[]
|
||||
}
|
||||
|
||||
export async function resolvePagesRoutes (builder, app: NuxtApp) {
|
||||
const { nuxt } = builder
|
||||
|
||||
// TODO: these variables should be overriable by app not global
|
||||
const pagesDirName = nuxt.options.dir.pages
|
||||
const extensions = nuxt.options.extensions
|
||||
|
||||
const pagesDir = resolve(app.srcDir, pagesDirName)
|
||||
const pagesPattern = `${pagesDirName}/**/*.{${extensions.join(',')}}`
|
||||
const files = await resolveFiles(builder, pagesPattern, app.srcDir)
|
||||
|
||||
const routes: NuxtRoute[] = []
|
||||
|
||||
for (const file of files) {
|
||||
const pathParts = relative(pagesDir, file)
|
||||
.replace(new RegExp(`${extname(file)}$`), '')
|
||||
.split('/')
|
||||
|
||||
const route: NuxtRoute = {
|
||||
name: '',
|
||||
path: '',
|
||||
file
|
||||
}
|
||||
|
||||
let parent = routes
|
||||
|
||||
for (let i = 0; i < pathParts.length; i++) {
|
||||
const part = pathParts[i]
|
||||
// Remove square brackets at the start and end.
|
||||
const isDynamicPart = isDynamicRoute(part)
|
||||
const normalizedPart = (isDynamicPart
|
||||
? part.replace(/^\[(\.{3})?/, '').replace(/\]$/, '')
|
||||
: part
|
||||
).toLowerCase()
|
||||
|
||||
route.name += route.name ? `-${normalizedPart}` : normalizedPart
|
||||
|
||||
const child = parent.find(
|
||||
parentRoute => parentRoute.name === route.name
|
||||
)
|
||||
if (child) {
|
||||
child.children = child.children || []
|
||||
parent = child.children
|
||||
route.path = ''
|
||||
} else if (normalizedPart === 'index' && !route.path) {
|
||||
route.path += '/'
|
||||
} else if (normalizedPart !== 'index') {
|
||||
if (isDynamicPart) {
|
||||
route.path += `/:${normalizedPart}`
|
||||
|
||||
// Catch-all route
|
||||
if (/^\[\.{3}/.test(part)) {
|
||||
route.path += '(.*)'
|
||||
} else if (i === pathParts.length - 1) {
|
||||
route.path += '?'
|
||||
}
|
||||
} else {
|
||||
route.path += `/${normalizedPart}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent.push(route)
|
||||
}
|
||||
|
||||
return prepareRoutes(routes)
|
||||
}
|
||||
|
||||
function prepareRoutes (routes: NuxtRoute[], hasParent = false) {
|
||||
for (const route of routes) {
|
||||
if (route.name) {
|
||||
route.name = route.name.replace(/-index$/, '')
|
||||
}
|
||||
|
||||
if (hasParent) {
|
||||
route.path = route.path.replace(/^\//, '').replace(/\?$/, '')
|
||||
}
|
||||
|
||||
if (route.children) {
|
||||
delete route.name
|
||||
route.children = prepareRoutes(route.children, true)
|
||||
}
|
||||
}
|
||||
return routes
|
||||
}
|
13
packages/nuxt3/src/builder/utils.ts
Normal file
13
packages/nuxt3/src/builder/utils.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { resolve } from 'path'
|
||||
import globby from 'globby'
|
||||
import { Builder } from './builder'
|
||||
|
||||
// TODO: move to core resolver
|
||||
export async function resolveFiles (builder: Builder, pattern: string, srcDir: string) {
|
||||
const { nuxt } = builder
|
||||
|
||||
return builder.ignore.filter(await globby(pattern, {
|
||||
cwd: srcDir,
|
||||
followSymbolicLinks: nuxt.options.build.followSymlinks
|
||||
})).map(p => resolve(srcDir, p))
|
||||
}
|
Loading…
Reference in New Issue
Block a user