Skip to content

Commit 728cb15

Browse files
authoredMay 2, 2024··
fix: render 404 page completely on client to infer locale from browser path (#3858)
1 parent 620ee6a commit 728cb15

File tree

6 files changed

+29
-48
lines changed

6 files changed

+29
-48
lines changed
 

‎src/client/app/router.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,13 @@ export function createRouter(
156156
latestPendingPath = null
157157
route.path = inBrowser ? pendingPath : withBase(pendingPath)
158158
route.component = fallbackComponent ? markRaw(fallbackComponent) : null
159-
route.data = notFoundPageData
159+
const relativePath = inBrowser
160+
? pendingPath
161+
.replace(/(^|\/)$/, '$1index')
162+
.replace(/(\.html)?$/, '.md')
163+
.replace(/^\//, '')
164+
: '404.md'
165+
route.data = { ...notFoundPageData, relativePath }
160166
}
161167
}
162168
}

‎src/client/theme-default/NotFound.vue

+13-37
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,31 @@
11
<script setup lang="ts">
2-
import { computed, onMounted, ref } from 'vue'
32
import { withBase } from 'vitepress'
43
import { useData } from './composables/data'
54
import { useLangs } from './composables/langs'
65
7-
const { site } = useData()
8-
const { localeLinks } = useLangs({ removeCurrent: false })
9-
10-
const locale = ref({
11-
link: '/',
12-
index: 'root'
13-
})
14-
15-
onMounted(() => {
16-
const path = window.location.pathname
17-
.replace(site.value.base, '')
18-
.replace(/(^.*?\/).*$/, '/$1')
19-
if (localeLinks.value.length) {
20-
locale.value =
21-
localeLinks.value.find(({ link }) => link.startsWith(path)) ||
22-
localeLinks.value[0]
23-
}
24-
})
25-
26-
const notFound = computed(() => ({
27-
code: 404,
28-
title: 'PAGE NOT FOUND',
29-
quote:
30-
"But if you don't change your direction, and if you keep looking, you may end up where you are heading.",
31-
linkLabel: 'go to home',
32-
linkText: 'Take me home',
33-
...(locale.value.index === 'root'
34-
? site.value.themeConfig?.notFound
35-
: site.value.locales?.[locale.value.index]?.themeConfig?.notFound)
36-
}))
6+
const { theme } = useData()
7+
const { currentLang } = useLangs()
378
</script>
389

3910
<template>
4011
<div class="NotFound">
41-
<p class="code">{{ notFound.code }}</p>
42-
<h1 class="title">{{ notFound.title }}</h1>
12+
<p class="code">{{ theme.notFound?.code ?? '404' }}</p>
13+
<h1 class="title">{{ theme.notFound?.title ?? 'PAGE NOT FOUND' }}</h1>
4314
<div class="divider" />
44-
<blockquote class="quote">{{ notFound.quote }}</blockquote>
15+
<blockquote class="quote">
16+
{{
17+
theme.notFound?.quote ??
18+
"But if you don't change your direction, and if you keep looking, you may end up where you are heading."
19+
}}
20+
</blockquote>
4521

4622
<div class="action">
4723
<a
4824
class="link"
49-
:href="withBase(locale.link)"
50-
:aria-label="notFound.linkLabel"
25+
:href="withBase(currentLang.link)"
26+
:aria-label="theme.notFound?.linkLabel ?? 'go to home'"
5127
>
52-
{{ notFound.linkText }}
28+
{{ theme.notFound?.linkText ?? 'Take me home' }}
5329
</a>
5430
</div>
5531
</div>

‎src/client/theme-default/composables/langs.ts

+2-7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@ import { computed } from 'vue'
22
import { ensureStartingSlash } from '../support/utils'
33
import { useData } from './data'
44

5-
export function useLangs({
6-
removeCurrent = true,
7-
correspondingLink = false
8-
} = {}) {
5+
export function useLangs({ correspondingLink = false } = {}) {
96
const { site, localeIndex, page, theme, hash } = useData()
107
const currentLang = computed(() => ({
11-
index: localeIndex.value,
128
label: site.value.locales[localeIndex.value]?.label,
139
link:
1410
site.value.locales[localeIndex.value]?.link ||
@@ -17,10 +13,9 @@ export function useLangs({
1713

1814
const localeLinks = computed(() =>
1915
Object.entries(site.value.locales).flatMap(([key, value]) =>
20-
removeCurrent && currentLang.value.label === value.label
16+
currentLang.value.label === value.label
2117
? []
2218
: {
23-
index: key,
2419
text: value.label,
2520
link:
2621
normalizeLink(

‎src/node/build/render.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export async function renderPage(
180180
${await renderHead(head)}
181181
</head>
182182
<body>${teleports?.body || ''}
183-
<div id="app">${content}</div>
183+
<div id="app">${page === '404.md' ? '' : content}</div>
184184
${metadataScript.inHead ? '' : metadataScript.html}
185185
${inlinedScript}
186186
</body>

‎src/shared/shared.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const INDEX_OR_EXT_RE = /(?:(^|\/)index)?\.(?:md|html)$/
2424
export const inBrowser = typeof document !== 'undefined'
2525

2626
export const notFoundPageData: PageData = {
27-
relativePath: '',
27+
relativePath: '404.md',
2828
filePath: '',
2929
title: '404',
3030
description: 'Not Found',

‎types/shared.d.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ export type Awaitable<T> = T | PromiseLike<T>
77

88
export interface PageData {
99
relativePath: string
10-
filePath: string // differs from relativePath in case of path rewrites
10+
/**
11+
* differs from relativePath in case of path rewrites
12+
* empty string if the page is virtual (e.g. 404 page)
13+
*/
14+
filePath: string
1115
title: string
1216
titleTemplate?: string | boolean
1317
description: string

0 commit comments

Comments
 (0)
Please sign in to comment.