Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/full/.testRun.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ function testUseConfig() {
await page.goto(getServerUrl() + '/images')
await testCounter()
})
// The <title> set via useConfig() inside a server-side +data() hook must be applied upon
// client-side navigation. https://github.com/vikejs/vike-vue/issues/233
test('useConfig() in +data() upon client-side navigation', async () => {
await page.goto(getServerUrl() + '/star-wars')
await expectTitle('6 Star Wars Movies')
// The movie page's <title> is set via useConfig({ title }) inside its server-side +data() hook.
await page.click('a:has-text("Return of the Jedi")')
await expectTitle('Return of the Jedi')
await ensureWasClientSideRouted('/pages/star-wars/index')
})
}

/** Ensure page wasn't server-side routed.
Expand Down
2 changes: 2 additions & 0 deletions packages/vike-react/src/hooks/useConfig/configsClientSide.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Settings the client-side applies upon navigation, see applyHeadSettings(). The others are HTML-only.
export const configsClientSide = ['title', 'lang'] as const
4 changes: 2 additions & 2 deletions packages/vike-react/src/hooks/useConfig/useConfig-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { objectKeys } from '../../utils/objectKeys.js'
import { includes } from '../../utils/includes.js'
import { assert } from '../../utils/assert.js'
import { configsCumulative } from './configsCumulative.js'
import { configsClientSide } from './configsClientSide.js'

/**
* Set configurations inside components and Vike hooks.
Expand All @@ -35,12 +36,11 @@ function useConfig(): (config: ConfigViaHook) => void {
}
}

const configsClientSide = ['title']
function setPageContextConfigViaHook(config: ConfigViaHook, pageContext: PageContext & PageContextInternal) {
pageContext._configViaHook ??= {}
objectKeys(config).forEach((configName) => {
// Skip HTML only configs which the client-side doesn't need, saving KBs sent to the client as well as avoiding serialization errors.
if (pageContext.isClientSideNavigation && !configsClientSide.includes(configName)) return
if (pageContext.isClientSideNavigation && !includes(configsClientSide, configName)) return

if (!includes(configsCumulative, configName)) {
// Overridable config
Expand Down
18 changes: 16 additions & 2 deletions packages/vike-react/src/integration/onRenderHtml.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import type { PageContextServer } from 'vike/types'
import { VikeReactProviderPageContext } from '../hooks/usePageContext.js'
import { getHeadSetting } from './getHeadSetting.js'
import { getPageElement } from './getPageElement.js'
import { configsClientSide } from '../hooks/useConfig/configsClientSide.js'
import { objectKeys } from '../utils/objectKeys.js'
import { includes } from '../utils/includes.js'
import type { PageContextInternal } from '../types/PageContext.js'
import type { Head } from '../types/Config.js'
import { isReactElement } from '../utils/isReactElement.js'
Expand All @@ -33,8 +36,9 @@ async function onRenderHtml(

const { htmlAttributesString, bodyAttributesString } = getTagAttributes(pageContext)

// Not needed on the client-side, thus we remove it to save KBs sent to the client
delete pageContext._configViaHook
// Keep only what the client-side applies upon navigation, and remove the rest (HTML-only and/or
// non-serializable values such as <Head> components). https://github.com/vikejs/vike-vue/issues/233
removeServerOnlyConfigViaHook(pageContext)

// pageContext.{pageHtmlString,pageHtmlStream} is set by renderPageToHtml() and can be overridden by user at onAfterRenderHtml()
let pageHtmlStringOrStream: string | ReturnType<typeof dangerouslySkipEscape> | PageHtmlStream =
Expand Down Expand Up @@ -92,6 +96,16 @@ async function renderPageToHtml(pageContext: PageContextServer) {
await callCumulativeHooks(pageContext.config.onAfterRenderHtml, pageContext)
}

function removeServerOnlyConfigViaHook(pageContext: PageContextInternal) {
const configViaHook = pageContext._configViaHook
if (!configViaHook) return
objectKeys(configViaHook).forEach((configName) => {
if (!includes(configsClientSide, configName)) delete configViaHook[configName]
})
// Remove it altogether if there isn't anything left, saving KBs sent to the client
if (objectKeys(configViaHook).length === 0) delete pageContext._configViaHook
}

function getHeadHtml(pageContext: PageContextServer & PageContextInternal) {
pageContext._headAlreadySet = true

Expand Down
Loading