Skip to content

Commit

Permalink
fix: hmr experience (#1708)
Browse files Browse the repository at this point in the history
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
KermanX and autofix-ci[bot] committed Jul 17, 2024
1 parent 96d8520 commit d7f4178
Show file tree
Hide file tree
Showing 22 changed files with 316 additions and 282 deletions.
2 changes: 1 addition & 1 deletion demo/starter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
"@slidev/theme-default": "^0.25.0",
"@slidev/theme-seriph": "^0.25.0",
"nodemon": "^3.1.4",
"vue": "^3.4.31"
"vue": "^3.4.32"
}
}
4 changes: 2 additions & 2 deletions demo/vue-runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"@slidev/cli": "workspace:*",
"@slidev/theme-default": "^0.25.0",
"@slidev/theme-seriph": "^0.25.0",
"@vue/compiler-sfc": "^3.4.31",
"@vue/compiler-sfc": "^3.4.32",
"nodemon": "^3.1.4",
"vue": "^3.4.31"
"vue": "^3.4.32"
}
}
31 changes: 14 additions & 17 deletions packages/client/composables/useClicks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { clamp, sum } from '@antfu/utils'
import type { ClicksContext, NormalizedRangeClickValue, NormalizedSingleClickValue, RawAtValue, RawSingleAtValue, SlideRoute } from '@slidev/types'
import type { Ref } from 'vue'
import { computed, ref, shallowReactive } from 'vue'
import { routeForceRefresh } from '../logic/route'
import { computed, onMounted, onUnmounted, ref, shallowReactive } from 'vue'

export function normalizeSingleAtValue(at: RawSingleAtValue): NormalizedSingleClickValue {
if (at === false || at === 'false')
Expand Down Expand Up @@ -54,17 +53,19 @@ export function createClicksContextBase(
get isMounted() {
return isMounted.value
},
onMounted: () => {
isMounted.value = true
// Convert maxMap to reactive
maxMap = shallowReactive(maxMap)
// Make sure the query is not greater than the total
context.current = current.value
},
onUnmounted: () => {
isMounted.value = false
relativeSizeMap = new Map()
maxMap = new Map()
setup() {
onMounted(() => {
isMounted.value = true
// Convert maxMap to reactive
maxMap = shallowReactive(maxMap)
// Make sure the query is not greater than the total
context.current = current.value
})
onUnmounted(() => {
isMounted.value = false
relativeSizeMap = new Map()
maxMap = new Map()
})
},
calculateSince(rawAt, size = 1) {
const at = normalizeSingleAtValue(rawAt)
Expand Down Expand Up @@ -144,13 +145,9 @@ export function createClicksContextBase(
maxMap.delete(el)
},
get currentOffset() {
// eslint-disable-next-line ts/no-unused-expressions
routeForceRefresh.value
return sum(...relativeSizeMap.values())
},
get total() {
// eslint-disable-next-line ts/no-unused-expressions
routeForceRefresh.value
return clicksTotalOverrides
?? (isMounted.value
? Math.max(0, ...maxMap.values())
Expand Down
6 changes: 3 additions & 3 deletions packages/client/env.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { computed, ref } from 'vue'
import { computed } from 'vue'
import { objectMap } from '@antfu/utils'
import configs from '#slidev/configs'

export { configs }

export const mode = __DEV__ ? 'dev' : 'build'

export const slideAspect = ref(configs.aspectRatio ?? (16 / 9))
export const slideWidth = ref(configs.canvasWidth ?? 980)
export const slideAspect = computed(() => configs.aspectRatio)
export const slideWidth = computed(() => configs.canvasWidth)

// To honor the aspect ratio more as possible, we need to approximate the height to the next integer.
// Doing this, we will prevent on print, to create an additional empty white page after each page.
Expand Down
1 change: 0 additions & 1 deletion packages/client/internals/PrintSlideClick.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ provideLocal(injectionSlidevContext, reactive({
<GlobalBottom />

<SlideWrapper
:is="route.component!"
:clicks-context="nav.clicksContext.value"
:class="getSlideClass(route)"
:route="route"
Expand Down
8 changes: 1 addition & 7 deletions packages/client/internals/QuickOverview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,6 @@ watchEffect(() => {
// Watch rowCount, make sure up and down shortcut work correctly.
overviewRowCount.value = rowCount.value
})
const activeSlidesLoaded = ref(false)
setTimeout(() => {
activeSlidesLoaded.value = true
}, 3000)
</script>

<template>
Expand All @@ -113,8 +108,7 @@ setTimeout(() => {
leave-to-class="opacity-0 scale-102 !backdrop-blur-0px"
>
<div
v-if="showOverview || activeSlidesLoaded"
v-show="showOverview"
v-if="showOverview"
class="fixed left-0 right-0 top-0 h-[calc(var(--vh,1vh)*100)] z-20 bg-main !bg-opacity-75 p-16 py-20 overflow-y-auto backdrop-blur-5px"
@click="close"
>
Expand Down
18 changes: 2 additions & 16 deletions packages/client/internals/SlideWrapper.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
<script setup lang="ts">
import { computed, defineAsyncComponent, defineComponent, h, ref, toRef } from 'vue'
import { computed, ref, toRef } from 'vue'
import type { CSSProperties, PropType } from 'vue'
import { provideLocal } from '@vueuse/core'
import type { ClicksContext, RenderContext, SlideRoute } from '@slidev/types'
import { injectionClicksContext, injectionCurrentPage, injectionFrontmatter, injectionRenderContext, injectionRoute, injectionSlideZoom } from '../constants'
import { getSlideClass } from '../utils'
import { configs } from '../env'
import SlideLoading from './SlideLoading.vue'
import { SlideBottom, SlideTop } from '#slidev/global-layers'
const props = defineProps({
Expand Down Expand Up @@ -47,19 +46,6 @@ const style = computed<CSSProperties>(() => ({
...zoomStyle.value,
'user-select': configs.selectable ? undefined : 'none',
}))
const SlideComponent = computed(() => props.route && defineAsyncComponent({
loader: async () => {
const component = await props.route.component()
return defineComponent({
mounted: props.clicksContext?.onMounted,
unmounted: props.clicksContext?.onUnmounted,
render: () => h(component.default),
})
},
delay: 300,
loadingComponent: SlideLoading,
}))
</script>

<template>
Expand All @@ -69,7 +55,7 @@ const SlideComponent = computed(() => props.route && defineAsyncComponent({
:style="style"
>
<SlideBottom />
<SlideComponent />
<component :is="props.route.component" />
<SlideTop />
</div>
</template>
Expand Down
48 changes: 32 additions & 16 deletions packages/client/internals/SlidesShow.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { TransitionGroup, computed, shallowRef, watch } from 'vue'
import { TransitionGroup, computed, shallowRef, watchEffect } from 'vue'
import { recomputeAllPoppers } from 'floating-vue'
import type { SlideRoute } from '@slidev/types'
import { useNav } from '../composables/useNav'
import { useViewTransition } from '../composables/useViewTransition'
import { skipTransition } from '../logic/hmr'
Expand All @@ -19,20 +20,34 @@ const {
currentSlideRoute,
currentTransition,
getPrimaryClicks,
prevRoute,
nextRoute,
slides,
isPrintMode,
isPrintWithClicks,
clicksDirection,
} = useNav()
// preload next route
watch(currentSlideRoute, () => {
if (currentSlideRoute.value?.meta && currentSlideRoute.value.meta.preload !== false)
currentSlideRoute.value.meta.__preloaded = true
if (nextRoute.value?.meta && nextRoute.value.meta.preload !== false)
nextRoute.value.meta.__preloaded = true
}, { immediate: true })
function preloadRoute(route: SlideRoute) {
if (route.meta.preload !== false) {
route.meta.__preloaded = true
route.load()
}
}
// preload current, prev and next slides
watchEffect(() => {
preloadRoute(currentSlideRoute.value)
preloadRoute(prevRoute.value)
preloadRoute(nextRoute.value)
})
// preload all slides after 3s
watchEffect((onCleanup) => {
const routes = slides.value
const timeout = setTimeout(() => {
routes.forEach(preloadRoute)
}, 3000)
onCleanup(() => clearTimeout(timeout))
})
const hasViewTransition = useViewTransition()
Expand Down Expand Up @@ -67,14 +82,15 @@ function onAfterLeave() {
}"
@after-leave="onAfterLeave"
>
<SlideWrapper
v-for="route of loadedRoutes"
v-show="route === currentSlideRoute"
:key="route.no"
:clicks-context="isPrintMode && !isPrintWithClicks ? createFixedClicks(route, CLICKS_MAX) : getPrimaryClicks(route)"
:route="route"
:render-context="renderContext"
/>
<template v-for="route of loadedRoutes" :key="route.no">
<SlideWrapper
v-if="Math.abs(route.no - currentSlideRoute.no) <= 20"
v-show="route === currentSlideRoute"
:clicks-context="isPrintMode && !isPrintWithClicks ? createFixedClicks(route, CLICKS_MAX) : getPrimaryClicks(route)"
:route="route"
:render-context="renderContext"
/>
</template>
</component>

<DragControl v-if="activeDragElement" :data="activeDragElement" />
Expand Down
5 changes: 1 addition & 4 deletions packages/client/logic/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { WritableComputedRef } from 'vue'
import { computed, nextTick, ref, unref } from 'vue'
import { computed, nextTick, unref } from 'vue'
import { useRouter } from 'vue-router'

export function useRouteQuery<T extends string | string[]>(
Expand Down Expand Up @@ -35,6 +35,3 @@ export function useRouteQuery<T extends string | string[]>(
},
})
}

// force update collected elements when the route is fully resolved
export const routeForceRefresh = ref(0)
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"shiki-magic-move": "^0.4.2",
"typescript": "^5.5.3",
"unocss": "^0.61.3",
"vue": "^3.4.31",
"vue": "^3.4.32",
"vue-router": "^4.4.0",
"yaml": "^2.4.5"
},
Expand Down
27 changes: 15 additions & 12 deletions packages/client/pages/play.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,21 @@ registerShortcuts()
if (__SLIDEV_FEATURE_WAKE_LOCK__)
useWakeLock()
useStyleTag(computed(() => `
vite-error-overlay {
--width: calc(100vw - ${isEditorVertical.value ? 0 : editorWidth.value}px);
--height: calc(100vh - ${isEditorVertical.value ? editorHeight.value : 0}px);
position: fixed;
left: 0;
top: 0;
width: calc(var(--width) / var(--slidev-slide-scale));
height: calc(var(--height) / var(--slidev-slide-scale));
transform-origin: top left;
transform: scale(var(--slidev-slide-scale));
}`))
if (import.meta.hot) {
useStyleTag(computed(() => `
vite-error-overlay {
--width: calc(100vw - ${isEditorVertical.value ? 0 : editorWidth.value}px);
--height: calc(100vh - ${isEditorVertical.value ? editorHeight.value : 0}px);
position: fixed;
left: 0;
top: 0;
width: calc(var(--width) / var(--slidev-slide-scale));
height: calc(var(--height) / var(--slidev-slide-scale));
transform-origin: top left;
transform: scale(var(--slidev-slide-scale));
}`,
))
}
const persistNav = computed(() => isScreenVertical.value || showEditor.value)
Expand Down
7 changes: 6 additions & 1 deletion packages/client/pages/presenter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const nextFrame = computed(() => {
if (clicksContext.value.current < clicksContext.value.total)
return [currentSlideRoute.value!, clicksContext.value.current + 1] as const
else if (hasNext.value)
return [nextRoute.value!, 0] as const
return [nextRoute.value, 0] as const
else
return null
})
Expand Down Expand Up @@ -135,6 +135,11 @@ onMounted(() => {
render-context="previewNext"
/>
</SlideContainer>
<div v-else class="h-full flex justify-center items-center">
<div class="text-gray-500">
End of the presentation
</div>
</div>
<div class="absolute left-0 top-0 bg-main border-b border-r border-main px2 py1 op50 text-sm">
Next
</div>
Expand Down
9 changes: 0 additions & 9 deletions packages/client/setup/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { AppContext } from '@slidev/types'
import TwoSlashFloatingVue from '@shikijs/vitepress-twoslash/client'
import type { App } from 'vue'
import { nextTick } from 'vue'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import { createHead } from '@unhead/vue'
import { routeForceRefresh } from '../logic/route'
import { createVClickDirectives } from '../modules/v-click'
import { createVMarkDirective } from '../modules/v-mark'
import { createVDragDirective } from '../modules/v-drag'
Expand Down Expand Up @@ -43,13 +41,6 @@ export default async function setupMain(app: App) {
router,
}

nextTick(() => {
router.afterEach(async () => {
await nextTick()
routeForceRefresh.value += 1
})
})

for (const setup of setups)
await setup(context)
}
2 changes: 1 addition & 1 deletion packages/create-app/template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@
"@slidev/cli": "^0.49.16",
"@slidev/theme-default": "latest",
"@slidev/theme-seriph": "latest",
"vue": "^3.4.31"
"vue": "^3.4.32"
}
}
Loading

0 comments on commit d7f4178

Please sign in to comment.