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.
vitepress/lib/app/index.js

110 lines
2.7 KiB

import {
createApp as createClientApp,
createSSRApp,
ref,
readonly
} from 'vue'
import { Content } from './components/Content'
import { createRouter, RouterSymbol } from './router'
import { useUpdateHead } from './composables/head'
import { useSiteData } from './composables/siteData'
import { usePageData, pageDataSymbol } from './composables/pageData'
import Theme from '/@theme/index'
import { hot } from '@hmr'
const inBrowser = typeof window !== 'undefined'
const NotFound = Theme.NotFound || (() => '404 Not Found')
export function createApp() {
const pageDataRef = ref()
if (__DEV__ && inBrowser) {
// dynamically update head tags during dev since it's an SPA
// this is not needed in production.
useUpdateHead(pageDataRef)
// hot reload pageData
hot.on('vitepress:pageData', (data) => {
if (
data.path.replace(/\.md$/, '') ===
location.pathname.replace(/\.html$/, '')
) {
pageDataRef.value = data.pageData
}
})
}
const router = createRouter((route) => {
let pagePath = route.path.replace(/\.html$/, '')
if (pagePath.endsWith('/')) {
pagePath += 'index'
}
if (__DEV__) {
// awlays force re-fetch content in dev
pagePath += `.md?t=${Date.now()}`
} else {
// in production, each .md file is built into a .md.js file following
// the path conversion scheme.
// /foo/bar.html -> /js/foo_bar.md.js
// TODO handle base
pagePath = './' + pagePath.slice(1).replace(/\//g, '_') + '.md.js'
}
if (inBrowser) {
// in browser: native dynamic import
return import(pagePath).then((page) => {
pageDataRef.value = readonly(page.__pageData)
return page.default
})
} else {
// SSR, sync require
const page = require(pagePath)
pageDataRef.value = page.__pageData
return page.default
}
}, NotFound)
const app = __DEV__
? createClientApp(Theme.Layout)
: createSSRApp(Theme.Layout)
app.provide(RouterSymbol, router)
app.provide(pageDataSymbol, pageDataRef)
app.component('Content', Content)
app.mixin({
beforeCreate() {
const siteRef = useSiteData()
const pageRef = usePageData()
Object.defineProperties(this, {
$site: {
get: () => siteRef.value
},
$page: {
get: () => pageRef.value
}
})
}
})
if (Theme.enhanceApp) {
Theme.enhanceApp({
app,
router,
siteData: useSiteData()
})
}
return { app, router }
}
if (inBrowser) {
const { app, router } = createApp()
// wait unitl page component is fetched before mounting
router.go().then(() => {
app.mount('#app')
})
}