Skip to content

feat: add client-only load strategy #443

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,18 @@ This is because the user session is stored in a secure cookie and cannot be acce

**This means that you should not rely on the user session during prerendering.**

You may also choose to instruct Nuxt AUth Utils to fetch the user session only on the client side, with the `loadStrategy` option in your `nuxt.config.ts`:

```ts
export default defineNuxtConfig({
auth: {
loadStrategy: 'client-only'
}
})
```

When using the `client-only` load strategy, the user session can still be manually fetched on the server side by calling `fetch` from the `useUserSession` composable.

### `<AuthState>` component

You can use the `<AuthState>` component to safely display auth-related data in your components without worrying about the rendering mode.
Expand All @@ -617,7 +629,7 @@ One common use case if the Login button in the header:
</template>
```

If the page is cached or prerendered, nothing will be rendered until the user session is fetched on the client-side.
If the page is cached or prerendered or the load strategy set as `client-only`, nothing will be rendered until the user session is fetched on the client-side.

You can use the `placeholder` slot to show a placeholder on server-side and while the user session is being fetched on client-side for the prerendered pages:

Expand Down
17 changes: 17 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export interface ModuleOptions {
*/
scrypt?: ScryptConfig
}
/**
* Session load strategy
* @default 'server-first'
*/
loadStrategy?: 'server-first' | 'client-only'
}

declare module 'nuxt/schema' {
Expand All @@ -51,6 +56,12 @@ declare module 'nuxt/schema' {
*/
session: SessionConfig
}

interface PublicRuntimeConfig {
auth: {
loadStrategy: 'server-first' | 'client-only'
}
}
}

export default defineNuxtModule<ModuleOptions>({
Expand All @@ -65,6 +76,7 @@ export default defineNuxtModule<ModuleOptions>({
hash: {
scrypt: {},
},
loadStrategy: 'server-first',
},
async setup(options, nuxt) {
const resolver = createResolver(import.meta.url)
Expand Down Expand Up @@ -162,6 +174,11 @@ export default defineNuxtModule<ModuleOptions>({
}
}

// Load strategy
runtimeConfig.public.auth = defu(runtimeConfig.public.auth, {
loadStrategy: options.loadStrategy ?? 'server-first',
})

// WebAuthn settings
runtimeConfig.webauthn = defu(runtimeConfig.webauthn, {
register: {},
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/app/plugins/session.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export default defineNuxtPlugin(async (nuxtApp) => {
if (!nuxtApp.payload.serverRendered) {
await useUserSession().fetch()
}
else if (Boolean(nuxtApp.payload.prerenderedAt) || Boolean(nuxtApp.payload.isCached)) {
else if (Boolean(nuxtApp.payload.prerenderedAt) || Boolean(nuxtApp.payload.isCached)
|| nuxtApp.$config.public.auth.loadStrategy === 'client-only'
) {
// To avoid hydration mismatch
nuxtApp.hook('app:mounted', async () => {
await useUserSession().fetch()
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/app/plugins/session.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export default defineNuxtPlugin({
async setup(nuxtApp) {
// Flag if request is cached
nuxtApp.payload.isCached = Boolean(useRequestEvent()?.context.cache)
if (nuxtApp.payload.serverRendered && !nuxtApp.payload.prerenderedAt && !nuxtApp.payload.isCached) {
if (nuxtApp.payload.serverRendered && !nuxtApp.payload.prerenderedAt && !nuxtApp.payload.isCached
&& nuxtApp.$config.public.auth.loadStrategy !== 'client-only'
) {
await useUserSession().fetch()
}
},
Expand Down