mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-29 17:07:22 +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 { resolve } from 'path'
|
||||||
import globby from 'globby'
|
|
||||||
import { Builder } from './builder'
|
import { Builder } from './builder'
|
||||||
|
import { NuxtRoute, resolvePagesRoutes } from './pages'
|
||||||
export interface NuxtRoute {
|
|
||||||
name?: string
|
|
||||||
path: string
|
|
||||||
component: string
|
|
||||||
children?: NuxtRoute[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface NuxtApp {
|
export interface NuxtApp {
|
||||||
srcDir: string
|
srcDir: string
|
||||||
@ -18,122 +11,21 @@ export interface NuxtApp {
|
|||||||
// Scan project structure
|
// Scan project structure
|
||||||
export async function resolveApp (builder: Builder, srcDir: string): Promise<NuxtApp> {
|
export async function resolveApp (builder: Builder, srcDir: string): Promise<NuxtApp> {
|
||||||
const { nuxt } = builder
|
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') ||
|
nuxt.resolver.tryResolvePath('~/app') ||
|
||||||
resolve(nuxt.options.appDir, 'app.vue')
|
resolve(nuxt.options.appDir, 'app.vue')
|
||||||
|
|
||||||
const pagesPattern = `${nuxt.options.dir.pages}/**/*.{${nuxt.options.extensions.join(',')}}`
|
// Resolve pages/
|
||||||
const pages = await resolveFiles(builder, pagesPattern, srcDir)
|
app.routes.push(...await resolvePagesRoutes(builder, app))
|
||||||
const routes = buildRoutes(pages, srcDir, nuxt.options.dir.pages, nuxt.options.extensions)
|
|
||||||
|
|
||||||
console.log('routes', routes)
|
return app
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
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