mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +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
|
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) {
|
export const createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
||||||
const routes = []
|
const routes = []
|
||||||
files.forEach((file) => {
|
files.forEach((file) => {
|
||||||
@ -292,46 +351,10 @@ export const createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Order Routes path
|
|
||||||
parent.push(route)
|
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
|
sortRoutes(routes)
|
||||||
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
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return cleanChildrenRoutes(routes)
|
return cleanChildrenRoutes(routes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,8 +404,6 @@ const getRoutePathExtension = (key) => {
|
|||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
const DYNAMIC_ROUTE_REGEX = /^\/(:|\*)/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps value in array if it is not already an array
|
* 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
|
const routes = eval('( ' + routerFile + ')') // eslint-disable-line no-eval
|
||||||
// pages/test/index.vue
|
// pages/test/index.vue
|
||||||
expect(routes[0].path).toBe('/test')
|
expect(routes[0].path).toBe('/parent')
|
||||||
expect(routes[0].name).toBe('test')
|
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
|
// pages/posts.vue
|
||||||
expect(routes[1].path).toBe('/posts')
|
expect(routes[1].path).toBe('/posts')
|
||||||
expect(routes[1].name).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].path).toBe(':id?')
|
||||||
expect(routes[1].children[0].name).toBe('posts-id')
|
expect(routes[1].children[0].name).toBe('posts-id')
|
||||||
// pages/parent.vue
|
// pages/parent.vue
|
||||||
expect(routes[2].path).toBe('/parent')
|
expect(routes[2].path).toBe('/test')
|
||||||
expect(routes[2].name).toBeFalsy() // parent route has no name
|
expect(routes[2].name).toBe('test')
|
||||||
// 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'
|
|
||||||
])
|
|
||||||
// pages/test/projects/index.vue
|
// pages/test/projects/index.vue
|
||||||
expect(routes[3].path).toBe('/test/projects')
|
expect(routes[3].path).toBe('/test/projects')
|
||||||
expect(routes[3].name).toBe('test-projects')
|
expect(routes[3].name).toBe('test-projects')
|
||||||
|
Loading…
Reference in New Issue
Block a user