Skip to content

Commit 213bb34

Browse files
authored
feat($core): redirects for clean urls (#1269)
1 parent 78cc60d commit 213bb34

File tree

2 files changed

+56
-10
lines changed

2 files changed

+56
-10
lines changed

packages/@vuepress/core/lib/app/app.js

+2-10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import appEnhancers from '@internal/app-enhancers'
88
import globalUIComponents from '@internal/global-ui'
99
import ClientComputedMixin from '@transform/ClientComputedMixin'
1010
import VuePress from './plugins/VuePress'
11+
import { handleRedirectForCleanUrls } from './redirect.js'
1112

1213
// built-in components
1314
import Content from './components/Content.js'
@@ -74,16 +75,7 @@ export function createApp (isServer) {
7475
}
7576
})
7677

77-
// redirect /foo to /foo/
78-
router.beforeEach((to, from, next) => {
79-
if (!/(\/|\.html)$/.test(to.path)) {
80-
next(Object.assign({}, to, {
81-
path: to.path + '/'
82-
}))
83-
} else {
84-
next()
85-
}
86-
})
78+
handleRedirectForCleanUrls(router)
8779

8880
const options = {}
8981

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// In VuePress, we have following convention about routing:
2+
//
3+
// - `/foo/` means source file is `/foo/{README|index}.md`
4+
// - `/foo.html` means your source file is `/foo.md`
5+
//
6+
// The original design of VuePress relied on above two styles
7+
// of routing, especially the calculation involved of routes at
8+
// default theme. so we can't easily modify `/foo.html` directly
9+
// to `/foo` (i.e. remove html suffix)
10+
//
11+
// This "temporary" utility handles redirect of clean urls, with
12+
// this utility, you'll get:
13+
//
14+
// For unknown request `/foo`
15+
// - redirect to `/foo.html` if it exists
16+
// - redirect to `/foo/` if it exists
17+
//
18+
// For unknown request `/foo/`
19+
// - redirect to `/foo.html` if it exists
20+
//
21+
// If all the above redirect rules don't exist, you'll get a 404
22+
23+
export function handleRedirectForCleanUrls (router) {
24+
router.beforeEach((to, from, next) => {
25+
if (isRouteExists(router, to.path)) {
26+
next()
27+
} else {
28+
if (!/(\/|\.html)$/.test(to.path)) {
29+
const endingSlashUrl = to.path + '/'
30+
const endingHtmlUrl = to.path + '.html'
31+
if (isRouteExists(router, endingHtmlUrl)) {
32+
next(endingHtmlUrl)
33+
} else if (isRouteExists(router, endingSlashUrl)) {
34+
next(endingSlashUrl)
35+
} else {
36+
next()
37+
}
38+
} else if (/\/$/.test(to.path)) {
39+
const endingHtmlUrl = to.path.replace(/\/$/, '') + '.html'
40+
if (isRouteExists(router, endingHtmlUrl)) {
41+
next(endingHtmlUrl)
42+
} else {
43+
next()
44+
}
45+
} else {
46+
next()
47+
}
48+
}
49+
})
50+
}
51+
52+
function isRouteExists (router, path) {
53+
return router.options.routes.filter(route => route.path === path).length > 0
54+
}

0 commit comments

Comments
 (0)