UNPKG

@knightly/vitepress

Version:

Vite & Vue powered static site generator

113 lines (112 loc) 3.9 kB
import { createApp as createClientApp, createSSRApp, defineAsyncComponent, h, onMounted, watch } from 'vue'; import { inBrowser, pathToFile } from './utils'; import { RouterSymbol, createRouter } from './router'; import { siteDataRef, useData } from './data'; import { useUpdateHead } from './composables/head'; import Theme from '/@theme/index'; import { usePrefetch } from './composables/preFetch'; import { dataSymbol, initData } from './data'; import { Content } from './components/Content'; import { ClientOnly } from './components/ClientOnly'; const NotFound = Theme.NotFound || (() => '404 Not Found'); const VitePressApp = { name: 'VitePressApp', setup() { const { site } = useData(); // change the language on the HTML element based on the current lang onMounted(() => { watch(() => site.value.lang, (lang) => { document.documentElement.lang = lang; }, { immediate: true }); }); if (import.meta.env.PROD) { // in prod mode, enable intersectionObserver based pre-fetch usePrefetch(); } return () => h(Theme.Layout); } }; export function createApp() { const router = newRouter(); handleHMR(router); const app = newApp(); app.provide(RouterSymbol, router); const data = initData(router.route); app.provide(dataSymbol, data); if (inBrowser) { // dynamically update head tags useUpdateHead(router.route, data.site); } // install global components app.component('Content', Content); app.component('ClientOnly', ClientOnly); app.component('Debug', import.meta.env.PROD ? () => null : defineAsyncComponent(() => import('./components/Debug.vue'))); // expose $frontmatter Object.defineProperty(app.config.globalProperties, '$frontmatter', { get() { return data.frontmatter.value; } }); if (Theme.enhanceApp) { Theme.enhanceApp({ app, router, siteData: siteDataRef }); } return { app, router }; } function newApp() { return import.meta.env.PROD ? createSSRApp(VitePressApp) : createClientApp(VitePressApp); } function newRouter() { let isInitialPageLoad = inBrowser; let initialPath; return createRouter((path) => { let pageFilePath = pathToFile(path); if (isInitialPageLoad) { initialPath = pageFilePath; } // use lean build if this is the initial page load or navigating back // to the initial loaded path (the static vnodes already adopted the // static content on that load so no need to re-fetch the page) if (isInitialPageLoad || initialPath === pageFilePath) { pageFilePath = pageFilePath.replace(/\.js$/, '.lean.js'); } // in browser: native dynamic import if (inBrowser) { isInitialPageLoad = false; return import(/*@vite-ignore*/ pageFilePath); } // SSR: sync require // @ts-ignore return require(pageFilePath); }, NotFound); } function handleHMR(router) { // update route.data on HMR updates of active page if (import.meta.hot) { // hot reload pageData import.meta.hot.on('vitepress:pageData', (payload) => { if (shouldHotReload(payload)) { router.route.data = payload.pageData; } }); } } function shouldHotReload(payload) { const payloadPath = payload.path.replace(/(\bindex)?\.md$/, ''); const locationPath = location.pathname.replace(/(\bindex)?\.html$/, ''); return payloadPath === locationPath; } if (inBrowser) { const { app, router } = createApp(); // wait until page component is fetched before mounting router.go().then(() => { app.mount('#app'); }); }