Skip to content

Commit f05b2e9

Browse files
committed
feat: add route option
1 parent 5a4700a commit f05b2e9

File tree

14 files changed

+89
-25
lines changed

14 files changed

+89
-25
lines changed

.eslintrc.cjs

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
module.exports = {
22
root: true,
33
extends: 'vuepress',
4+
5+
// FIXME: This should be added to `eslint-config-vuepress`
6+
globals: {
7+
__VUEPRESS_CLEAN_URL__: 'readonly',
8+
},
9+
410
overrides: [
511
{
612
files: ['*.ts', '*.vue', '*.cts'],

packages/bundler-vite/src/plugins/vuepressMainPlugin.ts

+1
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ const resolveDefine = async ({
203203
const define: UserConfig['define'] = {
204204
__VUEPRESS_VERSION__: JSON.stringify(app.version),
205205
__VUEPRESS_BASE__: JSON.stringify(app.options.base),
206+
__VUEPRESS_CLEAN_URL__: JSON.stringify(app.options.route.cleanUrl),
206207
__VUEPRESS_DEV__: JSON.stringify(!isBuild),
207208
__VUEPRESS_SSR__: JSON.stringify(isServer),
208209
// @see http://link.vuejs.org/feature-flags

packages/bundler-webpack/src/config/handlePluginDefine.ts

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const handlePluginDefine = async ({
2121
{
2222
__VUEPRESS_VERSION__: JSON.stringify(app.version),
2323
__VUEPRESS_BASE__: JSON.stringify(app.options.base),
24+
__VUEPRESS_CLEAN_URL__: JSON.stringify(app.options.route.cleanUrl),
2425
__VUEPRESS_DEV__: JSON.stringify(!isBuild),
2526
__VUEPRESS_SSR__: JSON.stringify(isServer),
2627
// @see http://link.vuejs.org/feature-flags

packages/cli/src/commands/dev/watchPageFiles.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const watchPageFiles = (app: App): FSWatcher[] => {
4141
app.pages.forEach((page) => addDeps(page))
4242

4343
// watch page files
44-
const pagesWatcher = chokidar.watch(app.options.pagePatterns, {
44+
const pagesWatcher = chokidar.watch(app.options.route.pagePatterns, {
4545
cwd: app.dir.source(),
4646
ignoreInitial: true,
4747
})

packages/client/src/router/resolveRoutePath.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import { redirects, routes } from '../internal/routes.js'
66
*/
77
export const resolveRoutePath = (path: string, current?: string): string => {
88
// normalized path
9-
const normalizedPath = normalizeRoutePath(path, current)
9+
const normalizedPath = normalizeRoutePath(
10+
path,
11+
current,
12+
__VUEPRESS_CLEAN_URL__,
13+
)
1014
if (routes.value[normalizedPath]) return normalizedPath
1115

1216
// encoded path

packages/client/types.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
declare const __VUEPRESS_VERSION__: string
22
declare const __VUEPRESS_BASE__: string
33
declare const __VUEPRESS_DEV__: boolean
4+
declare const __VUEPRESS_CLEAN_URL__: boolean
45
declare const __VUEPRESS_SSR__: boolean
56
declare const __VUE_HMR_RUNTIME__: Record<string, any>
67
declare const __VUE_OPTIONS_API__: boolean

packages/core/src/app/prepare/prepareRoutes.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,20 @@ if (import.meta.hot) {
2323
/**
2424
* Resolve page redirects
2525
*/
26-
const resolvePageRedirects = ({ path, pathInferred }: Page): string[] => {
26+
const resolvePageRedirects = (
27+
app: App,
28+
{ path, pathInferred }: Page,
29+
): string[] => {
2730
// paths that should redirect to this page, use set to dedupe
2831
const redirectsSet = new Set<string>()
2932

3033
// add redirect to the set when the redirect could not be normalized & encoded to the page path
3134
const addRedirect = (redirect: string): void => {
32-
const normalizedPath = normalizeRoutePath(redirect)
35+
const normalizedPath = normalizeRoutePath(
36+
redirect,
37+
'',
38+
app.options.route.cleanUrl,
39+
)
3340
if (normalizedPath === path) return
3441

3542
const encodedPath = encodeURI(normalizedPath)
@@ -56,7 +63,10 @@ export const redirects = JSON.parse(${JSON.stringify(
5663
JSON.stringify(
5764
Object.fromEntries(
5865
app.pages.flatMap((page) =>
59-
resolvePageRedirects(page).map((redirect) => [redirect, page.path]),
66+
resolvePageRedirects(app, page).map((redirect) => [
67+
redirect,
68+
page.path,
69+
]),
6070
),
6171
),
6272
),

packages/core/src/app/resolveAppOptions.ts

+15-4
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,16 @@ export const resolveAppOptions = ({
3838
bundler,
3939
debug = false,
4040
markdown = {},
41-
pagePatterns = ['**/*.md', '!.vuepress', '!node_modules'],
42-
permalinkPattern = null,
41+
pagePatterns: _pagePatterns,
42+
permalinkPattern: _permalinkPattern,
43+
route: {
44+
cleanUrl = false,
45+
pagePatterns = ['**/*.md', '!.vuepress', '!node_modules'],
46+
permalinkPattern = null,
47+
} = {
48+
pagePatterns: _pagePatterns,
49+
permalinkPattern: _permalinkPattern,
50+
},
4351
plugins = [],
4452
theme,
4553
}: AppConfig): AppOptions => ({
@@ -65,8 +73,11 @@ export const resolveAppOptions = ({
6573
bundler,
6674
debug,
6775
markdown,
68-
pagePatterns,
69-
permalinkPattern,
76+
route: {
77+
cleanUrl,
78+
pagePatterns,
79+
permalinkPattern,
80+
},
7081
plugins,
7182
theme,
7283
})

packages/core/src/app/resolveAppPages.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const resolveAppPages = async (app: App): Promise<Page[]> => {
1111
log('resolveAppPages start')
1212

1313
// resolve page absolute file paths according to the page patterns
14-
const pageFilePaths = await globby(app.options.pagePatterns, {
14+
const pageFilePaths = await globby(app.options.route.pagePatterns, {
1515
absolute: true,
1616
cwd: app.dir.source(),
1717
})

packages/core/src/page/inferPagePath.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ export const inferPagePath = ({
2323

2424
// infer page route path from file path
2525
// foo/bar.md -> /foo/bar.html
26-
const pathInferred = ensureLeadingSlash(filePathRelative)
27-
.replace(/\.md$/, '.html')
28-
.replace(/\/(README|index).html$/i, '/')
26+
let pathInferred = ensureLeadingSlash(filePathRelative).replace(
27+
/\/(README|index).md$/i,
28+
'/',
29+
)
30+
31+
if (pathInferred.endsWith('.md'))
32+
pathInferred =
33+
pathInferred.substring(0, pathInferred.length - 3) +
34+
(app.options.route.cleanUrl ? '' : '.html')
2935

3036
// resolve page locale path
3137
const pathLocale = resolveLocalePath(app.siteData.locales, pathInferred)

packages/core/src/types/app/options.ts

+20-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ import type { Bundler } from '../bundler.js'
55
import type { PluginConfig } from '../plugin.js'
66
import type { Theme } from '../theme.js'
77

8+
export interface RouteOptions {
9+
cleanUrl?: boolean
10+
pagePatterns?: string[]
11+
permalinkPattern?: string | null
12+
}
13+
814
/**
915
* Vuepress app common config that shared between dev and build
1016
*/
@@ -14,11 +20,9 @@ export interface AppConfigCommon extends Partial<SiteData> {
1420
temp?: string
1521
cache?: string
1622
public?: string
17-
1823
debug?: boolean
1924
markdown?: MarkdownOptions
20-
pagePatterns?: string[]
21-
permalinkPattern?: string | null
25+
route?: RouteOptions
2226
bundler: Bundler
2327
theme: Theme
2428
plugins?: PluginConfig
@@ -95,9 +99,20 @@ export interface AppConfigBuild {
9599
/**
96100
* Vuepress app config
97101
*/
98-
export type AppConfig = AppConfigCommon & AppConfigDev & AppConfigBuild
102+
export type AppConfig = AppConfigCommon &
103+
AppConfigDev &
104+
AppConfigBuild & {
105+
/** @deprecated use route.pagePatterns instead */
106+
pagePatterns?: string[]
107+
/** @deprecated use route.permalinkPattern instead */
108+
permalinkPattern?: string | null
109+
}
99110

100111
/**
101112
* Vuepress app options
102113
*/
103-
export type AppOptions = Required<AppConfig>
114+
export type AppOptions = Required<
115+
AppConfigCommon & AppConfigDev & AppConfigBuild
116+
> & {
117+
route: Required<RouteOptions>
118+
}

packages/core/tests/app/resolveAppOptions.spec.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,11 @@ describe('core > app > resolveAppOptions', () => {
3030
host: '0.0.0.0',
3131
port: 8080,
3232
open: false,
33-
pagePatterns: ['**/*.md', '!.vuepress', '!node_modules'],
34-
permalinkPattern: null,
33+
route: {
34+
cleanUrl: false,
35+
pagePatterns: ['**/*.md', '!.vuepress', '!node_modules'],
36+
permalinkPattern: null,
37+
},
3538
templateDev: path.normalize(
3639
require.resolve('@vuepress/client/templates/dev.html'),
3740
),

packages/shared/src/utils/inferRoutePath.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const inferRoutePath = (path: string): string => {
1+
export const inferRoutePath = (path: string, cleanUrl = false): string => {
22
// if the pathname is empty or ends with `/`, return as is
33
if (!path || path.endsWith('/')) return path
44

@@ -19,5 +19,7 @@ export const inferRoutePath = (path: string): string => {
1919
routePath = routePath.substring(0, routePath.length - 10)
2020
}
2121

22-
return routePath
22+
return cleanUrl && routePath.endsWith('html')
23+
? routePath.substring(0, routePath.length - 5)
24+
: routePath
2325
}

packages/shared/src/utils/normalizeRoutePath.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@ const FAKE_HOST = 'http://.'
55
/**
66
* Normalize the given path to the final route path
77
*/
8-
export const normalizeRoutePath = (path: string, current?: string): string => {
8+
export const normalizeRoutePath = (
9+
path: string,
10+
current = '',
11+
cleanUrl = false,
12+
): string => {
913
if (!path.startsWith('/') && current) {
1014
// the relative path should be resolved against the current path
1115
const loc = current.slice(0, current.lastIndexOf('/'))
1216

1317
const { pathname, search, hash } = new URL(`${loc}/${path}`, FAKE_HOST)
1418

15-
return inferRoutePath(pathname) + search + hash
19+
return inferRoutePath(pathname, cleanUrl) + search + hash
1620
}
1721

1822
const [pathname, ...queryAndHash] = path.split(/(\?|#)/)
1923

20-
return inferRoutePath(pathname) + queryAndHash.join('')
24+
return inferRoutePath(pathname, cleanUrl) + queryAndHash.join('')
2125
}

0 commit comments

Comments
 (0)