mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-23 14:15:13 +00:00
fix(core): stable route sorting (#4331)
This commit is contained in:
parent
3702dfe5dc
commit
846455e2f7
@ -256,6 +256,65 @@ function cleanChildrenRoutes(routes, isChild = false) {
|
||||
return routes
|
||||
}
|
||||
|
||||
const DYNAMIC_ROUTE_REGEX = /^\/(:|\*)/
|
||||
|
||||
const sortRoutes = function sortRoutes(routes) {
|
||||
routes.sort((a, b) => {
|
||||
if (!a.path.length) {
|
||||
return -1
|
||||
}
|
||||
if (!b.path.length) {
|
||||
return 1
|
||||
}
|
||||
// Order: /static, /index, /:dynamic
|
||||
// Match exact route before index: /login before /index/_slug
|
||||
if (a.path === '/') {
|
||||
return DYNAMIC_ROUTE_REGEX.test(b.path) ? -1 : 1
|
||||
}
|
||||
if (b.path === '/') {
|
||||
return DYNAMIC_ROUTE_REGEX.test(a.path) ? 1 : -1
|
||||
}
|
||||
|
||||
let i
|
||||
let res = 0
|
||||
let y = 0
|
||||
let z = 0
|
||||
const _a = a.path.split('/')
|
||||
const _b = b.path.split('/')
|
||||
for (i = 0; i < _a.length; i++) {
|
||||
if (res !== 0) {
|
||||
break
|
||||
}
|
||||
y = _a[i] === '*' ? 2 : _a[i].includes(':') ? 1 : 0
|
||||
z = _b[i] === '*' ? 2 : _b[i].includes(':') ? 1 : 0
|
||||
res = y - z
|
||||
// If a.length >= b.length
|
||||
if (i === _b.length - 1 && res === 0) {
|
||||
// unless * found sort by level, then alphabetically
|
||||
res = _a[i] === '*' ? -1 : (
|
||||
_a.length === _b.length ? a.path.localeCompare(b.path) : (_a.length - _b.length)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (res === 0) {
|
||||
// unless * found sort by level, then alphabetically
|
||||
res = _a[i - 1] === '*' && _b[i] ? 1 : (
|
||||
_a.length === _b.length ? a.path.localeCompare(b.path) : (_a.length - _b.length)
|
||||
)
|
||||
}
|
||||
return res
|
||||
})
|
||||
|
||||
routes.forEach((route) => {
|
||||
if (route.children) {
|
||||
sortRoutes(route.children)
|
||||
}
|
||||
})
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
export const createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
||||
const routes = []
|
||||
files.forEach((file) => {
|
||||
@ -292,46 +351,10 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
||||
}
|
||||
}
|
||||
})
|
||||
// Order Routes path
|
||||
parent.push(route)
|
||||
parent.sort((a, b) => {
|
||||
if (!a.path.length) {
|
||||
return -1
|
||||
}
|
||||
if (!b.path.length) {
|
||||
return 1
|
||||
}
|
||||
// Order: /static, /index, /:dynamic
|
||||
// Match exact route before index: /login before /index/_slug
|
||||
if (a.path === '/') {
|
||||
return DYNAMIC_ROUTE_REGEX.test(b.path) ? -1 : 1
|
||||
}
|
||||
if (b.path === '/') {
|
||||
return DYNAMIC_ROUTE_REGEX.test(a.path) ? 1 : -1
|
||||
}
|
||||
})
|
||||
|
||||
let i
|
||||
let res = 0
|
||||
let y = 0
|
||||
let z = 0
|
||||
const _a = a.path.split('/')
|
||||
const _b = b.path.split('/')
|
||||
for (i = 0; i < _a.length; i++) {
|
||||
if (res !== 0) {
|
||||
break
|
||||
}
|
||||
y = _a[i] === '*' ? 2 : _a[i].includes(':') ? 1 : 0
|
||||
z = _b[i] === '*' ? 2 : _b[i].includes(':') ? 1 : 0
|
||||
res = y - z
|
||||
// If a.length >= b.length
|
||||
if (i === _b.length - 1 && res === 0) {
|
||||
// change order if * found
|
||||
res = _a[i] === '*' ? -1 : 1
|
||||
}
|
||||
}
|
||||
return res === 0 ? (_a[i - 1] === '*' && _b[i] ? 1 : -1) : res
|
||||
})
|
||||
})
|
||||
sortRoutes(routes)
|
||||
return cleanChildrenRoutes(routes)
|
||||
}
|
||||
|
||||
@ -381,8 +404,6 @@ const getRoutePathExtension = (key) => {
|
||||
return key
|
||||
}
|
||||
|
||||
const DYNAMIC_ROUTE_REGEX = /^\/(:|\*)/
|
||||
|
||||
/**
|
||||
* Wraps value in array if it is not already an array
|
||||
*
|
||||
|
@ -20,8 +20,16 @@ describe('dynamic routes', () => {
|
||||
)
|
||||
const routes = eval('( ' + routerFile + ')') // eslint-disable-line no-eval
|
||||
// pages/test/index.vue
|
||||
expect(routes[0].path).toBe('/test')
|
||||
expect(routes[0].name).toBe('test')
|
||||
expect(routes[0].path).toBe('/parent')
|
||||
expect(routes[0].name).toBeFalsy() // parent route has no name
|
||||
// pages/parent/*.vue
|
||||
expect(routes[0].children.length).toBe(3) // parent has 3 children
|
||||
expect(routes[0].children.map(r => r.path)).toEqual(['', 'child', 'teub'])
|
||||
expect(routes[0].children.map(r => r.name)).toEqual([
|
||||
'parent',
|
||||
'parent-child',
|
||||
'parent-teub'
|
||||
])
|
||||
// pages/posts.vue
|
||||
expect(routes[1].path).toBe('/posts')
|
||||
expect(routes[1].name).toBe('posts')
|
||||
@ -30,16 +38,8 @@ describe('dynamic routes', () => {
|
||||
expect(routes[1].children[0].path).toBe(':id?')
|
||||
expect(routes[1].children[0].name).toBe('posts-id')
|
||||
// pages/parent.vue
|
||||
expect(routes[2].path).toBe('/parent')
|
||||
expect(routes[2].name).toBeFalsy() // parent route has no name
|
||||
// pages/parent/*.vue
|
||||
expect(routes[2].children.length).toBe(3) // parent has 3 children
|
||||
expect(routes[2].children.map(r => r.path)).toEqual(['', 'teub', 'child'])
|
||||
expect(routes[2].children.map(r => r.name)).toEqual([
|
||||
'parent',
|
||||
'parent-teub',
|
||||
'parent-child'
|
||||
])
|
||||
expect(routes[2].path).toBe('/test')
|
||||
expect(routes[2].name).toBe('test')
|
||||
// pages/test/projects/index.vue
|
||||
expect(routes[3].path).toBe('/test/projects')
|
||||
expect(routes[3].name).toBe('test-projects')
|
||||
|
Loading…
Reference in New Issue
Block a user