From c6bdcfbf4f14916f20a7192b44941d33d4bee51e Mon Sep 17 00:00:00 2001 From: Matias Capeletto Date: Thu, 26 Nov 2020 11:49:41 +0100 Subject: [PATCH 01/16] feat!: add more global and computed properties (#152) BREAKING CHANGE: `$theme` global computed is renamed to `$themeConfig` to align better with VuePress. Co-authored-by: Kia King Ishii --- docs/.vitepress/config.js | 1 + docs/guide/frontmatter.md | 4 +- docs/guide/global-computed.md | 73 +++++++++++++++++++ src/client/app/index.ts | 21 +++++- .../theme-default/components/NavBarTitle.vue | 13 +--- src/node/markdownToVue.ts | 26 ++++++- types/shared.d.ts | 5 +- 7 files changed, 126 insertions(+), 17 deletions(-) create mode 100644 docs/guide/global-computed.md diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 10e44a51..ca10e3c7 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -44,6 +44,7 @@ function getGuideSidebar() { text: 'Advanced', children: [ { text: 'Frontmatter', link: '/guide/frontmatter' }, + { text: 'Global Computed', link: '/guide/global-computed' }, { text: 'Customization', link: '/guide/customization' } ] } diff --git a/docs/guide/frontmatter.md b/docs/guide/frontmatter.md index 3c6fb5d3..71f28bee 100644 --- a/docs/guide/frontmatter.md +++ b/docs/guide/frontmatter.md @@ -9,7 +9,7 @@ editLink: true --- ``` -Between the triple-dashed lines, you can set [predefined variables](#predefined-variables), or even create custom ones of your own. These variables can be used via the \$page.frontmatter variable. +Between the triple-dashed lines, you can set [predefined variables](#predefined-variables), or even create custom ones of your own. These variables can be used via the $frontmatter variable. Here’s an example of how you could use it in your Markdown file: @@ -19,7 +19,7 @@ title: Docs with VitePress editLink: true --- -# {{ $page.frontmatter.title }} +# {{ $frontmatter.title }} Guide content ``` diff --git a/docs/guide/global-computed.md b/docs/guide/global-computed.md new file mode 100644 index 00000000..7221534a --- /dev/null +++ b/docs/guide/global-computed.md @@ -0,0 +1,73 @@ +# Global Computed + +In VitePress, some core [computed properties](https://v3.vuejs.org/guide/computed.html#computed-properties) can be used by the default theme or custom themes. Or directly in Markdown pages using vue, for example using `$frontmatter.title` to access the title defined in the frontmatter section of the page. + +## $site + +This is the `$site` value of the site you're currently reading: + +```js +{ + base: '/', + lang: 'en-US', + title: 'VitePress', + description: 'Vite & Vue powered static site generator.', + head: [], + locales: {}, + themeConfig: $themeConfig +} +``` + +## $themeConfig + +Refers to `$site.themeConfig`. + +```js +{ + locales: {}, + repo: 'vuejs/vitepress', + docsDir: 'docs', + editLinks: true, + editLinkText: 'Edit this page on GitHub', + lastUpdated: 'Last Updated', + nav: [...], + sidebar: { ... } +} +``` + +## $page + +This is the `$page` value of the page you're currently reading: + +```js +{ + relativePath: 'guide/global-computed.md', + title: 'Global Computed', + headers: [ + { level: 2, title: '$site', slug: 'site' }, + { level: 2, title: '$page', slug: '$page' }, + ... + ], + frontmatter: $frontmatter, + lastUpdated: 1606297645000 +} +``` + +## $frontmatter + +Reference of `$page.frontmatter`. + +```js +{ + title: 'Docs with VitePress', + editLink: true +} +``` + +## $title + +Value of the `` label used for the current page. + +## $description + +The content value of the `<meta name= "description" content= "...">` for the current page. diff --git a/src/client/app/index.ts b/src/client/app/index.ts index f3eaa170..5ae7de79 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -82,14 +82,31 @@ export function createApp() { return siteDataByRouteRef.value } }, + $themeConfig: { + get() { + return siteDataByRouteRef.value.themeConfig + } + }, $page: { get() { return router.route.data } }, - $theme: { + $frontmatter: { get() { - return siteDataByRouteRef.value.themeConfig + return router.route.data.frontmatter + } + }, + $title: { + get() { + return router.route.data.title || siteDataByRouteRef.value.title + } + }, + $description: { + get() { + return ( + router.route.data.description || siteDataByRouteRef.value.description + ) } } }) diff --git a/src/client/theme-default/components/NavBarTitle.vue b/src/client/theme-default/components/NavBarTitle.vue index bafdc6c7..124560b6 100644 --- a/src/client/theme-default/components/NavBarTitle.vue +++ b/src/client/theme-default/components/NavBarTitle.vue @@ -5,24 +5,17 @@ :aria-label="`${$site.title}, back to home`" > <img - v-if="$theme.logo" + v-if="$themeConfig.logo" class="logo" - :src="withBase($theme.logo)" + :src="withBase($themeConfig.logo)" alt="Logo" /> {{ $site.title }} </a> </template> -<script lang="ts"> -import { defineComponent } from 'vue' +<script setup lang="ts"> import { withBase } from '../utils' - -export default defineComponent({ - setup() { - return { withBase } - } -}) </script> <style scoped> diff --git a/src/node/markdownToVue.ts b/src/node/markdownToVue.ts index 86be2ec3..55a48f61 100644 --- a/src/node/markdownToVue.ts +++ b/src/node/markdownToVue.ts @@ -3,7 +3,7 @@ import matter from 'gray-matter' import LRUCache from 'lru-cache' import { createMarkdownRenderer, MarkdownOptions } from './markdown/markdown' import { deeplyParseHeader } from './utils/parseHeader' -import { PageData } from '../../types/shared' +import { PageData, HeadConfig } from '../../types/shared' const debug = require('debug')('vitepress:md') const cache = new LRUCache<string, MarkdownCompileResult>({ max: 1024 }) @@ -41,6 +41,7 @@ export function createMarkdownToVueRenderFn( // inject page data const pageData: PageData = { title: inferTitle(frontmatter, content), + description: inferDescription(frontmatter), frontmatter, headers: data.headers, relativePath: file.replace(/\\/g, '/'), @@ -106,3 +107,26 @@ const inferTitle = (frontmatter: any, content: string) => { } return '' } + +const inferDescription = (frontmatter: Record<string, any>) => { + if (!frontmatter.head) { + return '' + } + + return getHeadMetaContent(frontmatter.head, 'description') || '' +} + +const getHeadMetaContent = ( + head: HeadConfig[], + name: string +): string | undefined => { + if (!head || !head.length) { + return undefined + } + + const meta = head.find(([tag, attrs = {}]) => { + return tag === 'meta' && attrs.name === name && attrs.content + }) + + return meta && meta[1].content +} diff --git a/types/shared.d.ts b/types/shared.d.ts index 859176f2..8ecfea93 100644 --- a/types/shared.d.ts +++ b/types/shared.d.ts @@ -24,10 +24,11 @@ export type HeadConfig = | [string, Record<string, string>, string] export interface PageData { + relativePath: string title: string - frontmatter: Record<string, any> + description: string headers: Header[] - relativePath: string + frontmatter: Record<string, any> lastUpdated: number } From 9d6b8cadcc6cd59bde6b9b20037f9038190672ce Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote <posva@users.noreply.github.com> Date: Thu, 26 Nov 2020 13:57:12 +0100 Subject: [PATCH 02/16] feat: add native support for carbon ads (#86) Co-authored-by: Kia King Ishii <kia.king.08@gmail.com> --- docs/.vitepress/config.js | 11 +- docs/config/carbon-ads.md | 13 ++ src/client/theme-default/Layout.vue | 18 +++ .../theme-default/components/BuySellAds.vue | 146 ++++++++++++++++++ .../theme-default/components/CarbonAds.vue | 102 ++++++++++++ .../theme-default/styles/custom-blocks.css | 1 + src/client/theme-default/styles/vars.css | 2 + 7 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 docs/config/carbon-ads.md create mode 100644 src/client/theme-default/components/BuySellAds.vue create mode 100644 src/client/theme-default/components/CarbonAds.vue diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index ca10e3c7..6a7dc24e 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -11,6 +11,12 @@ module.exports = { editLinkText: 'Edit this page on GitHub', lastUpdated: 'Last Updated', + carbonAds: { + carbon: 'CEBDT27Y', + custom: 'CKYD62QM', + placement: 'vuejsorg' + }, + nav: [ { text: 'Guide', link: '/' }, { text: 'Config Reference', link: '/config/basics' }, @@ -55,7 +61,10 @@ function getConfigSidebar() { return [ { text: 'App Config', - children: [{ text: 'Basics', link: '/config/basics' }] + children: [ + { text: 'Basics', link: '/config/basics' }, + { text: 'Carbon Ads', link: '/config/carbon-ads' } + ] } ] } diff --git a/docs/config/carbon-ads.md b/docs/config/carbon-ads.md new file mode 100644 index 00000000..20abee95 --- /dev/null +++ b/docs/config/carbon-ads.md @@ -0,0 +1,13 @@ +# Carbon Ads + +VitePress has built in native support for [Carbon Ads](https://www.carbonads.net). By defining the Carbon Ads credentials in config, VitePress will display ads on the page. + +```js +module.exports = { + carbonAds: { + carbon: 'your-carbon-key', + custom: 'your-carbon-custom', + placement: 'your-carbon-placement' + } +} +``` diff --git a/src/client/theme-default/Layout.vue b/src/client/theme-default/Layout.vue index 6b3f9443..a95cc45a 100644 --- a/src/client/theme-default/Layout.vue +++ b/src/client/theme-default/Layout.vue @@ -34,10 +34,26 @@ <main v-else> <Page> <template #top> + <slot name="page-top-ads"> + <CarbonAds + v-if="$site.themeConfig.carbonAds" + :key="'carbon' + $page.path" + :code="$site.themeConfig.carbonAds.carbon" + :placement="$site.themeConfig.carbonAds.placement" + /> + </slot> <slot name="page-top" /> </template> <template #bottom> <slot name="page-bottom" /> + <slot name="page-bottom-ads"> + <BuySellAds + v-if="$site.themeConfig.carbonAds" + :key="'custom' + $page.path" + :code="$site.themeConfig.carbonAds.custom" + :placement="$site.themeConfig.carbonAds.placement" + /> + </slot> </template> </Page> </main> @@ -53,6 +69,8 @@ import ToggleSideBarButton from './components/ToggleSideBarButton.vue' import SideBar from './components/SideBar.vue' import Page from './components/Page.vue' import { useRoute, useSiteData, useSiteDataByRoute } from 'vitepress' +import CarbonAds from './components/CarbonAds.vue' +import BuySellAds from './components/BuySellAds.vue' const route = useRoute() const siteData = useSiteData() diff --git a/src/client/theme-default/components/BuySellAds.vue b/src/client/theme-default/components/BuySellAds.vue new file mode 100644 index 00000000..2ddccf3b --- /dev/null +++ b/src/client/theme-default/components/BuySellAds.vue @@ -0,0 +1,146 @@ +<template> + <div class="buy-sell-ads"> + <div class="bsa-cpc" /> + </div> +</template> + +<script setup lang="ts"> +import { defineProps, onMounted } from 'vue' + +// global _bsa +const ID = 'bsa-cpc-script' + +declare global { + var _bsa: BSA | undefined + + interface BSA { + init( + name: string, + code: string, + placement: string, + options: { + target: string + align: string + disable_css?: 'true' | 'false' + } + ): void + } +} + +const { code, placement } = defineProps<{ + code: string + placement: string +}>() + +onMounted(() => { + if (!document.getElementById(ID)) { + const s = document.createElement('script') + + s.id = ID + s.src = '//m.servedby-buysellads.com/monetization.js' + + document.head.appendChild(s) + + s.onload = () => { load() } + } else { + load() + } +}) + +function load() { + if (typeof _bsa !== 'undefined' && _bsa) { + _bsa.init('default', code, `placement:${placement}`, { + target: '.bsa-cpc', + align: 'horizontal', + disable_css: 'true' + }) + } +} +</script> + +<style scoped> +.buy-sell-ads { + margin: 0 auto; + padding-top: 2rem; + font-size: .85rem; +} + +.bsa-cpc { + border-radius: 6px; + background-color: #f8f8f8; +} + +.bsa-cpc ::v-deep(a._default_) { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + margin-bottom: 20px; + padding: 12px; + text-decoration: none; + line-height: 1.4; + font-weight: 400; + color: var(--c-text-light); +} + +@media (min-width: 512px) { + .bsa-cpc ::v-deep(a._default_) { + flex-wrap: nowrap; + } +} + +.bsa-cpc ::v-deep(.default-ad) { + display: none; +} + +.bsa-cpc ::v-deep(a._default_ .default-image) { + flex-shrink: 0; + margin-right: 12px; + width: 24px; +} + +.bsa-cpc ::v-deep(a._default_ .default-image img) { + border-radius: 4px; + height: 24px; + vertical-align: middle; +} + +.bsa-cpc ::v-deep(._default_::after) { + border: 1px solid #1c90f3; + border-radius: 4px; + margin-top: 8px; + margin-left: 36px; + padding: 0 8px; + line-height: 22px; + font-size: .85em; + font-weight: 500; + color: #1c90f3; + content: 'Sponsored'; +} + +@media (min-width: 512px) { + .bsa-cpc ::v-deep(._default_::after) { + margin-top: 0px; + margin-left: 12px; + } +} + +.bsa-cpc ::v-deep(.default-text) { + flex-grow: 1; + align-self: center; + width: calc(100% - 36px); +} + +@media (min-width: 512px) { + .bsa-cpc ::v-deep(.default-text) { + width: auto; + } +} + +.bsa-cpc ::v-deep(.default-title) { + font-weight: 600; +} + +.bsa-cpc ::v-deep(.default-description) { + padding-left: 8px; +} +</style> diff --git a/src/client/theme-default/components/CarbonAds.vue b/src/client/theme-default/components/CarbonAds.vue new file mode 100644 index 00000000..7f3e6d6a --- /dev/null +++ b/src/client/theme-default/components/CarbonAds.vue @@ -0,0 +1,102 @@ +<template> + <div class="carbon-ads" ref="el" /> +</template> + +<script setup lang="ts"> +import { defineProps, ref, onMounted } from 'vue' + +const { code, placement } = defineProps<{ + code: string + placement: string +}>() + +const el = ref() + +onMounted(() => { + const s = document.createElement('script') + s.id = '_carbonads_js' + s.src = `//cdn.carbonads.com/carbon.js?serve=${code}&placement=${placement}` + el.value.appendChild(s) +}) +</script> + +<style scoped> +.carbon-ads { + padding: 1.75rem 0 0; + border-radius: 4px; + margin: 0 auto; + max-width: 280px; + font-size: .75rem; + background-color: rgba(255, 255, 255, .8); +} + +.carbon-ads::after { + clear: both; + display: block; + content: ""; +} + +@media (min-width: 420px) { + .carbon-ads { + position: relative; + right: -8px; + z-index: 1; + float: right; + margin: -8px -8px 24px 24px; + padding: 8px; + width: 146px; + max-width: 100%; + } +} + +@media (min-width: 1400px) { + .carbon-ads { + position: fixed; + top: auto; + right: 8px; + bottom: 8px; + float: none; + margin: 0; + } +} + +.carbon-ads ::v-deep(.carbon-img) { + float: left; + margin-right: .75rem; + max-width: 100px; + border: 1px solid var(--c-divider); +} + +@media (min-width: 420px) { + .carbon-ads ::v-deep(.carbon-img) { + float: none; + display: block; + margin-right: 0; + max-width: 130px; + } +} + +.carbon-ads ::v-deep(.carbon-img img) { + display: block; + width: 100%; +} + +@media (min-width: 420px) { + .carbon-ads ::v-deep(.carbon-text) { + padding-top: 8px; + } +} + +.carbon-ads ::v-deep(.carbon-text) { + display: block; + font-weight: 400; + color: var(--c-text-light); +} + +.carbon-ads ::v-deep(.carbon-poweredby) { + display: block; + padding-top: 2px; + font-weight: 400; + color: var(--c-text-lighter); +} +</style> diff --git a/src/client/theme-default/styles/custom-blocks.css b/src/client/theme-default/styles/custom-blocks.css index b96580df..b5456d76 100644 --- a/src/client/theme-default/styles/custom-blocks.css +++ b/src/client/theme-default/styles/custom-blocks.css @@ -4,6 +4,7 @@ margin: 1rem 0; border-left: .5rem solid; padding: .1rem 1.5rem; + overflow-x: auto; } .custom-block.tip { diff --git a/src/client/theme-default/styles/vars.css b/src/client/theme-default/styles/vars.css index 4ae10251..4957c052 100644 --- a/src/client/theme-default/styles/vars.css +++ b/src/client/theme-default/styles/vars.css @@ -13,6 +13,7 @@ --c-text-light-1: #2c3e50; --c-text-light-2: #476582; + --c-text-light-3: #90a4b7; --c-brand: #3eaf7c; --c-brand-light: #4abf8a; @@ -45,6 +46,7 @@ --c-text: var(--c-text-light-1); --c-text-light: var(--c-text-light-2); + --c-text-lighter: var(--c-text-light-3); --c-bg: var(--c-white); From 776d8014a28999616b44df0de0a24370c4a47428 Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 00:34:16 +0900 Subject: [PATCH 03/16] refactor: organize app index related files --- src/client/app/components/Content.ts | 4 +- src/client/app/composables/pageData.ts | 13 ++-- src/client/app/composables/siteData.ts | 10 +-- src/client/app/composables/siteDataByRoute.ts | 8 ++- src/client/app/index.ts | 52 ++------------- src/client/app/mixin.ts | 64 +++++++++++++++++++ 6 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 src/client/app/mixin.ts diff --git a/src/client/app/components/Content.ts b/src/client/app/components/Content.ts index 82a0070e..cf2ff4aa 100644 --- a/src/client/app/components/Content.ts +++ b/src/client/app/components/Content.ts @@ -5,10 +5,12 @@ import { usePrefetch } from '../composables/preFetch' export const Content = { setup() { const route = useRoute() + if (process.env.NODE_ENV === 'production') { - // in prod mode, enable intersectionObserver based pre-fetch. + // in prod mode, enable intersectionObserver based pre-fetch usePrefetch() } + return () => (route.component ? h(route.component) : null) } } diff --git a/src/client/app/composables/pageData.ts b/src/client/app/composables/pageData.ts index 8e98b185..666af353 100644 --- a/src/client/app/composables/pageData.ts +++ b/src/client/app/composables/pageData.ts @@ -1,8 +1,11 @@ -import { computed } from 'vue' -import { useRoute } from '../router' +import { Ref, computed } from 'vue' +import { PageData } from '/@types/shared' +import { Route, useRoute } from '../router' -export function usePageData() { - const route = useRoute() +export type PageDataRef = Ref<PageData> - return computed(() => route.data) +export function usePageData(route?: Route) { + const r = route || useRoute() + + return computed(() => r.data) } diff --git a/src/client/app/composables/siteData.ts b/src/client/app/composables/siteData.ts index 41a43d5e..26643166 100644 --- a/src/client/app/composables/siteData.ts +++ b/src/client/app/composables/siteData.ts @@ -1,8 +1,6 @@ import serialized from '@siteData' -import { ref, readonly, Ref } from 'vue' -import { SiteData } from '../../../../types/shared' - -const parse = (data: string) => readonly(JSON.parse(data)) as SiteData +import { SiteData } from '/@types/shared' +import { Ref, ref, readonly } from 'vue' export type SiteDataRef<T = any> = Ref<SiteData<T>> @@ -12,6 +10,10 @@ export function useSiteData<T = any>() { return siteDataRef as Ref<SiteData<T>> } +function parse(data: string): SiteData { + return readonly(JSON.parse(data)) as SiteData +} + // hmr if (import.meta.hot) { import.meta.hot!.acceptDeps('/@siteData', (m) => { diff --git a/src/client/app/composables/siteDataByRoute.ts b/src/client/app/composables/siteDataByRoute.ts index f7bcb3a0..2ccab628 100644 --- a/src/client/app/composables/siteDataByRoute.ts +++ b/src/client/app/composables/siteDataByRoute.ts @@ -1,10 +1,12 @@ import { computed } from 'vue' import { resolveSiteDataByRoute } from '/@shared/config' import { siteDataRef } from './siteData' -import { useRoute } from '../router' +import { Route, useRoute } from '../router' + +export function useSiteDataByRoute(route?: Route) { + const r = route || useRoute() -export function useSiteDataByRoute(route = useRoute()) { return computed(() => { - return resolveSiteDataByRoute(siteDataRef.value, route.path) + return resolveSiteDataByRoute(siteDataRef.value, r.path) }) } diff --git a/src/client/app/index.ts b/src/client/app/index.ts index 5ae7de79..ebcfeb5b 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -1,11 +1,11 @@ import { createApp as createClientApp, createSSRApp } from 'vue' import { inBrowser, pathToFile } from './utils' import { createRouter, RouterSymbol } from './router' +import { mixinGlobalComputed, mixinGlobalComponents } from './mixin' import { siteDataRef } from './composables/siteData' import { useSiteDataByRoute } from './composables/siteDataByRoute' +import { usePageData } from './composables/PageData' import { useUpdateHead } from './composables/head' -import { Content } from './components/Content' -import Debug from './components/Debug.vue' import Theme from '/@theme/index' const NotFound = Theme.NotFound || (() => '404 Not Found') @@ -58,58 +58,17 @@ export function createApp() { app.provide(RouterSymbol, router) - app.component('Content', Content) - app.component( - 'Debug', - process.env.NODE_ENV === 'production' ? () => null : Debug - ) + mixinGlobalComponents(app) const siteDataByRouteRef = useSiteDataByRoute(router.route) + const pageDataRef = usePageData(router.route) if (inBrowser) { // dynamically update head tags useUpdateHead(router.route, siteDataByRouteRef) } - Object.defineProperties(app.config.globalProperties, { - $site: { - get() { - return siteDataRef.value - } - }, - $siteByRoute: { - get() { - return siteDataByRouteRef.value - } - }, - $themeConfig: { - get() { - return siteDataByRouteRef.value.themeConfig - } - }, - $page: { - get() { - return router.route.data - } - }, - $frontmatter: { - get() { - return router.route.data.frontmatter - } - }, - $title: { - get() { - return router.route.data.title || siteDataByRouteRef.value.title - } - }, - $description: { - get() { - return ( - router.route.data.description || siteDataByRouteRef.value.description - ) - } - } - }) + mixinGlobalComputed(app, siteDataRef, siteDataByRouteRef, pageDataRef) if (Theme.enhanceApp) { Theme.enhanceApp({ @@ -124,6 +83,7 @@ export function createApp() { if (inBrowser) { const { app, router } = createApp() + // wait unitl page component is fetched before mounting router.go().then(() => { app.mount('#app') diff --git a/src/client/app/mixin.ts b/src/client/app/mixin.ts new file mode 100644 index 00000000..fc6fbca7 --- /dev/null +++ b/src/client/app/mixin.ts @@ -0,0 +1,64 @@ +import { App } from 'vue' +import { SiteDataRef } from './composables/siteData' +import { PageDataRef } from './composables/PageData' +import { Content } from './components/Content' +import Debug from './components/Debug.vue' + +export function mixinGlobalComputed( + app: App, + site: SiteDataRef, + siteByRoute: SiteDataRef, + page: PageDataRef +): void { + Object.defineProperties(app.config.globalProperties, { + $site: { + get() { + return site.value + } + }, + + $siteByRoute: { + get() { + return siteByRoute.value + } + }, + + $themeConfig: { + get() { + return siteByRoute.value.themeConfig + } + }, + + $page: { + get() { + return page + } + }, + + $frontmatter: { + get() { + return page.value.frontmatter + } + }, + + $title: { + get() { + return page.value.title || siteByRoute.value.title + } + }, + + $description: { + get() { + return page.value.description || siteByRoute.value.description + } + } + }) +} + +export function mixinGlobalComponents(app: App) { + const isProd = process.env.NODE_ENV === 'production' + + app.component('Content', Content) + + app.component('Debug', isProd ? () => null : Debug) +} From 15e18df01e6e5ca8af605365896fee0024244b37 Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 01:39:14 +0900 Subject: [PATCH 04/16] feat: add `$withBase` global app function --- src/client/app/mixin.ts | 9 ++++++++- src/client/app/utils.ts | 7 +++++++ src/client/theme-default/components/Home.vue | 5 ++--- src/client/theme-default/components/NavBarLink.vue | 4 +++- .../theme-default/components/NavBarTitle.vue | 6 +----- .../theme-default/components/NextAndPrevLinks.vue | 5 ++--- src/client/theme-default/composables/url.ts | 14 ++++++++++++++ src/client/theme-default/utils.ts | 6 +----- 8 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 src/client/theme-default/composables/url.ts diff --git a/src/client/app/mixin.ts b/src/client/app/mixin.ts index fc6fbca7..7d1ddb4d 100644 --- a/src/client/app/mixin.ts +++ b/src/client/app/mixin.ts @@ -1,4 +1,5 @@ import { App } from 'vue' +import { joinPath } from './utils' import { SiteDataRef } from './composables/siteData' import { PageDataRef } from './composables/PageData' import { Content } from './components/Content' @@ -31,7 +32,7 @@ export function mixinGlobalComputed( $page: { get() { - return page + return page.value } }, @@ -51,6 +52,12 @@ export function mixinGlobalComputed( get() { return page.value.description || siteByRoute.value.description } + }, + + $withBase: { + value(path: string) { + return joinPath(site.value.base, path) + } } }) } diff --git a/src/client/app/utils.ts b/src/client/app/utils.ts index 93a9674e..0509668a 100644 --- a/src/client/app/utils.ts +++ b/src/client/app/utils.ts @@ -1,5 +1,12 @@ export const inBrowser = typeof window !== 'undefined' +/** + * Join two paths by resolving the slash collision. + */ +export function joinPath(base: string, path: string): string { + return `${base}${path}`.replace(/\/+/g, '/') +} + /** * Converts a url path to the corresponding js chunk filename. */ diff --git a/src/client/theme-default/components/Home.vue b/src/client/theme-default/components/Home.vue index 370961f5..819f7787 100644 --- a/src/client/theme-default/components/Home.vue +++ b/src/client/theme-default/components/Home.vue @@ -2,7 +2,7 @@ <header class="hero"> <img v-if="data.heroImage" - :src="heroImageSrc" + :src="$withBase(heroImageSrc)" :alt="data.heroAlt || 'hero'" /> @@ -39,7 +39,6 @@ <script setup lang="ts"> import { computed } from 'vue' import { useRoute, useSiteData } from 'vitepress' -import { withBase } from '../utils' const route = useRoute() const siteData = useSiteData() @@ -48,7 +47,7 @@ const actionLink = computed(() => ({ link: data.value.actionLink, text: data.value.actionText })) -const heroImageSrc = computed(() => withBase(data.value.heroImage)) +const heroImageSrc = computed(() => data.value.heroImage) const siteTitle = computed(() => siteData.value.title) const siteDescription = computed(() => siteData.value.description) </script> diff --git a/src/client/theme-default/components/NavBarLink.vue b/src/client/theme-default/components/NavBarLink.vue index ab59f34b..b1667db7 100644 --- a/src/client/theme-default/components/NavBarLink.vue +++ b/src/client/theme-default/components/NavBarLink.vue @@ -16,8 +16,9 @@ <script setup lang="ts"> import { computed, defineProps } from 'vue' import { useRoute } from 'vitepress' -import { withBase, isExternal } from '../utils' +import { isExternal } from '../utils' import type { DefaultTheme } from '../config' +import { useUrl } from '../composables/url' import OutboundLink from './icons/OutboundLink.vue' const { item } = defineProps<{ @@ -35,6 +36,7 @@ const normalizePath = (path: string): string => { return path } +const { withBase } = useUrl() const route = useRoute() const classes = computed(() => ({ diff --git a/src/client/theme-default/components/NavBarTitle.vue b/src/client/theme-default/components/NavBarTitle.vue index 124560b6..2b4256a7 100644 --- a/src/client/theme-default/components/NavBarTitle.vue +++ b/src/client/theme-default/components/NavBarTitle.vue @@ -7,17 +7,13 @@ <img v-if="$themeConfig.logo" class="logo" - :src="withBase($themeConfig.logo)" + :src="$withBase($themeConfig.logo)" alt="Logo" /> {{ $site.title }} </a> </template> -<script setup lang="ts"> -import { withBase } from '../utils' -</script> - <style scoped> .nav-bar-title { font-size: 1.3rem; diff --git a/src/client/theme-default/components/NextAndPrevLinks.vue b/src/client/theme-default/components/NextAndPrevLinks.vue index 65586a13..dcfea074 100644 --- a/src/client/theme-default/components/NextAndPrevLinks.vue +++ b/src/client/theme-default/components/NextAndPrevLinks.vue @@ -2,13 +2,13 @@ <div v-if="hasLinks" class="next-and-prev-link"> <div class="container"> <div class="prev"> - <a v-if="prev" class="link" :href="withBase(prev.link)"> + <a v-if="prev" class="link" :href="$withBase(prev.link)"> <ArrowLeft class="icon icon-prev" /> <span class="text">{{ prev.text }}</span> </a> </div> <div class="next"> - <a v-if="next" class="link" :href="withBase(next.link)"> + <a v-if="next" class="link" :href="$withBase(next.link)"> <span class="text">{{ next.text }}</span> <ArrowRight class="icon icon-next" /> </a> @@ -18,7 +18,6 @@ </template> <script setup lang="ts"> -import { withBase } from '../utils' import { useNextAndPrevLinks } from '../composables/nextAndPrevLinks' import ArrowLeft from './icons/ArrowLeft.vue' import ArrowRight from './icons/ArrowRight.vue' diff --git a/src/client/theme-default/composables/url.ts b/src/client/theme-default/composables/url.ts new file mode 100644 index 00000000..c8afec03 --- /dev/null +++ b/src/client/theme-default/composables/url.ts @@ -0,0 +1,14 @@ +import { useSiteData } from 'vitepress' +import { joinPath } from '/@app/utils' + +export function useUrl() { + const site = useSiteData() + + function withBase(path: string): string { + return joinPath(site.value.base, path) + } + + return { + withBase + } +} diff --git a/src/client/theme-default/utils.ts b/src/client/theme-default/utils.ts index 16ccc824..f86d7d4f 100644 --- a/src/client/theme-default/utils.ts +++ b/src/client/theme-default/utils.ts @@ -1,4 +1,4 @@ -import { useSiteData, Route } from 'vitepress' +import { Route } from 'vitepress' export const hashRE = /#.*$/ export const extRE = /(index)?\.(md|html)$/ @@ -13,10 +13,6 @@ export function isArray(value: any): value is any[] { return Array.isArray(value) } -export function withBase(path: string) { - return (useSiteData().value.base + path).replace(/\/+/g, '/') -} - export function isExternal(path: string): boolean { return outboundRE.test(path) } From cfbc32fe00b1d91d722a2708b3c56d3bbed9db79 Mon Sep 17 00:00:00 2001 From: Matias Capeletto <matias.capeletto@gmail.com> Date: Thu, 26 Nov 2020 17:59:01 +0100 Subject: [PATCH 05/16] docs: add asset handling page (#156) Co-authored-by: Kia King Ishii <kia.king.08@gmail.com> --- docs/.vitepress/config.js | 1 + docs/guide/assets.md | 35 +++++++++++++++++++++++++++++++++++ docs/guide/global-computed.md | 8 ++++++++ 3 files changed, 44 insertions(+) create mode 100644 docs/guide/assets.md diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 6a7dc24e..e9a69a0e 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -42,6 +42,7 @@ function getGuideSidebar() { { text: 'What is VitePress?', link: '/' }, { text: 'Getting Started', link: '/guide/getting-started' }, { text: 'Configuration', link: '/guide/configuration' }, + { text: 'Asset Handling', link: '/guide/assets' }, { text: 'Markdown Extensions', link: '/guide/markdown' }, { text: 'Deploying', link: '/guide/deploy' } ] diff --git a/docs/guide/assets.md b/docs/guide/assets.md new file mode 100644 index 00000000..fbd25cc8 --- /dev/null +++ b/docs/guide/assets.md @@ -0,0 +1,35 @@ +# Asset Handling + +All Markdown files are compiled into Vue components and processed by [Vite](https://github.com/vitejs/vite). You can, **and should**, reference any assets using relative URLs: + +```md +![An image](./image.png) +``` + +You can reference static assets in your markdown files, your `*.vue` components in the theme, styles and plain `.css` files either using absolute public paths (based on project root) or relative paths (based on your file system). The latter is similar to the behavior you are used to if you have used `vue-cli` or webpack's `file-loader`. + +Common image, media, and font filetypes are detected and included as assets automatically. + +All referenced assets, including those using absolute paths, will be copied to the dist folder with a hashed file name in the production build. Never-referenced assets will not be copied. Similar to `vue-cli`, image assets smaller than 4kb will be base64 inlined. + +All **static** path references, including absolute paths, should be based on your working directory structure. + +## Public Files + +Sometimes you may need to provide static assets that are not directly referenced in any of your Markdown or theme components (for example, favicons and PWA icons). The `public` directory under project root can be used as an escape hatch to provide static assets that either are never referenced in source code (e.g. `robots.txt`), or must retain the exact same file name (without hashing). + +Assets placed in `public` will be copied to the root of the dist directory as-is. + +Note that you should reference files placed in `public` using root absolute path - for example, `public/icon.png` should always be referenced in source code as `/icon.png`. + +## Base URL + +If your site is deployed to a non-root URL, you will need to set the `base` option in `.vitepress/config.js`. For example, if you plan to deploy your site to `https://foo.github.io/bar/`, then `base` should be set to `'/bar/'` (it should always start and end with a slash). + +With a base URL, to reference an image in `public`, you'd have to use URLs like `/bar/image.png`. But this is brittle if you ever decide to change the base. To help with that, VitePress provides a built-in helper `$withBase` (injected onto Vue's prototype) that generates the correct path: + +```html +<img :src="$withBase('/foo.png')" alt="foo"> +``` + +Note you can use the above syntax not only in theme components, but in your Markdown files as well. diff --git a/docs/guide/global-computed.md b/docs/guide/global-computed.md index 7221534a..d1c0d3f1 100644 --- a/docs/guide/global-computed.md +++ b/docs/guide/global-computed.md @@ -71,3 +71,11 @@ Value of the `<title>` label used for the current page. ## $description The content value of the `<meta name= "description" content= "...">` for the current page. + +## $withBase + +Helper method to generate correct path by prepending the `base` path configured in `.vitepress/config.js`. It's useful when you want to link to [public files with base path](./assets#public-files). + +```html +<img :src="$withBase('/foo.png')" alt="foo"> +``` From d90b9bdfb440e2d71a6d70e4e27765f96721c85a Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 02:23:07 +0900 Subject: [PATCH 06/16] style: refactor the style of app exports.ts --- src/client/app/exports.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/client/app/exports.ts b/src/client/app/exports.ts index 3c41ab3b..d45ea82d 100644 --- a/src/client/app/exports.ts +++ b/src/client/app/exports.ts @@ -1,6 +1,8 @@ // exports in this file are exposed to themes and md files via 'vitepress' // so the user can do `import { useRoute, useSiteData } from 'vitepress'`. +import { ComponentOptions } from 'vue' + // generic types export type { SiteData, PageData } from '/@types/shared' @@ -17,6 +19,7 @@ export { usePageData } from './composables/pageData' export { Content } from './components/Content' import _Debug from './components/Debug.vue' -import { ComponentOptions } from 'vue' + const Debug = _Debug as ComponentOptions + export { Debug } From 9062dd9a1fbd774d76e5ee88a8f5ad23ff146c3b Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 02:25:58 +0900 Subject: [PATCH 07/16] style: small fix for code style --- src/client/app/exports.ts | 2 +- types/shared.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/app/exports.ts b/src/client/app/exports.ts index d45ea82d..19392422 100644 --- a/src/client/app/exports.ts +++ b/src/client/app/exports.ts @@ -1,5 +1,5 @@ // exports in this file are exposed to themes and md files via 'vitepress' -// so the user can do `import { useRoute, useSiteData } from 'vitepress'`. +// so the user can do `import { useRoute, useSiteData } from 'vitepress'` import { ComponentOptions } from 'vue' diff --git a/types/shared.d.ts b/types/shared.d.ts index 8ecfea93..cf2aa73a 100644 --- a/types/shared.d.ts +++ b/types/shared.d.ts @@ -1,4 +1,4 @@ -// types shared between server and client. +// types shared between server and client export interface LocaleConfig { lang: string @@ -10,10 +10,10 @@ export interface LocaleConfig { } export interface SiteData<ThemeConfig = any> { + base: string lang: string title: string description: string - base: string head: HeadConfig[] themeConfig: ThemeConfig locales: Record<string, LocaleConfig> From 49ff3269cca45856fe15a883379b33f8e9faa27d Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 02:31:05 +0900 Subject: [PATCH 08/16] docs: fix some typos --- docs/config/basics.md | 2 +- docs/config/carbon-ads.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config/basics.md b/docs/config/basics.md index b9b03a33..1c4b71d0 100644 --- a/docs/config/basics.md +++ b/docs/config/basics.md @@ -52,6 +52,6 @@ Description for the site. This will render as a `<meta>` tag in the page HTML. ```js module.exports = { - title: 'A VitePress site' + description: 'A VitePress site' } ``` diff --git a/docs/config/carbon-ads.md b/docs/config/carbon-ads.md index 20abee95..166d6b36 100644 --- a/docs/config/carbon-ads.md +++ b/docs/config/carbon-ads.md @@ -1,4 +1,4 @@ -# Carbon Ads +# App Config: Carbon Ads VitePress has built in native support for [Carbon Ads](https://www.carbonads.net). By defining the Carbon Ads credentials in config, VitePress will display ads on the page. From 8c94cabf0df9cfd51ee0f089a80fb74a7b550204 Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 03:01:22 +0900 Subject: [PATCH 09/16] refactor: adjust the edit link external icon looks just a bit --- .../theme-default/components/icons/OutboundLink.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/client/theme-default/components/icons/OutboundLink.vue b/src/client/theme-default/components/icons/OutboundLink.vue index deb1c742..250db07c 100644 --- a/src/client/theme-default/components/icons/OutboundLink.vue +++ b/src/client/theme-default/components/icons/OutboundLink.vue @@ -1,13 +1,13 @@ <template functional> <svg - class="icon" + class="icon outbound" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" - width="16" - height="16" + width="15" + height="15" > <path fill="currentColor" @@ -21,11 +21,11 @@ </template> <style> -.icon { +.icon.outbound { position: relative; top: -1px; display: inline-block; - color: #aaa; vertical-align: middle; + color: var(--c-text-lighter); } </style> From fad85b80fd1d4be9269d233fe551af5c79321a5f Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 03:02:06 +0900 Subject: [PATCH 10/16] refactor: float h2 code block when there's carbon ads --- src/client/theme-default/styles/code.css | 1 + src/client/theme-default/styles/layout.css | 1 + 2 files changed, 2 insertions(+) diff --git a/src/client/theme-default/styles/code.css b/src/client/theme-default/styles/code.css index 22f6267b..adc2a221 100644 --- a/src/client/theme-default/styles/code.css +++ b/src/client/theme-default/styles/code.css @@ -20,6 +20,7 @@ div[class*='language-'] { position: relative; margin: 1rem -1.5rem; background-color: var(--code-bg-color); + overflow-x: auto; } li > div[class*='language-'] { diff --git a/src/client/theme-default/styles/layout.css b/src/client/theme-default/styles/layout.css index a3169802..5038a14b 100644 --- a/src/client/theme-default/styles/layout.css +++ b/src/client/theme-default/styles/layout.css @@ -86,6 +86,7 @@ h2 { padding-bottom: .3rem; line-height: 1.25; font-size: 1.65rem; + overflow-x: auto; } h2 + h3 { From f2dafa05f29894e4262eeb06bce74f1ce1e456dd Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 10:04:32 +0900 Subject: [PATCH 11/16] chore: fix netlify build failure --- src/client/app/index.ts | 2 +- src/client/app/mixin.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/app/index.ts b/src/client/app/index.ts index ebcfeb5b..a9f67ae0 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -4,7 +4,7 @@ import { createRouter, RouterSymbol } from './router' import { mixinGlobalComputed, mixinGlobalComponents } from './mixin' import { siteDataRef } from './composables/siteData' import { useSiteDataByRoute } from './composables/siteDataByRoute' -import { usePageData } from './composables/PageData' +import { usePageData } from './composables/pageData' import { useUpdateHead } from './composables/head' import Theme from '/@theme/index' diff --git a/src/client/app/mixin.ts b/src/client/app/mixin.ts index 7d1ddb4d..75f18460 100644 --- a/src/client/app/mixin.ts +++ b/src/client/app/mixin.ts @@ -1,7 +1,7 @@ import { App } from 'vue' import { joinPath } from './utils' import { SiteDataRef } from './composables/siteData' -import { PageDataRef } from './composables/PageData' +import { PageDataRef } from './composables/pageData' import { Content } from './components/Content' import Debug from './components/Debug.vue' From 224c24c36a0888dec3da2c3fcb50571dbe40a3d6 Mon Sep 17 00:00:00 2001 From: Asko Kauppi <akauppi@gmail.com> Date: Fri, 27 Nov 2020 03:06:40 +0200 Subject: [PATCH 12/16] docs: fix typo (#161) Lowercasing `description` to be akin to other entries. Shows especially in the navigation pane. --- docs/config/basics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config/basics.md b/docs/config/basics.md index 1c4b71d0..d0d6719d 100644 --- a/docs/config/basics.md +++ b/docs/config/basics.md @@ -43,7 +43,7 @@ module.exports = { } ``` -## Description +## description - Type: `string` - Default: `A VitePress site` From b9d63c0719b04fb5f6ce57c204623679c6f84fd8 Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 10:12:42 +0900 Subject: [PATCH 13/16] docs: fix broken link in config page (#160) close #160 --- docs/guide/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/configuration.md b/docs/guide/configuration.md index 85617686..ab071a5e 100644 --- a/docs/guide/configuration.md +++ b/docs/guide/configuration.md @@ -20,4 +20,4 @@ module.exports = { } ``` -Check out the [Config Reference](/config/) for a full list of options. +Check out the [Config Reference](/config/basics) for a full list of options. From 30740d3516e3f7cce0e083faa90a732d9916f9af Mon Sep 17 00:00:00 2001 From: Matias Capeletto <matias.capeletto@gmail.com> Date: Fri, 27 Nov 2020 07:31:34 +0100 Subject: [PATCH 14/16] fix: align $title with vuepress (#158) (#163) fix #158 --- src/client/app/mixin.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/client/app/mixin.ts b/src/client/app/mixin.ts index 75f18460..e33a5b9e 100644 --- a/src/client/app/mixin.ts +++ b/src/client/app/mixin.ts @@ -44,7 +44,9 @@ export function mixinGlobalComputed( $title: { get() { - return page.value.title || siteByRoute.value.title + return page.value.title + ? page.value.title + ' | ' + siteByRoute.value.title + : siteByRoute.value.title } }, From 01d2837474caef19daaf0be4b3c283dbe85a09da Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 17:12:55 +0900 Subject: [PATCH 15/16] fix: siteData passed to enhanceApp being siteDataByRoute (#159) fix #159 --- src/client/app/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/app/index.ts b/src/client/app/index.ts index a9f67ae0..db2fa13d 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -74,7 +74,7 @@ export function createApp() { Theme.enhanceApp({ app, router, - siteData: siteDataByRouteRef + siteData: siteDataRef }) } From 77bb75f7eec8f149e32a52d66be76c21d1f282c9 Mon Sep 17 00:00:00 2001 From: Kia King Ishii <kia.king.08@gmail.com> Date: Fri, 27 Nov 2020 17:52:46 +0900 Subject: [PATCH 16/16] refactor: client app index --- src/client/app/index.ts | 93 ++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/src/client/app/index.ts b/src/client/app/index.ts index db2fa13d..ac1f8f88 100644 --- a/src/client/app/index.ts +++ b/src/client/app/index.ts @@ -1,6 +1,6 @@ -import { createApp as createClientApp, createSSRApp } from 'vue' +import { App, createApp as createClientApp, createSSRApp } from 'vue' import { inBrowser, pathToFile } from './utils' -import { createRouter, RouterSymbol } from './router' +import { Router, RouterSymbol, createRouter } from './router' import { mixinGlobalComputed, mixinGlobalComponents } from './mixin' import { siteDataRef } from './composables/siteData' import { useSiteDataByRoute } from './composables/siteDataByRoute' @@ -11,10 +11,47 @@ import Theme from '/@theme/index' const NotFound = Theme.NotFound || (() => '404 Not Found') export function createApp() { + const router = newRouter() + + handleHMR(router) + + const app = newApp() + + app.provide(RouterSymbol, router) + + const siteDataByRouteRef = useSiteDataByRoute(router.route) + const pageDataRef = usePageData(router.route) + + if (inBrowser) { + // dynamically update head tags + useUpdateHead(router.route, siteDataByRouteRef) + } + + mixinGlobalComputed(app, siteDataRef, siteDataByRouteRef, pageDataRef) + mixinGlobalComponents(app) + + if (Theme.enhanceApp) { + Theme.enhanceApp({ + app, + router, + siteData: siteDataRef + }) + } + + return { app, router } +} + +function newApp(): App { + return process.env.NODE_ENV === 'production' + ? createSSRApp(Theme.Layout) + : createClientApp(Theme.Layout) +} + +function newRouter(): Router { let isInitialPageLoad = inBrowser let initialPath: string - const router = createRouter((path) => { + return createRouter((path) => { let pageFilePath = pathToFile(path) if (isInitialPageLoad) { @@ -23,62 +60,40 @@ export function createApp() { // 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). + // 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 - // in browser: native dynamic import + return import(/*@vite-ignore*/ pageFilePath) - } else { - // SSR, sync require - return require(pageFilePath) } + + // SSR: sync require + return require(pageFilePath) }, NotFound) +} +function handleHMR(router: Router): void { // update route.data on HMR updates of active page if (import.meta.hot) { // hot reload pageData import.meta.hot!.on('vitepress:pageData', (payload) => { - if ( - payload.path.replace(/(\bindex)?\.md$/, '') === - location.pathname.replace(/(\bindex)?\.html$/, '') - ) { + if (shouldHotReload(payload)) { router.route.data = payload.pageData } }) } +} - const app = - process.env.NODE_ENV === 'production' - ? createSSRApp(Theme.Layout) - : createClientApp(Theme.Layout) - - app.provide(RouterSymbol, router) - - mixinGlobalComponents(app) - - const siteDataByRouteRef = useSiteDataByRoute(router.route) - const pageDataRef = usePageData(router.route) - - if (inBrowser) { - // dynamically update head tags - useUpdateHead(router.route, siteDataByRouteRef) - } - - mixinGlobalComputed(app, siteDataRef, siteDataByRouteRef, pageDataRef) - - if (Theme.enhanceApp) { - Theme.enhanceApp({ - app, - router, - siteData: siteDataRef - }) - } +function shouldHotReload(payload: any): boolean { + const payloadPath = payload.path.replace(/(\bindex)?\.md$/, '') + const locationPath = location.pathname.replace(/(\bindex)?\.html$/, '') - return { app, router } + return payloadPath === locationPath } if (inBrowser) {