diff --git a/README.md b/README.md index 00d1f52c..f6ec5dcc 100755 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ is added automatically to requests. Defaults to `false`. - `exposeAPIRouteRules`: If enabled, the module will create a Nitro server handler that proxies API requests to Drupal backend. Defaults to `true` for SSR (it's disabled for SSG). +- `passThroughHeaders`: Response headers to pass through from Drupal to the client. Defaults to ['cache-control', 'content-language', 'set-cookie', 'x-drupal-cache', 'x-drupal-dynamic-cache']. Note: This is only available in SSR mode. + ## Overriding options with environment variables Runtime config values can be overridden with environment variables via `NUXT_PUBLIC_` prefix. Supported runtime overrides: diff --git a/src/module.ts b/src/module.ts index f47c53c7..c392a421 100644 --- a/src/module.ts +++ b/src/module.ts @@ -17,6 +17,7 @@ export interface ModuleOptions { fetchProxyHeaders: string[], useLocalizedMenuEndpoint: boolean, exposeAPIRouteRules: boolean, + passThroughHeaders?: string[], } export default defineNuxtModule({ @@ -38,7 +39,8 @@ export default defineNuxtModule({ fetchProxyHeaders: ['cookie'], useLocalizedMenuEndpoint: true, addRequestFormat: false, - exposeAPIRouteRules: true + exposeAPIRouteRules: true, + passThroughHeaders: ['cache-control', 'content-language', 'set-cookie', 'x-drupal-cache', 'x-drupal-dynamic-cache'], }, setup (options, nuxt) { // Keep backwards compatibility for baseURL(deprecated). diff --git a/src/runtime/composables/useDrupalCe.ts b/src/runtime/composables/useDrupalCe.ts index 72f2bf1d..a13d741c 100644 --- a/src/runtime/composables/useDrupalCe.ts +++ b/src/runtime/composables/useDrupalCe.ts @@ -1,5 +1,6 @@ import { callWithNuxt } from '#app' import { defu } from 'defu' +import { appendResponseHeader } from 'h3' import { useRuntimeConfig, useRequestURL, useState, useFetch, navigateTo, createError, h, resolveComponent, setResponseStatus, useNuxtApp, useRequestHeaders, UseFetchOptions, ref, watch } from '#imports' export const useDrupalCe = () => { @@ -58,6 +59,13 @@ export const useDrupalCe = () => { useFetchOptions = processFetchOptions(useFetchOptions) useFetchOptions.query = useFetchOptions.query ?? {} + useFetchOptions.onResponse = (context) => { + if (config.passThroughHeaders && import.meta.server) { + const headersObject = Object.fromEntries([...context.response.headers.entries()]) + passThroughHeaders(nuxtApp, headersObject) + } + } + if (config.addRequestContentFormat) { useFetchOptions.query._content_format = config.addRequestContentFormat } @@ -148,12 +156,32 @@ export const useDrupalCe = () => { : h(resolveComponent(customElements.element), customElements) } + /** + * Pass through headers from Drupal to the client + * @param pageHeaders The headers from the Drupal response + */ + const passThroughHeaders = (nuxtApp, pageHeaders) => { + // Only run when SSR context is available. + if (!nuxtApp.ssrContext) { + return + } + const event = nuxtApp.ssrContext.event + if (pageHeaders) { + Object.keys(pageHeaders).forEach((key) => { + if (config.passThroughHeaders.includes(key)) { + appendResponseHeader(event, key, pageHeaders[key]) + } + }) + } + } + return { fetchPage, fetchMenu, getMessages, getPage, renderCustomElements, + passThroughHeaders } }