fix(core): stable route sorting (#4331)

This commit is contained in:
Pim 2018-11-14 17:50:06 +01:00 committed by Clark Du
parent 3702dfe5dc
commit 846455e2f7
2 changed files with 73 additions and 52 deletions

View File

@ -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
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) 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
* *

View File

@ -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')