Skip to content

Commit

Permalink
feat: replace ClientOnly component with clientOnly function with …
Browse files Browse the repository at this point in the history
…TS support vikejs#67, vikejs#82

BREAKING CHANGE: `ClientOnly` component is removed, please use the new `clientOnly` function to create components that only load and render on client side
  • Loading branch information
pdanpdan committed Jun 7, 2024
1 parent 72c404d commit 703658c
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 48 deletions.
2 changes: 1 addition & 1 deletion examples/full/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Full-fledged example of using `vike-vue`, showcasing:

- [Layout](https://vike.dev/Layout)
- Fetching data with [`data()`](https://vike.dev/data)
- [`<ClientOnly>`](https://vike.dev/ClientOnly)
- [`clientOnly`](https://vike.dev/clientOnly)
- [Toggling SSR](https://vike.dev/ssr) on a per-page basis.
- [Markdown](https://vike.dev/markdown)
- [Route Function](https://vike.dev/route-function)
Expand Down
6 changes: 3 additions & 3 deletions packages/vike-vue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,11 @@ All hooks are [cumulative](https://vike.dev/meta#api), so you can add your own h
* [`usePageContext()`](https://vike.dev/usePageContext): Access the [`pageContext` object](https://vike.dev/pageContext)
from any component.

## Components
## Utilities

`vike-vue` introduces the following new components:
`vike-vue` introduces the following new utility functions:

* [`ClientOnly`](https://vike.dev/ClientOnly): Wrapper to render and load a component only on the client-side.
* [`clientOnly`](https://vike.dev/clientOnly): Creates a wrapper component to load and render a component only on the client-side.

## Teleports

Expand Down
11 changes: 4 additions & 7 deletions packages/vike-vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@
"./renderer/onRenderClient": "./dist/renderer/onRenderClient.js",
"./usePageContext": "./dist/hooks/usePageContext.js",
"./useData": "./dist/hooks/useData.js",
"./ClientOnly": {
"default": "./dist/components/ClientOnly.js",
"types": "./dist/components/ClientOnly.vue.d.ts"
},
"./clientOnly": "./dist/utils/clientOnly.js",
"./types": {
"default": "./dist/types/index.js",
"types": "./dist/types/index.d.ts"
Expand Down Expand Up @@ -60,14 +57,14 @@
"useData": [
"./dist/hooks/useData.d.ts"
],
"clientOnly": [
"./dist/utils/clientOnly.d.ts"
],
"renderer/onRenderHtml": [
"./dist/renderer/onRenderHtml.d.ts"
],
"renderer/onRenderClient": [
"./dist/renderer/onRenderClient.d.ts"
],
"ClientOnly": [
"./dist/components/ClientOnly.vue.d.ts"
]
}
},
Expand Down
36 changes: 0 additions & 36 deletions packages/vike-vue/src/components/ClientOnly.vue

This file was deleted.

53 changes: 53 additions & 0 deletions packages/vike-vue/src/utils/clientOnly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { h, shallowRef, defineComponent, onBeforeMount } from 'vue'
import type { Component, SlotsType } from 'vue'

type MaybePromise<T> = T | Promise<T>
type ComponentResolved<T> = MaybePromise<T | { default: T; }>

type ClientOnlySlots = {
fallback?: {};
'client-only-fallback'?: {};
}

export function clientOnly<T extends Component>(
source: ComponentResolved<T> | (() => ComponentResolved<T>),
) {
const clientOnlyComponent = defineComponent({
inheritAttrs: false,

setup(_, { attrs, slots }) {
const resolvedComp = shallowRef<T | null>(null)

onBeforeMount(() => {
const loader = source instanceof Function ? source : () => source
Promise.resolve(loader())
.then((component) => {
resolvedComp.value = 'default' in component ? component.default : component
})
.catch((e) => {
console.error('Component loading failed:', e)
throw e
})
})

const cleanSlots = (slots: ClientOnlySlots) => {
const cleaned = { ...slots }
if (slots[ 'client-only-fallback' ]) {
delete cleaned['client-only-fallback']
} else {
delete cleaned.fallback
}
return cleaned
}

return () =>
resolvedComp.value !== null
? h(resolvedComp.value, attrs, cleanSlots(slots as ClientOnlySlots))
: slots['client-only-fallback']?.()
},

slots: Object as SlotsType<ClientOnlySlots>,
})

return clientOnlyComponent as typeof clientOnlyComponent & T
}
2 changes: 1 addition & 1 deletion packages/vike-vue/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ export default defineConfig({
['+config']: resolve(__dirname, './src/+config.ts'),
['renderer/onRenderClient']: resolve(__dirname, './src/renderer/onRenderClient.ts'),
['renderer/onRenderHtml']: resolve(__dirname, './src/renderer/onRenderHtml.ts'),
['utils/clientOnly']: resolve(__dirname, './src/utils/clientOnly.ts'),
['types/index']: resolve(__dirname, './src/types/index.ts'),
['hooks/usePageContext']: resolve(__dirname, './src/hooks/usePageContext.ts'),
['hooks/useData']: resolve(__dirname, './src/hooks/useData.ts'),
['components/ClientOnly']: resolve(__dirname, './src/components/ClientOnly.vue'),
},
formats: ['es'],
},
Expand Down

0 comments on commit 703658c

Please sign in to comment.