fix(client): bypass client router for links explicitly specifying target (#2563)

BREAKING CHANGE: specifying `target="_self"` for internal links will now perform full reload.
pull/2566/head
Divyansh Singh 2 years ago committed by GitHub
parent 03855dd0cf
commit e95015f598
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -31,6 +31,20 @@ There is one exception to this: if you have an HTML page in `public` and link to
- [/pure.html](/pure.html)
- <pathname:///pure.html>
Note that `pathname://` is only supported in Markdown links. Also, `pathname://` will open the link in a new tab by default. You can use `target="_self"` instead to open it in the same tab:
**Input**
```md
[Link to pure.html](/pure.html){target="_self"}
<!-- there is no need to specify pathname:// if the target is explicitly specified -->
```
**Output**
[Link to pure.html](/pure.html){target="_self"}
## Base URL
If your site is deployed to a non-root URL, you will need to set the `base` option in `.vitepress/config.js`. For example, if you plan to deploy your site to `https://foo.github.io/bar/`, then `base` should be set to `'/bar/'` (it should always start and end with a slash).

@ -66,7 +66,7 @@ export function usePrefetch() {
if (!hasFetched.has(pathname)) {
hasFetched.add(pathname)
const pageChunkPath = pathToFile(pathname)
doFetch(pageChunkPath)
if (pageChunkPath) doFetch(pageChunkPath)
}
}
})
@ -76,7 +76,6 @@ export function usePrefetch() {
document
.querySelectorAll<HTMLAnchorElement | SVGAElement>('#app a')
.forEach((link) => {
const { target } = link
const { hostname, pathname } = new URL(
link.href instanceof SVGAnimatedString
? link.href.animVal
@ -91,7 +90,7 @@ export function usePrefetch() {
if (
// only prefetch same tab navigation, since a new tab will load
// the lean js chunk instead.
target !== `_blank` &&
link.target !== '_blank' &&
// only prefetch inbound links
hostname === location.hostname
) {

@ -1,23 +1,22 @@
import RawTheme from '@theme/index'
import {
type App,
createApp as createClientApp,
createSSRApp,
defineComponent,
h,
onMounted,
watchEffect
watchEffect,
type App
} from 'vue'
import RawTheme from '@theme/index'
import { inBrowser, pathToFile } from './utils'
import { type Router, RouterSymbol, createRouter, scrollTo } from './router'
import { siteDataRef, useData } from './data'
import { useUpdateHead } from './composables/head'
import { usePrefetch } from './composables/preFetch'
import { dataSymbol, initData } from './data'
import { Content } from './components/Content'
import { ClientOnly } from './components/ClientOnly'
import { useCopyCode } from './composables/copyCode'
import { Content } from './components/Content'
import { useCodeGroups } from './composables/codeGroups'
import { useCopyCode } from './composables/copyCode'
import { useUpdateHead } from './composables/head'
import { usePrefetch } from './composables/preFetch'
import { dataSymbol, initData, siteDataRef, useData } from './data'
import { RouterSymbol, createRouter, scrollTo, type Router } from './router'
import { inBrowser, pathToFile } from './utils'
function resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme {
if (theme.extends) {
@ -123,6 +122,8 @@ function newRouter(): Router {
return createRouter((path) => {
let pageFilePath = pathToFile(path)
if (!pageFilePath) return null
if (isInitialPageLoad) {
initialPath = pageFilePath
}

@ -22,7 +22,7 @@ export const RouterSymbol: InjectionKey<Router> = Symbol()
// we are just using URL to parse the pathname and hash - the base doesn't
// matter and is only passed to support same-host hrefs.
const fakeHost = `http://a.com`
const fakeHost = 'http://a.com'
const getDefaultRoute = (): Route => ({
path: '/',
@ -36,7 +36,7 @@ interface PageModule {
}
export function createRouter(
loadPageModule: (path: string) => Promise<PageModule>,
loadPageModule: (path: string) => Awaitable<PageModule | null>,
fallbackComponent?: Component
): Router {
const route = reactive(getDefaultRoute())
@ -73,6 +73,9 @@ export function createRouter(
const pendingPath = (latestPendingPath = targetLoc.pathname)
try {
let page = await loadPageModule(pendingPath)
if (!page) {
throw new Error(`Page not found: ${pendingPath}`)
}
if (latestPendingPath === pendingPath) {
latestPendingPath = null
@ -120,7 +123,10 @@ export function createRouter(
}
}
} catch (err: any) {
if (!/fetch/.test(err.message) && !/^\/404(\.html|\/)?$/.test(href)) {
if (
!/fetch|Page not found/.test(err.message) &&
!/^\/404(\.html|\/)?$/.test(href)
) {
console.error(err)
}
@ -176,7 +182,7 @@ export function createRouter(
!e.shiftKey &&
!e.altKey &&
!e.metaKey &&
target !== `_blank` &&
!target &&
origin === currentUrl.origin &&
// don't intercept if non-html extension is present
!(extMatch && extMatch[0] !== '.html')

@ -18,7 +18,7 @@ export { inBrowser } from '../shared'
/**
* Join two paths by resolving the slash collision.
*/
export function joinPath(base: string, path: string): string {
export function joinPath(base: string, path: string) {
return `${base}${path}`.replace(/\/+/g, '/')
}
@ -31,7 +31,7 @@ export function withBase(path: string) {
/**
* Converts a url path to the corresponding js chunk filename.
*/
export function pathToFile(path: string): string {
export function pathToFile(path: string) {
let pagePath = path.replace(/\.html$/, '')
pagePath = decodeURIComponent(pagePath)
pagePath = pagePath.replace(/\/$/, '/index') // /foo/ -> /foo/index
@ -57,6 +57,7 @@ export function pathToFile(path: string): string {
: pagePath.slice(0, -3) + '_index.md'
pageHash = __VP_HASH_MAP__[pagePath.toLowerCase()]
}
if (!pageHash) return null
pagePath = `${base}assets/${pagePath}.${pageHash}.js`
} else {
// ssr build uses much simpler name mapping

@ -230,6 +230,7 @@ debouncedWatch(
async function fetchExcerpt(id: string) {
const file = pathToFile(id.slice(0, id.indexOf('#')))
try {
if (!file) throw new Error(`Cannot find file for id: ${id}`)
return { id, mod: await import(/*@vite-ignore*/ file) }
} catch (e) {
console.error(e)

@ -33,7 +33,7 @@ export function normalizeLink(url: string): string {
}
const { site } = useData()
const { pathname, search, hash } = new URL(url, 'http://example.com')
const { pathname, search, hash } = new URL(url, 'http://a.com')
const normalizedPath =
pathname.endsWith('/') || pathname.endsWith('.html')

Loading…
Cancel
Save