refactor: migrate default theme to use script-setup (#137)

Co-authored-by: Kia King Ishii <kia.king.08@gmail.com>
pull/156/head
Evan You 4 years ago committed by GitHub
parent 136a56e74d
commit b127aeeaf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -62,8 +62,8 @@
"url": "https://github.com/vuejs/vitepress/issues" "url": "https://github.com/vuejs/vitepress/issues"
}, },
"dependencies": { "dependencies": {
"@vue/compiler-sfc": "^3.0.2", "@vue/compiler-sfc": "^3.0.3",
"@vue/server-renderer": "^3.0.2", "@vue/server-renderer": "^3.0.3",
"chalk": "^4.1.0", "chalk": "^4.1.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"diacritics": "^1.3.0", "diacritics": "^1.3.0",
@ -82,8 +82,8 @@
"prismjs": "^1.20.0", "prismjs": "^1.20.0",
"rollup": "^2.33.3", "rollup": "^2.33.3",
"slash": "^3.0.0", "slash": "^3.0.0",
"vite": "^1.0.0-rc.9", "vite": "^1.0.0-rc.13",
"vue": "^3.0.2" "vue": "^3.0.3"
}, },
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^9.0.1", "@types/fs-extra": "^9.0.1",

@ -45,7 +45,7 @@
<Debug /> <Debug />
</template> </template>
<script> <script setup lang="ts">
import { ref, computed, watch } from 'vue' import { ref, computed, watch } from 'vue'
import NavBar from './components/NavBar.vue' import NavBar from './components/NavBar.vue'
import Home from './components/Home.vue' import Home from './components/Home.vue'
@ -54,76 +54,56 @@ import SideBar from './components/SideBar.vue'
import Page from './components/Page.vue' import Page from './components/Page.vue'
import { useRoute, useSiteData, useSiteDataByRoute } from 'vitepress' import { useRoute, useSiteData, useSiteDataByRoute } from 'vitepress'
export default { const route = useRoute()
components: { const siteData = useSiteData()
Home, const siteRouteData = useSiteDataByRoute()
NavBar,
ToggleSideBarButton,
SideBar,
Page
},
setup() { const openSideBar = ref(false)
const route = useRoute() const enableHome = computed(() => !!route.data.frontmatter.home)
const siteData = useSiteData()
const siteRouteData = useSiteDataByRoute()
const openSideBar = ref(false) const showNavbar = computed(() => {
const enableHome = computed(() => !!route.data.frontmatter.home) const { themeConfig } = siteRouteData.value
const { frontmatter } = route.data
const showNavbar = computed(() => { if (frontmatter.navbar === false || themeConfig.navbar === false) {
const { themeConfig } = siteRouteData.value return false
const { frontmatter } = route.data }
if ( return (
frontmatter.navbar === false siteData.value.title ||
|| themeConfig.navbar === false) { themeConfig.logo ||
return false themeConfig.repo ||
} themeConfig.nav
return ( )
siteData.value.title })
|| themeConfig.logo
|| themeConfig.repo
|| themeConfig.nav
)
})
const showSidebar = computed(() => {
const { frontmatter } = route.data
const { themeConfig } = siteRouteData.value
return (
!frontmatter.home
&& frontmatter.sidebar !== false
&& ((typeof themeConfig.sidebar === 'object') && (Object.keys(themeConfig.sidebar).length != 0)
|| (Array.isArray(themeConfig.sidebar) && themeConfig.sidebar.length != 0))
)
})
const pageClasses = computed(() => { const showSidebar = computed(() => {
return [{ const { frontmatter } = route.data
'no-navbar': !showNavbar.value, const { themeConfig } = siteRouteData.value
'sidebar-open': openSideBar.value, return (
'no-sidebar': !showSidebar.value !frontmatter.home &&
}] frontmatter.sidebar !== false &&
}) ((typeof themeConfig.sidebar === 'object' &&
Object.keys(themeConfig.sidebar).length != 0) ||
(Array.isArray(themeConfig.sidebar) && themeConfig.sidebar.length != 0))
)
})
const toggleSidebar = (to) => { const pageClasses = computed(() => {
openSideBar.value = typeof to === 'boolean' ? to : !openSideBar.value return [
{
'no-navbar': !showNavbar.value,
'sidebar-open': openSideBar.value,
'no-sidebar': !showSidebar.value
} }
]
})
const hideSidebar = toggleSidebar.bind(null, false) const toggleSidebar = (to) => {
// close the sidebar when navigating to a different location openSideBar.value = typeof to === 'boolean' ? to : !openSideBar.value
watch(route, hideSidebar)
// TODO: route only changes when the pathname changes
// listening to hashchange does nothing because it's prevented in router
return {
showNavbar,
showSidebar,
openSideBar,
pageClasses,
enableHome,
toggleSidebar
}
}
} }
const hideSidebar = toggleSidebar.bind(null, false)
// close the sidebar when navigating to a different location
watch(route, hideSidebar)
// TODO: route only changes when the pathname changes
// listening to hashchange does nothing because it's prevented in router
</script> </script>

@ -2,15 +2,11 @@
<div class="theme"> <div class="theme">
<h1>404</h1> <h1>404</h1>
<blockquote>{{ getMsg() }}</blockquote> <blockquote>{{ getMsg() }}</blockquote>
<a :href="$site.base" aria-label="go to home"> <a :href="$site.base" aria-label="go to home">Take me home.</a>
Take me home.
</a>
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'
const msgs = [ const msgs = [
`There's nothing here.`, `There's nothing here.`,
`How did we get here?`, `How did we get here?`,
@ -18,11 +14,7 @@ const msgs = [
`Looks like we've got some broken links.` `Looks like we've got some broken links.`
] ]
export default defineComponent({ function getMsg() {
setup: () => ({ return msgs[Math.floor(Math.random() * msgs.length)]
getMsg() { }
return msgs[Math.floor(Math.random() * msgs.length)]
}
})
})
</script> </script>

@ -6,25 +6,11 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'
import { useEditLink } from '../composables/editLink' import { useEditLink } from '../composables/editLink'
import OutboundLink from './icons/OutboundLink.vue' import OutboundLink from './icons/OutboundLink.vue'
export default defineComponent({ const { url, text } = useEditLink()
components: {
OutboundLink
},
setup() {
const { url, text } = useEditLink()
return {
url,
text
}
}
})
</script> </script>
<style scoped> <style scoped>

@ -4,26 +4,17 @@
v-if="data.heroImage" v-if="data.heroImage"
:src="heroImageSrc" :src="heroImageSrc"
:alt="data.heroAlt || 'hero'" :alt="data.heroAlt || 'hero'"
> />
<h1 <h1 v-if="data.heroText !== null" id="main-title">
v-if="data.heroText !== null"
id="main-title"
>
{{ data.heroText || siteTitle || 'Hello' }} {{ data.heroText || siteTitle || 'Hello' }}
</h1> </h1>
<p <p v-if="data.tagline !== null" class="description">
v-if="data.tagline !== null"
class="description"
>
{{ data.tagline || siteDescription || 'Welcome to your VitePress site' }} {{ data.tagline || siteDescription || 'Welcome to your VitePress site' }}
</p> </p>
<p <p v-if="data.actionText && data.actionLink" class="action">
v-if="data.actionText && data.actionLink"
class="action"
>
<a class="action-link" :href="actionLink.link"> <a class="action-link" :href="actionLink.link">
{{ actionLink.text }} {{ actionLink.text }}
</a> </a>
@ -31,58 +22,35 @@
<slot name="hero" /> <slot name="hero" />
</header> </header>
<div <div v-if="data.features && data.features.length" class="features">
v-if="data.features && data.features.length" <div v-for="(feature, index) in data.features" :key="index" class="feature">
class="features"
>
<div
v-for="(feature, index) in data.features"
:key="index"
class="feature"
>
<h2>{{ feature.title }}</h2> <h2>{{ feature.title }}</h2>
<p>{{ feature.details }}</p> <p>{{ feature.details }}</p>
</div> </div>
<slot name="features" /> <slot name="features" />
</div> </div>
<div <div v-if="data.footer" class="footer">
v-if="data.footer"
class="footer"
>
{{ data.footer }} {{ data.footer }}
<slot name="footer" /> <slot name="footer" />
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent, computed } from 'vue' import { computed } from 'vue'
import { useRoute, useSiteData } from 'vitepress' import { useRoute, useSiteData } from 'vitepress'
import { withBase } from '../utils' import { withBase } from '../utils'
export default defineComponent({ const route = useRoute()
setup() { const siteData = useSiteData()
const route = useRoute() const data = computed(() => route.data.frontmatter)
const siteData = useSiteData() const actionLink = computed(() => ({
link: data.value.actionLink,
const data = computed(() => route.data.frontmatter) text: data.value.actionText
const actionLink = computed(() => ({ }))
link: data.value.actionLink, const heroImageSrc = computed(() => withBase(data.value.heroImage))
text: data.value.actionText const siteTitle = computed(() => siteData.value.title)
})) const siteDescription = computed(() => siteData.value.description)
const heroImageSrc = computed(() => withBase(data.value.heroImage))
const siteTitle = computed(() => siteData.value.title)
const siteDescription = computed(() => siteData.value.description)
return {
data,
actionLink,
heroImageSrc,
siteTitle,
siteDescription
}
}
})
</script> </script>
<style scoped> <style scoped>

@ -10,17 +10,9 @@
<slot name="search" /> <slot name="search" />
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'
import NavBarTitle from './NavBarTitle.vue' import NavBarTitle from './NavBarTitle.vue'
import NavBarLinks from './NavBarLinks.vue' import NavBarLinks from './NavBarLinks.vue'
export default defineComponent({
components: {
NavBarTitle,
NavBarLinks
}
})
</script> </script>
<style scoped> <style scoped>

@ -1,77 +0,0 @@
import { defineComponent, computed, PropType } from 'vue'
import { useRoute } from 'vitepress'
import { withBase, isExternal } from '../utils'
import { DefaultTheme } from '../config'
import OutboundLink from './icons/OutboundLink.vue'
const normalizePath = (path: string): string => {
path = path
.replace(/#.*$/, '')
.replace(/\?.*$/, '')
.replace(/\.html$/, '')
if (path.endsWith('/')) {
path += 'index'
}
return path
}
export default defineComponent({
components: {
OutboundLink
},
props: {
item: {
type: Object as PropType<DefaultTheme.NavItemWithLink>,
required: true
}
},
setup(props) {
const item = props.item
const route = useRoute()
const classes = computed(() => ({
active: isActiveLink.value,
external: isExternalLink.value
}))
const isActiveLink = computed(() => {
return normalizePath(withBase(item.link)) === normalizePath(route.path)
})
const isExternalLink = computed(() => {
return isExternal(item.link)
})
const href = computed(() => {
return isExternalLink.value ? item.link : withBase(item.link)
})
const target = computed(() => {
if (item.target) {
return item.target
}
return isExternalLink.value ? '_blank' : ''
})
const rel = computed(() => {
if (item.rel) {
return item.rel
}
return isExternalLink.value ? 'noopener noreferrer' : ''
})
return {
classes,
isActiveLink,
isExternalLink,
href,
target,
rel
}
}
})

@ -13,7 +13,63 @@
</div> </div>
</template> </template>
<script src="./NavBarLink"></script> <script setup lang="ts">
import { computed, defineProps } from 'vue'
import { useRoute } from 'vitepress'
import { withBase, isExternal } from '../utils'
import type { DefaultTheme } from '../config'
import OutboundLink from './icons/OutboundLink.vue'
const { item } = defineProps<{
item: DefaultTheme.NavItemWithLink
}>()
const normalizePath = (path: string): string => {
path = path
.replace(/#.*$/, '')
.replace(/\?.*$/, '')
.replace(/\.html$/, '')
if (path.endsWith('/')) {
path += 'index'
}
return path
}
const route = useRoute()
const classes = computed(() => ({
active: isActiveLink.value,
external: isExternalLink.value
}))
const isActiveLink = computed(() => {
return normalizePath(withBase(item.link)) === normalizePath(route.path)
})
const isExternalLink = computed(() => {
return isExternal(item.link)
})
const href = computed(() => {
return isExternalLink.value ? item.link : withBase(item.link)
})
const target = computed(() => {
if (item.target) {
return item.target
}
return isExternalLink.value ? '_blank' : ''
})
const rel = computed(() => {
if (item.rel) {
return item.rel
}
return isExternalLink.value ? 'noopener noreferrer' : ''
})
</script>
<style scoped> <style scoped>
.navbar-link { .navbar-link {

@ -1,101 +0,0 @@
import { computed } from 'vue'
import { useSiteData, useSiteDataByRoute, useRoute } from 'vitepress'
import { inBrowser } from '/@app/utils'
import NavBarLink from './NavBarLink.vue'
import NavDropdownLink from './NavDropdownLink.vue'
import { DefaultTheme } from '../config'
const platforms = ['GitHub', 'GitLab', 'Bitbucket'].map(
(platform) => [platform, new RegExp(platform, 'i')] as const
)
export default {
components: {
NavBarLink,
NavDropdownLink
},
setup() {
const siteDataByRoute = useSiteDataByRoute()
const siteData = useSiteData()
const route = useRoute()
const repoInfo = computed(() => {
const theme = siteData.value.themeConfig as DefaultTheme.Config
const repo = theme.docsRepo || theme.repo
let text: string | undefined = theme.repoLabel
if (repo) {
const link = /^https?:/.test(repo) ? repo : `https://github.com/${repo}`
if (!text) {
// if no label is provided, deduce it from the repo url
const repoHosts = link.match(/^https?:\/\/[^/]+/)
if (repoHosts) {
const repoHost = repoHosts[0]
const foundPlatform = platforms.find(([_platform, re]) =>
re.test(repoHost)
)
text = foundPlatform && foundPlatform[0]
}
}
return { link, text: text || 'Source' }
}
return null
})
const localeCandidates = computed(() => {
const locales = siteData.value.themeConfig.locales
if (!locales) {
return null
}
const localeKeys = Object.keys(locales)
if (localeKeys.length <= 1) {
return null
}
// handle site base
const siteBase = inBrowser ? siteData.value.base : '/'
const siteBaseWithoutSuffix = siteBase.endsWith('/')
? siteBase.slice(0, -1)
: siteBase
// remove site base in browser env
const routerPath = route.path.slice(siteBaseWithoutSuffix.length)
const currentLangBase = localeKeys.find((v) => {
if (v === '/') {
return false
}
return routerPath.startsWith(v)
})
const currentContentPath = currentLangBase
? routerPath.substring(currentLangBase.length - 1)
: routerPath
const candidates = localeKeys.map((v) => {
const localePath = v.endsWith('/') ? v.slice(0, -1) : v
return {
text: locales[v].label || locales[v].lang,
link: `${localePath}${currentContentPath}`
}
})
const currentLangKey = currentLangBase ? currentLangBase : '/'
const selectText = locales[currentLangKey].selectText
? locales[currentLangKey].selectText
: 'Languages'
return {
text: selectText,
items: candidates
}
})
const navData = computed(() => {
return siteDataByRoute.value.themeConfig.nav
})
return {
navData,
repoInfo,
localeCandidates
}
}
}

@ -11,7 +11,94 @@
</nav> </nav>
</template> </template>
<script src="./NavBarLinks"></script> <script setup lang="ts">
import { computed } from 'vue'
import { useSiteData, useSiteDataByRoute, useRoute } from 'vitepress'
import { inBrowser } from '/@app/utils'
import NavBarLink from './NavBarLink.vue'
import NavDropdownLink from './NavDropdownLink.vue'
import type { DefaultTheme } from '../config'
const platforms = ['GitHub', 'GitLab', 'Bitbucket'].map(
(platform) => [platform, new RegExp(platform, 'i')] as const
)
const siteDataByRoute = useSiteDataByRoute()
const siteData = useSiteData()
const route = useRoute()
const repoInfo = computed(() => {
const theme = siteData.value.themeConfig as DefaultTheme.Config
const repo = theme.docsRepo || theme.repo
let text: string | undefined = theme.repoLabel
if (repo) {
const link = /^https?:/.test(repo) ? repo : `https://github.com/${repo}`
if (!text) {
// if no label is provided, deduce it from the repo url
const repoHosts = link.match(/^https?:\/\/[^/]+/)
if (repoHosts) {
const repoHost = repoHosts[0]
const foundPlatform = platforms.find(([_platform, re]) =>
re.test(repoHost)
)
text = foundPlatform && foundPlatform[0]
}
}
return { link, text: text || 'Source' }
}
return null
})
const localeCandidates = computed(() => {
const locales = siteData.value.themeConfig.locales
if (!locales) {
return null
}
const localeKeys = Object.keys(locales)
if (localeKeys.length <= 1) {
return null
}
// handle site base
const siteBase = inBrowser ? siteData.value.base : '/'
const siteBaseWithoutSuffix = siteBase.endsWith('/')
? siteBase.slice(0, -1)
: siteBase
// remove site base in browser env
const routerPath = route.path.slice(siteBaseWithoutSuffix.length)
const currentLangBase = localeKeys.find((v) => {
if (v === '/') {
return false
}
return routerPath.startsWith(v)
})
const currentContentPath = currentLangBase
? routerPath.substring(currentLangBase.length - 1)
: routerPath
const candidates = localeKeys.map((v) => {
const localePath = v.endsWith('/') ? v.slice(0, -1) : v
return {
text: locales[v].label || locales[v].lang,
link: `${localePath}${currentContentPath}`
}
})
const currentLangKey = currentLangBase ? currentLangBase : '/'
const selectText = locales[currentLangKey].selectText
? locales[currentLangKey].selectText
: 'Languages'
return {
text: selectText,
items: candidates
}
})
const navData = computed(() => {
return siteDataByRoute.value.themeConfig.nav
})
</script>
<style scoped> <style scoped>
.navbar-links { .navbar-links {

@ -1,42 +0,0 @@
import NavBarLink from './NavBarLink.vue'
import { defineComponent, ref, watch, PropType } from 'vue'
import { useRoute } from 'vitepress'
import { DefaultTheme } from '../config'
export default defineComponent({
name: 'DropdownLink',
components: {
NavBarLink
},
props: {
item: {
type: Object as PropType<DefaultTheme.NavItemWithChildren>,
required: true
}
},
setup(props) {
const open = ref(false)
const route = useRoute()
watch(
() => route.path,
() => {
open.value = false
}
)
const setOpen = (value: boolean) => {
open.value = value
}
const isLastItemOfArray = <T>(item: T, array: T[]) => {
return array.length && array.indexOf(item) === array.length - 1
}
return {
open,
setOpen,
isLastItemOfArray
}
}
})

@ -11,7 +11,11 @@
</button> </button>
<ul class="nav-dropdown"> <ul class="nav-dropdown">
<li v-for="(subItem, index) in item.items" :key="subItem.link || index" class="dropdown-item"> <li
v-for="(subItem, index) in item.items"
:key="subItem.link || index"
class="dropdown-item"
>
<h4 v-if="subItem.items">{{ subItem.text }}</h4> <h4 v-if="subItem.items">{{ subItem.text }}</h4>
<ul v-if="subItem.items" class="dropdown-subitem-wrapper"> <ul v-if="subItem.items" class="dropdown-subitem-wrapper">
<li <li
@ -22,10 +26,10 @@
<NavBarLink <NavBarLink
:item="childSubItem" :item="childSubItem"
@focusout=" @focusout="
isLastItemOfArray(childSubItem, subItem.items) && isLastItemOfArray(childSubItem, subItem.items) &&
isLastItemOfArray(subItem, item.items) && isLastItemOfArray(subItem, item.items) &&
setOpen(false) setOpen(false)
" "
/> />
</li> </li>
</ul> </ul>
@ -40,7 +44,34 @@
</div> </div>
</template> </template>
<script src="./NavDropdownLink"></script> <script setup lang="ts">
import NavBarLink from './NavBarLink.vue'
import { ref, watch, defineProps } from 'vue'
import { useRoute } from 'vitepress'
import type { DefaultTheme } from '../config'
defineProps<{
item: DefaultTheme.NavItemWithChildren
}>()
const open = ref(false)
const route = useRoute()
watch(
() => route.path,
() => {
open.value = false
}
)
const setOpen = (value: boolean) => {
open.value = value
}
const isLastItemOfArray = <T>(item: T, array: T[]) => {
return array.length && array.indexOf(item) === array.length - 1
}
</script>
<style> <style>
.dropdown-wrapper { .dropdown-wrapper {

@ -17,30 +17,13 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'
import { useNextAndPrevLinks } from '../composables/nextAndPrevLinks'
import { withBase } from '../utils' import { withBase } from '../utils'
import { useNextAndPrevLinks } from '../composables/nextAndPrevLinks'
import ArrowLeft from './icons/ArrowLeft.vue' import ArrowLeft from './icons/ArrowLeft.vue'
import ArrowRight from './icons/ArrowRight.vue' import ArrowRight from './icons/ArrowRight.vue'
export default defineComponent({ const { hasLinks, prev, next } = useNextAndPrevLinks()
components: {
ArrowLeft,
ArrowRight
},
setup () {
const { hasLinks, prev, next } = useNextAndPrevLinks()
return {
hasLinks,
prev,
next,
withBase,
}
}
})
</script> </script>
<style scoped> <style scoped>
@ -96,6 +79,10 @@ export default defineComponent({
transform: translateY(1px); transform: translateY(1px);
} }
.icon-prev { margin-right: 8px; } .icon-prev {
.icon-next { margin-left: 8px; } margin-right: 8px;
}
.icon-next {
margin-left: 8px;
}
</style> </style>

@ -14,17 +14,9 @@
</div> </div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'
import PageFooter from './PageFooter.vue' import PageFooter from './PageFooter.vue'
import NextAndPrevLinks from './NextAndPrevLinks.vue' import NextAndPrevLinks from './NextAndPrevLinks.vue'
export default defineComponent({
components: {
PageFooter,
NextAndPrevLinks
}
})
</script> </script>
<style scoped> <style scoped>

@ -12,20 +12,13 @@
</aside> </aside>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue' import { defineProps } from 'vue'
import NavBarLinks from './NavBarLinks.vue' import NavBarLinks from './NavBarLinks.vue'
import SideBarLinks from './SideBarLinks.vue' import SideBarLinks from './SideBarLinks.vue'
export default defineComponent({ defineProps({
components: { open: { type: Boolean, required: true }
NavBarLinks,
SideBarLinks
},
props: {
open: { type: Boolean, required: true }
}
}) })
</script> </script>
@ -41,7 +34,7 @@ export default defineComponent({
background-color: var(--c-bg); background-color: var(--c-bg);
overflow-y: auto; overflow-y: auto;
transform: translateX(-100%); transform: translateX(-100%);
transition: transform .25s ease; transition: transform 0.25s ease;
} }
@media (min-width: 720px) { @media (min-width: 720px) {

@ -1,29 +1,12 @@
<template> <template>
<ul v-if="items.length > 0" class="sidebar-links"> <ul v-if="items.length > 0" class="sidebar-links">
<SideBarLink <SideBarLink v-for="item of items" :key="item.text" :item="item" />
v-for="item of items"
:key="item.text"
:item="item"
/>
</ul> </ul>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'
import { useSideBar } from '../composables/sideBar' import { useSideBar } from '../composables/sideBar'
import { SideBarLink } from './SideBarLink' import { SideBarLink } from './SideBarLink'
export default defineComponent({ const items = useSideBar()
components: {
SideBarLink
},
setup() {
const items = useSideBar()
return {
items
}
}
})
</script> </script>

@ -15,6 +15,8 @@ export type BuildOptions = Pick<
> >
export async function build(buildOptions: BuildOptions = {}) { export async function build(buildOptions: BuildOptions = {}) {
const start = Date.now()
process.env.NODE_ENV = 'production' process.env.NODE_ENV = 'production'
const siteConfig = await resolveConfig(buildOptions.root) const siteConfig = await resolveConfig(buildOptions.root)
@ -66,4 +68,6 @@ export async function build(buildOptions: BuildOptions = {}) {
} finally { } finally {
await fs.remove(siteConfig.tempDir) await fs.remove(siteConfig.tempDir)
} }
console.log(`build complete in ${((Date.now() - start) / 1000).toFixed(2)}s.`)
} }

@ -85,10 +85,14 @@ export async function bundle(
}, },
generateBundle(_options, bundle) { generateBundle(_options, bundle) {
if (!isClientBuild) {
return
}
// for each .md entry chunk, adjust its name to its correct path. // for each .md entry chunk, adjust its name to its correct path.
for (const name in bundle) { for (const name in bundle) {
const chunk = bundle[name] const chunk = bundle[name]
if (isPageChunk(chunk) && isClientBuild) { if (isPageChunk(chunk)) {
// record page -> hash relations // record page -> hash relations
const hash = chunk.fileName.match(hashRE)![1] const hash = chunk.fileName.match(hashRE)![1]
const pageName = chunk.fileName.replace(hashRE, '') const pageName = chunk.fileName.replace(hashRE, '')
@ -150,26 +154,15 @@ export async function bundle(
let clientResult, serverResult let clientResult, serverResult
const spinner = ora() const spinner = ora()
spinner.start('building client bundle...') spinner.start('building client + server bundles...')
try {
clientResult = await build(viteOptions)
} catch (e) {
spinner.stopAndPersist({
symbol: failMark
})
throw e
}
spinner.stopAndPersist({
symbol: okMark
})
spinner.start('building server bundle...')
isClientBuild = false
try { try {
serverResult = await ssrBuild({ ;[clientResult, serverResult] = await Promise.all([
...viteOptions, build(viteOptions),
outDir: config.tempDir ssrBuild({
}) ...viteOptions,
outDir: config.tempDir
})
])
} catch (e) { } catch (e) {
spinner.stopAndPersist({ spinner.stopAndPersist({
symbol: failMark symbol: failMark

@ -63,6 +63,7 @@ export function createMarkdownToVueRenderFn(
} }
const scriptRE = /<\/script>/ const scriptRE = /<\/script>/
const scriptSetupRE = /<\s*script[^>]*\bsetup\b[^>]*/
const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/ const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/
const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/ const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/
@ -70,7 +71,11 @@ function injectPageData(tags: string[], data: PageData) {
const code = `\nexport const __pageData = ${JSON.stringify( const code = `\nexport const __pageData = ${JSON.stringify(
JSON.stringify(data) JSON.stringify(data)
)}` )}`
const existingScriptIndex = tags.findIndex((tag) => scriptRE.test(tag))
const existingScriptIndex = tags.findIndex((tag) => {
return scriptRE.test(tag) && !scriptSetupRE.test(tag)
})
if (existingScriptIndex > -1) { if (existingScriptIndex > -1) {
const tagSrc = tags[existingScriptIndex] const tagSrc = tags[existingScriptIndex]
// user has <script> tag inside markdown // user has <script> tag inside markdown
@ -82,7 +87,7 @@ function injectPageData(tags: string[], data: PageData) {
code + (hasDefaultExport ? `` : `\nexport default{}\n`) + `</script>` code + (hasDefaultExport ? `` : `\nexport default{}\n`) + `</script>`
) )
} else { } else {
tags.push(`<script>${code}\nexport default {}</script>`) tags.unshift(`<script>${code}\nexport default {}</script>`)
} }
return tags return tags

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save