mirror of https://github.com/vuejs/vitepress
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
4.6 KiB
178 lines
4.6 KiB
import RawTheme from '@theme/index'
|
|
import {
|
|
createApp as createClientApp,
|
|
createSSRApp,
|
|
defineComponent,
|
|
h,
|
|
onMounted,
|
|
watchEffect,
|
|
type App
|
|
} from 'vue'
|
|
import { ClientOnly } from './components/ClientOnly'
|
|
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'
|
|
import { SidebarTextItem } from './components/SidebarTextItem'
|
|
import { LocalSearchBoxItem } from './components/LocalSearchBoxItem'
|
|
|
|
function resolveThemeExtends(theme: typeof RawTheme): typeof RawTheme {
|
|
if (theme.extends) {
|
|
const base = resolveThemeExtends(theme.extends)
|
|
return {
|
|
...base,
|
|
...theme,
|
|
async enhanceApp(ctx) {
|
|
if (base.enhanceApp) await base.enhanceApp(ctx)
|
|
if (theme.enhanceApp) await theme.enhanceApp(ctx)
|
|
}
|
|
}
|
|
}
|
|
return theme
|
|
}
|
|
|
|
const Theme = resolveThemeExtends(RawTheme)
|
|
|
|
const VitePressApp = defineComponent({
|
|
name: 'VitePressApp',
|
|
setup() {
|
|
const { site, lang, dir } = useData()
|
|
|
|
// change the language on the HTML element based on the current lang
|
|
onMounted(() => {
|
|
watchEffect(() => {
|
|
document.documentElement.lang = lang.value
|
|
document.documentElement.dir = dir.value
|
|
})
|
|
})
|
|
|
|
if (import.meta.env.PROD && site.value.router.prefetchLinks) {
|
|
// in prod mode, enable intersectionObserver based pre-fetch
|
|
usePrefetch()
|
|
}
|
|
|
|
// setup global copy code handler
|
|
useCopyCode()
|
|
// setup global code groups handler
|
|
useCodeGroups()
|
|
|
|
if (Theme.setup) Theme.setup()
|
|
return () => h(Theme.Layout!)
|
|
}
|
|
})
|
|
|
|
export async function createApp() {
|
|
;(globalThis as any).__VITEPRESS__ = true
|
|
|
|
const router = newRouter()
|
|
|
|
const app = newApp()
|
|
|
|
app.provide(RouterSymbol, router)
|
|
|
|
const data = initData(router.route)
|
|
app.provide(dataSymbol, data)
|
|
|
|
// install global components
|
|
app.component('Content', Content)
|
|
app.component('ClientOnly', ClientOnly)
|
|
app.component('SidebarTextItem', SidebarTextItem)
|
|
app.component('LocalSearchBoxItem', LocalSearchBoxItem)
|
|
|
|
// expose $frontmatter & $params
|
|
Object.defineProperties(app.config.globalProperties, {
|
|
$frontmatter: {
|
|
get() {
|
|
return data.frontmatter.value
|
|
}
|
|
},
|
|
$params: {
|
|
get() {
|
|
return data.page.value.params
|
|
}
|
|
}
|
|
})
|
|
|
|
if (Theme.enhanceApp) {
|
|
await Theme.enhanceApp({
|
|
app,
|
|
router,
|
|
siteData: siteDataRef
|
|
})
|
|
}
|
|
|
|
// setup devtools in dev mode
|
|
if (import.meta.env.DEV || __VUE_PROD_DEVTOOLS__) {
|
|
import('./devtools.js').then(({ setupDevtools }) =>
|
|
setupDevtools(app, router, data)
|
|
)
|
|
}
|
|
|
|
return { app, router, data }
|
|
}
|
|
|
|
function newApp(): App {
|
|
return import.meta.env.PROD
|
|
? createSSRApp(VitePressApp)
|
|
: createClientApp(VitePressApp)
|
|
}
|
|
|
|
function newRouter(): Router {
|
|
let isInitialPageLoad = inBrowser
|
|
|
|
return createRouter((path) => {
|
|
let pageFilePath = pathToFile(path)
|
|
let pageModule = null
|
|
|
|
if (pageFilePath) {
|
|
// use lean build if this is the initial page load
|
|
if (isInitialPageLoad) {
|
|
pageFilePath = pageFilePath.replace(/\.js$/, '.lean.js')
|
|
}
|
|
|
|
if (import.meta.env.DEV) {
|
|
pageModule = import(/*@vite-ignore*/ pageFilePath).catch(() => {
|
|
// try with/without trailing slash
|
|
// in prod this is handled in src/client/app/utils.ts#pathToFile
|
|
const url = new URL(pageFilePath!, 'http://a.com')
|
|
const path =
|
|
(url.pathname.endsWith('/index.md')
|
|
? url.pathname.slice(0, -9) + '.md'
|
|
: url.pathname.slice(0, -3) + '/index.md') +
|
|
url.search +
|
|
url.hash
|
|
return import(/*@vite-ignore*/ path)
|
|
})
|
|
} else {
|
|
pageModule = import(/*@vite-ignore*/ pageFilePath)
|
|
}
|
|
}
|
|
|
|
if (inBrowser) {
|
|
isInitialPageLoad = false
|
|
}
|
|
|
|
return pageModule
|
|
}, Theme.NotFound)
|
|
}
|
|
|
|
if (inBrowser) {
|
|
createApp().then(({ app, router, data }) => {
|
|
// wait until page component is fetched before mounting
|
|
router.go(location.href, { initialLoad: true }).then(() => {
|
|
// dynamically update head tags
|
|
useUpdateHead(router.route, data.site)
|
|
app.mount('#app')
|
|
|
|
// scroll to hash on new tab during dev
|
|
if (import.meta.env.DEV && location.hash) {
|
|
scrollTo(location.hash)
|
|
}
|
|
})
|
|
})
|
|
}
|