|
|
|
import { createApp as createClientApp, createSSRApp, ref, readonly } from 'vue'
|
|
|
|
import { createRouter, RouterSymbol } from './router'
|
|
|
|
import { useUpdateHead } from './composables/head'
|
|
|
|
import { siteDataRef } from './composables/siteData'
|
|
|
|
import { pageDataSymbol } from './composables/pageData'
|
|
|
|
import { Content } from './components/Content'
|
|
|
|
import Debug from './components/Debug.vue'
|
|
|
|
import Theme from '/@theme/index'
|
|
|
|
import { hot } from 'vite/hmr'
|
|
|
|
|
|
|
|
const inBrowser = typeof window !== 'undefined'
|
|
|
|
|
|
|
|
const NotFound = Theme.NotFound || (() => '404 Not Found')
|
|
|
|
|
|
|
|
export function createApp() {
|
|
|
|
// unlike site data which is static across all requests, page data is
|
|
|
|
// distinct per-request.
|
|
|
|
const pageDataRef = ref()
|
|
|
|
|
|
|
|
if (inBrowser) {
|
|
|
|
// dynamically update head tags
|
|
|
|
useUpdateHead(pageDataRef)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__DEV__ && inBrowser) {
|
|
|
|
// hot reload pageData
|
|
|
|
hot.on('vitepress:pageData', (data) => {
|
|
|
|
if (
|
|
|
|
data.path.replace(/(\bindex)?\.md$/, '') ===
|
|
|
|
location.pathname.replace(/(\bindex)?\.html$/, '')
|
|
|
|
) {
|
|
|
|
pageDataRef.value = data.pageData
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
let isInitialPageLoad = inBrowser
|
|
|
|
/**
|
|
|
|
* @type string
|
|
|
|
*/
|
|
|
|
let initialPath
|
|
|
|
|
|
|
|
const router = createRouter((route) => {
|
|
|
|
let pagePath = route.path.replace(/\.html$/, '')
|
|
|
|
if (pagePath.endsWith('/')) {
|
|
|
|
pagePath += 'index'
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isInitialPageLoad) {
|
|
|
|
initialPath = pagePath
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
const useLeanBuild = isInitialPageLoad || initialPath === pagePath
|
|
|
|
pagePath =
|
|
|
|
(inBrowser ? __BASE__ + '_assets/' : './') +
|
|
|
|
pagePath.slice(inBrowser ? __BASE__.length : 1).replace(/\//g, '_') +
|
|
|
|
(useLeanBuild ? '.md.lean.js' : '.md.js')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inBrowser) {
|
|
|
|
isInitialPageLoad = false
|
|
|
|
// in browser: native dynamic import
|
|
|
|
return import(pagePath).then((page) => {
|
|
|
|
if (page.__pageData) {
|
|
|
|
pageDataRef.value = readonly(JSON.parse(page.__pageData))
|
|
|
|
}
|
|
|
|
return page.default
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
// SSR, sync require
|
|
|
|
const page = require(pagePath)
|
|
|
|
pageDataRef.value = JSON.parse(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.component('Debug', __DEV__ ? Debug : () => null)
|
|
|
|
|
|
|
|
Object.defineProperties(app.config.globalProperties, {
|
|
|
|
$site: {
|
|
|
|
get() {
|
|
|
|
return siteDataRef.value
|
|
|
|
}
|
|
|
|
},
|
|
|
|
$page: {
|
|
|
|
get() {
|
|
|
|
return pageDataRef.value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if (Theme.enhanceApp) {
|
|
|
|
Theme.enhanceApp({
|
|
|
|
app,
|
|
|
|
router,
|
|
|
|
siteData: siteDataRef
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return { app, router }
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inBrowser) {
|
|
|
|
const { app, router } = createApp()
|
|
|
|
// wait unitl page component is fetched before mounting
|
|
|
|
router.go().then(() => {
|
|
|
|
app.mount('#app')
|
|
|
|
})
|
|
|
|
}
|