138 lines
3.5 KiB
TypeScript

import {
reactive, ref, markRaw, shallowRef
} from 'vue'
import { inBrowser, withBase, useData } from 'vitepress'
// @ts-ignore
import siteData from '@siteData'
export const siteDataRef = shallowRef(siteData)
const routes: any = ref([])
const NotFound = () => '404 Not Found'
const notFoundPageData = {
relativePath: '',
title: '404',
description: 'Not Found',
headers: [],
frontmatter: {},
lastUpdated: 0
}
const getDefaultRoute = () => ({
path: '/',
component: null,
data: notFoundPageData
})
const createRouterRoutes = (
loadPageModule: Function,
fallbackComponent: any
) => {
// const router = useRouter()
const { theme } = useData()
const { pages } = theme.value
let latestPendingPath = ''
async function loadPage(
href = '/index',
scrollPosition = 0,
isRetry = false
) {
const route = reactive(getDefaultRoute())
const pendingPath = `/posts${href}`
try {
let page = loadPageModule(pendingPath)
if ('then' in page && typeof page.then === 'function') {
page = await page
}
const { default: comp, __pageData } = page
if (!comp) {
throw new Error(`Invalid route component: ${comp}`)
}
route.path = inBrowser ? pendingPath : pendingPath
route.component = markRaw(comp)
route.data = markRaw(__pageData)
} catch (err) {
// @ts-ignore
if (!/fetch/.test(err.message) && !/^\/404(\.html|\/)?$/.test(href)) {
console.error(err)
}
if (!isRetry) {
try {
const res = await fetch(`${siteDataRef.value.base}hashmap.json`)
// eslint-disable-next-line no-underscore-dangle
window.__VP_HASH_MAP__ = await res.json()
await loadPage(href, scrollPosition, true)
return
} catch (e) {}
}
if (latestPendingPath === pendingPath) {
latestPendingPath = ''
route.path = inBrowser ? pendingPath : withBase(pendingPath)
route.component = fallbackComponent ? markRaw(fallbackComponent) : null
route.data = notFoundPageData
}
}
return route
}
pages.forEach(async (p: { link: string }) => {
const r = await loadPage(p.link)
routes.value.push(r)
})
return {
routes: routes.value
}
}
const getRoutes = () => {
let isInitialPageLoad = inBrowser
let initialPath = ''
return createRouterRoutes((path: string) => {
let pageFilePath = pathToFile(path)
if (isInitialPageLoad) {
initialPath = pageFilePath
}
if (isInitialPageLoad || initialPath === pageFilePath) {
pageFilePath = pageFilePath.replace(/\.js$/, '.lean.js')
}
if (inBrowser) {
isInitialPageLoad = false
}
return import(/* @vite-ignore */ pageFilePath)
}, NotFound)
}
function pathToFile(path: string) {
let pagePath = path.replace(/\.html$/, '')
pagePath = decodeURIComponent(pagePath)
if (pagePath.endsWith('/')) {
pagePath += 'index'
}
// @ts-ignore
if (import.meta.env.DEV) {
pagePath += `.md?t=${Date.now()}`
} else {
// /foo/bar.html -> ./foo_bar.md
if (inBrowser) {
// @ts-ignore
const base = import.meta.env.BASE_URL
pagePath = `${
pagePath.slice(base.length - 1).replace(/\//g, '_') || 'index'
}.md`
const pageHash = __VP_HASH_MAP__[`posts_${pagePath.toLowerCase()}`]
pagePath = `${base}assets/posts_${pagePath}.${pageHash}.js`
} else {
// ssr
pagePath = `./${pagePath.slice(1).replace(/\//g, '_')}.md.js`
}
}
return pagePath
}
export { getRoutes }
export default {}