diff --git a/.changeset/weak-wombats-swim.md b/.changeset/weak-wombats-swim.md deleted file mode 100644 index b26399ac87..0000000000 --- a/.changeset/weak-wombats-swim.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'astro': minor -'@astrojs/image': minor -'@astrojs/cloudflare': patch -'@astrojs/netlify': patch -'@astrojs/node': patch -'@astrojs/vercel': patch ---- - -Unflags support for `output: 'hybrid'` mode, which enables pre-rendering by default. The additional `experimental.hybridOutput` flag can be safely removed from your configuration. diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 1766968c09..c3372ec25d 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -1141,6 +1141,44 @@ export interface AstroUserConfig { * ``` */ middleware?: boolean; + + /** + * @docs + * @name experimental.hybridOutput + * @type {boolean} + * @default `false` + * @version 2.5.0 + * @description + * Enable experimental support for hybrid SSR with pre-rendering enabled by default. + * + * To enable this feature, first set `experimental.hybridOutput` to `true` in your Astro config, and set `output` to `hybrid`. + * + * ```js + * { + * output: 'hybrid', + * experimental: { + * hybridOutput: true, + * }, + * } + * ``` + * Then add `export const prerender = false` to any page or endpoint you want to opt-out of pre-rendering. + * ```astro + * --- + * // pages/contact.astro + * export const prerender = false + * + * if (Astro.request.method === 'POST') { + * // handle form submission + * } + * --- + *
+ * + * + * + *
+ * ``` + */ + hybridOutput?: boolean; }; // Legacy options to be removed diff --git a/packages/astro/src/assets/generate.ts b/packages/astro/src/assets/generate.ts index d6cb02e560..a7a9ddd2d3 100644 --- a/packages/astro/src/assets/generate.ts +++ b/packages/astro/src/assets/generate.ts @@ -3,7 +3,7 @@ import { basename, join } from 'node:path/posix'; import type { StaticBuildOptions } from '../core/build/types.js'; import { warn } from '../core/logger/core.js'; import { prependForwardSlash } from '../core/path.js'; -import { isServerLikeOutput } from '../prerender/utils.js'; +import { isHybridOutput } from '../prerender/utils.js'; import { getConfiguredImageService, isESMImportedImage } from './internal.js'; import type { LocalImageService } from './services/service.js'; import type { ImageTransform } from './types.js'; @@ -47,7 +47,7 @@ export async function generateImage( } let serverRoot: URL, clientRoot: URL; - if (isServerLikeOutput(buildOpts.settings.config)) { + if (buildOpts.settings.config.output === 'server' || isHybridOutput(buildOpts.settings.config)) { serverRoot = buildOpts.settings.config.build.server; clientRoot = buildOpts.settings.config.build.client; } else { diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 056b91263a..a12313987b 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -31,7 +31,7 @@ import { removeTrailingForwardSlash, } from '../../core/path.js'; import { runHookBuildGenerated } from '../../integrations/index.js'; -import { isServerLikeOutput } from '../../prerender/utils.js'; +import { isHybridOutput } from '../../prerender/utils.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { callEndpoint, createAPIContext, throwIfRedirectNotAllowed } from '../endpoint/index.js'; import { AstroError } from '../errors/index.js'; @@ -94,7 +94,7 @@ export function chunkIsPage( export async function generatePages(opts: StaticBuildOptions, internals: BuildInternals) { const timer = performance.now(); - const ssr = isServerLikeOutput(opts.settings.config); + const ssr = opts.settings.config.output === 'server' || isHybridOutput(opts.settings.config); // hybrid mode is essentially SSR with prerender by default const serverEntry = opts.buildConfig.serverEntry; const outFolder = ssr ? opts.buildConfig.server : getOutDirWithinCwd(opts.settings.config.outDir); @@ -237,7 +237,7 @@ async function getPathsForRoute( route: pageData.route, isValidate: false, logging: opts.logging, - ssr: isServerLikeOutput(opts.settings.config), + ssr: opts.settings.config.output === 'server' || isHybridOutput(opts.settings.config), }) .then((_result) => { const label = _result.staticPaths.length === 1 ? 'page' : 'pages'; @@ -413,7 +413,7 @@ async function generatePath( } } - const ssr = isServerLikeOutput(settings.config); + const ssr = settings.config.output === 'server' || isHybridOutput(settings.config); const url = getUrlForPath( pathname, opts.settings.config.base, diff --git a/packages/astro/src/core/build/plugins/plugin-ssr.ts b/packages/astro/src/core/build/plugins/plugin-ssr.ts index 062fab77b0..accdd01ad6 100644 --- a/packages/astro/src/core/build/plugins/plugin-ssr.ts +++ b/packages/astro/src/core/build/plugins/plugin-ssr.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from 'url'; import type { Plugin as VitePlugin } from 'vite'; import type { AstroAdapter } from '../../../@types/astro'; import { runHookBuildSsr } from '../../../integrations/index.js'; -import { isServerLikeOutput } from '../../../prerender/utils.js'; +import { isHybridOutput } from '../../../prerender/utils.js'; import { BEFORE_HYDRATION_SCRIPT_ID, PAGE_SCRIPT_ID } from '../../../vite-plugin-scripts/index.js'; import type { SerializedRouteInfo, SerializedSSRManifest } from '../../app/types'; import { joinPaths, prependForwardSlash } from '../../path.js'; @@ -272,7 +272,8 @@ export function pluginSSR( options: StaticBuildOptions, internals: BuildInternals ): AstroBuildPlugin { - const ssr = isServerLikeOutput(options.settings.config); + const ssr = + options.settings.config.output === 'server' || isHybridOutput(options.settings.config); return { build: 'ssr', hooks: { diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 06ce9d7eed..cceaa03613 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -15,7 +15,7 @@ import { emptyDir, removeEmptyDirs } from '../../core/fs/index.js'; import { appendForwardSlash, prependForwardSlash } from '../../core/path.js'; import { isModeServerWithNoAdapter } from '../../core/util.js'; import { runHookBuildSetup } from '../../integrations/index.js'; -import { isServerLikeOutput } from '../../prerender/utils.js'; +import { isHybridOutput } from '../../prerender/utils.js'; import { PAGE_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; import { info } from '../logger/core.js'; @@ -117,6 +117,7 @@ export async function viteBuild(opts: StaticBuildOptions) { export async function staticBuild(opts: StaticBuildOptions, internals: BuildInternals) { const { settings } = opts; + const hybridOutput = isHybridOutput(settings.config); switch (true) { case settings.config.output === 'static': { settings.timer.start('Static generate'); @@ -125,7 +126,7 @@ export async function staticBuild(opts: StaticBuildOptions, internals: BuildInte settings.timer.end('Static generate'); return; } - case isServerLikeOutput(settings.config): { + case settings.config.output === 'server' || hybridOutput: { settings.timer.start('Server generate'); await generatePages(opts, internals); await cleanStaticOutput(opts, internals); @@ -144,7 +145,7 @@ async function ssrBuild( container: AstroBuildPluginContainer ) { const { settings, viteConfig } = opts; - const ssr = isServerLikeOutput(settings.config); + const ssr = settings.config.output === 'server' || isHybridOutput(settings.config); const out = ssr ? opts.buildConfig.server : getOutDirWithinCwd(settings.config.outDir); const { lastVitePlugins, vitePlugins } = container.runBeforeHook('ssr', input); @@ -224,7 +225,7 @@ async function clientBuild( ) { const { settings, viteConfig } = opts; const timer = performance.now(); - const ssr = isServerLikeOutput(settings.config); + const ssr = settings.config.output === 'server' || isHybridOutput(settings.config); const out = ssr ? opts.buildConfig.client : getOutDirWithinCwd(settings.config.outDir); // Nothing to do if there is no client-side JS. @@ -289,11 +290,12 @@ async function runPostBuildHooks( const config = container.options.settings.config; const buildConfig = container.options.settings.config.build; for (const [fileName, mutation] of mutations) { - const root = isServerLikeOutput(config) - ? mutation.build === 'server' - ? buildConfig.server - : buildConfig.client - : config.outDir; + const root = + config.output === 'server' || isHybridOutput(config) + ? mutation.build === 'server' + ? buildConfig.server + : buildConfig.client + : config.outDir; const fileURL = new URL(fileName, root); await fs.promises.mkdir(new URL('./', fileURL), { recursive: true }); await fs.promises.writeFile(fileURL, mutation.code, 'utf-8'); @@ -310,7 +312,7 @@ async function cleanStaticOutput(opts: StaticBuildOptions, internals: BuildInter if (pageData.route.prerender) allStaticFiles.add(internals.pageToBundleMap.get(pageData.moduleSpecifier)); } - const ssr = isServerLikeOutput(opts.settings.config); + const ssr = opts.settings.config.output === 'server' || isHybridOutput(opts.settings.config); const out = ssr ? opts.buildConfig.server : getOutDirWithinCwd(opts.settings.config.outDir); // The SSR output is all .mjs files, the client output is not. const files = await glob('**/*.mjs', { diff --git a/packages/astro/src/core/config/config.ts b/packages/astro/src/core/config/config.ts index 9915ed162b..0ca13a2209 100644 --- a/packages/astro/src/core/config/config.ts +++ b/packages/astro/src/core/config/config.ts @@ -6,6 +6,7 @@ import * as colors from 'kleur/colors'; import path from 'path'; import { fileURLToPath, pathToFileURL } from 'url'; import { mergeConfig as mergeViteConfig } from 'vite'; +import { isHybridMalconfigured } from '../../prerender/utils.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; import type { LogOptions } from '../logger/core.js'; import { arraify, isObject, isURL } from '../util.js'; @@ -223,6 +224,12 @@ export async function openConfig(configOptions: LoadConfigOptions): Promise = new Set(['.js', '.ts']); const localFs = fsMod ?? nodeFs; - const prerender = getPrerenderDefault(settings.config); + const isPrerenderDefault = isHybridOutput(settings.config); const foundInvalidFileExtensions: Set = new Set(); @@ -341,7 +341,7 @@ export function createRouteManifest( component, generate, pathname: pathname || undefined, - prerender, + prerender: isPrerenderDefault, }); } }); @@ -417,7 +417,7 @@ export function createRouteManifest( component, generate, pathname: pathname || void 0, - prerender, + prerender: isPrerenderDefault, }); }); diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 11e792b78d..c12bd03add 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -4,7 +4,7 @@ import slash from 'slash'; import { fileURLToPath } from 'url'; import { normalizePath } from 'vite'; import type { AstroConfig, AstroSettings, RouteType } from '../@types/astro'; -import { isServerLikeOutput } from '../prerender/utils.js'; +import { isHybridOutput } from '../prerender/utils.js'; import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './constants.js'; import type { ModuleLoader } from './module-loader'; import { prependForwardSlash, removeTrailingForwardSlash } from './path.js'; @@ -139,7 +139,9 @@ export function isEndpoint(file: URL, settings: AstroSettings): boolean { } export function isModeServerWithNoAdapter(settings: AstroSettings): boolean { - return isServerLikeOutput(settings.config) && !settings.adapter; + return ( + (settings.config.output === 'server' || isHybridOutput(settings.config)) && !settings.adapter + ); } export function relativeToSrcDir(config: AstroConfig, idOrUrl: URL | string) { diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts index 0d8cd6700a..5d88a1196b 100644 --- a/packages/astro/src/integrations/index.ts +++ b/packages/astro/src/integrations/index.ts @@ -18,7 +18,7 @@ import type { PageBuildData } from '../core/build/types'; import { buildClientDirectiveEntrypoint } from '../core/client-directive/index.js'; import { mergeConfig } from '../core/config/config.js'; import { info, type LogOptions } from '../core/logger/core.js'; -import { isServerLikeOutput } from '../prerender/utils.js'; +import { isHybridOutput } from '../prerender/utils.js'; import { mdxContentEntryType } from '../vite-plugin-markdown/content-entry-type.js'; async function withTakingALongTimeMsg({ @@ -339,7 +339,8 @@ export async function runHookBuildGenerated({ buildConfig: BuildConfig; logging: LogOptions; }) { - const dir = isServerLikeOutput(config) ? buildConfig.client : config.outDir; + const dir = + config.output === 'server' || isHybridOutput(config) ? buildConfig.client : config.outDir; for (const integration of config.integrations) { if (integration?.hooks?.['astro:build:generated']) { @@ -365,7 +366,8 @@ export async function runHookBuildDone({ routes: RouteData[]; logging: LogOptions; }) { - const dir = isServerLikeOutput(config) ? buildConfig.client : config.outDir; + const dir = + config.output === 'server' || isHybridOutput(config) ? buildConfig.client : config.outDir; await fs.promises.mkdir(dir, { recursive: true }); for (const integration of config.integrations) { diff --git a/packages/astro/src/prerender/utils.ts b/packages/astro/src/prerender/utils.ts index bd6e367ad5..40066035cf 100644 --- a/packages/astro/src/prerender/utils.ts +++ b/packages/astro/src/prerender/utils.ts @@ -1,9 +1,11 @@ +// TODO: remove after the experimetal phase when + import type { AstroConfig } from '../@types/astro'; -export function isServerLikeOutput(config: AstroConfig) { - return config.output === 'server' || config.output === 'hybrid'; +export function isHybridMalconfigured(config: AstroConfig) { + return config.experimental.hybridOutput ? config.output !== 'hybrid' : config.output === 'hybrid'; } -export function getPrerenderDefault(config: AstroConfig) { - return config.output === 'hybrid'; +export function isHybridOutput(config: AstroConfig) { + return config.experimental.hybridOutput && config.output === 'hybrid'; } diff --git a/packages/astro/src/vite-plugin-astro-server/request.ts b/packages/astro/src/vite-plugin-astro-server/request.ts index adf4199d16..865c5b4013 100644 --- a/packages/astro/src/vite-plugin-astro-server/request.ts +++ b/packages/astro/src/vite-plugin-astro-server/request.ts @@ -9,7 +9,7 @@ import { error } from '../core/logger/core.js'; import * as msg from '../core/messages.js'; import { removeTrailingForwardSlash } from '../core/path.js'; import { eventError, telemetry } from '../events/index.js'; -import { isServerLikeOutput } from '../prerender/utils.js'; +import { isHybridOutput } from '../prerender/utils.js'; import { runWithErrorHandling } from './controller.js'; import { handle500Response } from './response.js'; import { handleRoute, matchRoute } from './route.js'; @@ -25,7 +25,7 @@ export async function handleRequest( const { settings, loader: moduleLoader } = env; const { config } = settings; const origin = `${moduleLoader.isHttps() ? 'https' : 'http'}://${req.headers.host}`; - const buildingToSSR = isServerLikeOutput(config); + const buildingToSSR = config.output === 'server' || isHybridOutput(config); const url = new URL(origin + req.url); let pathname: string; diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index 1e6d1b87d1..dae4162296 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -17,7 +17,7 @@ import { getParamsAndProps, GetParamsAndPropsError } from '../core/render/index. import { createRequest } from '../core/request.js'; import { matchAllRoutes } from '../core/routing/index.js'; import { getSortedPreloadedMatches } from '../prerender/routing.js'; -import { isServerLikeOutput } from '../prerender/utils.js'; +import { isHybridOutput } from '../prerender/utils.js'; import { log404 } from './common.js'; import { handle404Response, writeSSRResult, writeWebResponse } from './response.js'; @@ -59,7 +59,7 @@ export async function matchRoute( routeCache, pathname: pathname, logging, - ssr: isServerLikeOutput(settings.config), + ssr: settings.config.output === 'server' || isHybridOutput(settings.config), }); if (paramsAndPropsRes !== GetParamsAndPropsError.NoMatchingStaticPath) { @@ -132,7 +132,7 @@ export async function handleRoute( const { config } = settings; const filePath: URL | undefined = matchedRoute.filePath; const { route, preloadedComponent, mod } = matchedRoute; - const buildingToSSR = isServerLikeOutput(config); + const buildingToSSR = config.output === 'server' || isHybridOutput(config); // Headers are only available when using SSR. const request = createRequest({ @@ -158,7 +158,7 @@ export async function handleRoute( routeCache: env.routeCache, pathname: pathname, logging, - ssr: isServerLikeOutput(config), + ssr: config.output === 'server' || isHybridOutput(config), }); const options: SSROptions = { diff --git a/packages/astro/src/vite-plugin-scanner/index.ts b/packages/astro/src/vite-plugin-scanner/index.ts index 465ff74ed6..a349e7fa6a 100644 --- a/packages/astro/src/vite-plugin-scanner/index.ts +++ b/packages/astro/src/vite-plugin-scanner/index.ts @@ -2,7 +2,7 @@ import { normalizePath, type Plugin as VitePlugin } from 'vite'; import type { AstroSettings } from '../@types/astro.js'; import { isEndpoint, isPage } from '../core/util.js'; -import { getPrerenderDefault } from '../prerender/utils.js'; +import { isHybridOutput } from '../prerender/utils.js'; import { scan } from './scan.js'; export default function astroScannerPlugin({ settings }: { settings: AstroSettings }): VitePlugin { @@ -25,11 +25,11 @@ export default function astroScannerPlugin({ settings }: { settings: AstroSettin const fileIsPage = isPage(fileURL, settings); const fileIsEndpoint = isEndpoint(fileURL, settings); if (!(fileIsPage || fileIsEndpoint)) return; - const defaultPrerender = getPrerenderDefault(settings.config); - const pageOptions = await scan(code, id, settings.config.output === 'hybrid'); + const hybridOutput = isHybridOutput(settings.config); + const pageOptions = await scan(code, id, hybridOutput); if (typeof pageOptions.prerender === 'undefined') { - pageOptions.prerender = defaultPrerender; + pageOptions.prerender = hybridOutput ? true : false; } const { meta = {} } = this.getModuleInfo(id) ?? {}; diff --git a/packages/astro/test/ssr-prerender-get-static-paths.test.js b/packages/astro/test/ssr-prerender-get-static-paths.test.js index 6316561d6c..1a17123041 100644 --- a/packages/astro/test/ssr-prerender-get-static-paths.test.js +++ b/packages/astro/test/ssr-prerender-get-static-paths.test.js @@ -144,6 +144,9 @@ describe('Prerender', () => { adapter: testAdapter(), base: '/blog', output: 'hybrid', + experimental: { + hybridOutput: true, + }, vite: { plugins: [vitePluginRemovePrerenderExport()], }, diff --git a/packages/astro/test/units/routing/route-matching.test.js b/packages/astro/test/units/routing/route-matching.test.js index 4653617653..6925183828 100644 --- a/packages/astro/test/units/routing/route-matching.test.js +++ b/packages/astro/test/units/routing/route-matching.test.js @@ -133,6 +133,9 @@ describe('Route matching', () => { userConfig: { trailingSlash: 'never', output: 'hybrid', + experimental: { + hybridOutput: true, + }, adapter: testAdapter(), }, disableTelemetry: true, diff --git a/packages/integrations/cloudflare/test/prerender.test.js b/packages/integrations/cloudflare/test/prerender.test.js index 526f8a4ac5..5d3ff9f10a 100644 --- a/packages/integrations/cloudflare/test/prerender.test.js +++ b/packages/integrations/cloudflare/test/prerender.test.js @@ -38,6 +38,9 @@ describe('Hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'hybrid', + experimental: { + hybridOutput: true, + }, }); await fixture.build(); }); diff --git a/packages/integrations/image/src/index.ts b/packages/integrations/image/src/index.ts index fb6496c0c0..b2bc114477 100644 --- a/packages/integrations/image/src/index.ts +++ b/packages/integrations/image/src/index.ts @@ -3,7 +3,7 @@ import { ssgBuild } from './build/ssg.js'; import type { ImageService, SSRImageService, TransformOptions } from './loaders/index.js'; import type { LoggerLevel } from './utils/logger.js'; import { joinPaths, prependForwardSlash, propsToFilename } from './utils/paths.js'; -import { isServerLikeOutput } from './utils/prerender.js'; +import { isHybridOutput } from './utils/prerender.js'; import { createPlugin } from './vite-plugin-astro-image.js'; export { getImage } from './lib/get-image.js'; @@ -85,7 +85,7 @@ export default function integration(options: IntegrationOptions = {}): AstroInte vite: getViteConfiguration(command === 'dev'), }); - if (command === 'dev' || isServerLikeOutput(config)) { + if (command === 'dev' || config.output === 'server' || isHybridOutput(config)) { injectRoute({ pattern: ROUTE_PATTERN, entryPoint: '@astrojs/image/endpoint', diff --git a/packages/integrations/image/src/utils/prerender.ts b/packages/integrations/image/src/utils/prerender.ts index f69f3b5d47..9265c80bf0 100644 --- a/packages/integrations/image/src/utils/prerender.ts +++ b/packages/integrations/image/src/utils/prerender.ts @@ -1,5 +1,5 @@ import type { AstroConfig } from 'astro'; -export function isServerLikeOutput(config: AstroConfig) { - return config.output === 'server' || config.output === 'hybrid'; +export function isHybridOutput(config: AstroConfig) { + return config.experimental.hybridOutput && config.output === 'hybrid'; } diff --git a/packages/integrations/netlify/test/edge-functions/fixtures/prerender/astro.config.mjs b/packages/integrations/netlify/test/edge-functions/fixtures/prerender/astro.config.mjs index d049599e59..c579d74eff 100644 --- a/packages/integrations/netlify/test/edge-functions/fixtures/prerender/astro.config.mjs +++ b/packages/integrations/netlify/test/edge-functions/fixtures/prerender/astro.config.mjs @@ -6,6 +6,13 @@ const isHybridMode = process.env.PRERENDER === "false"; /** @type {import('astro').AstroConfig} */ const partialConfig = { output: isHybridMode ? "hybrid" : "server", + ...(isHybridMode + ? ({ + experimental: { + hybridOutput: true, + }, + }) + : ({})), }; export default defineConfig({ diff --git a/packages/integrations/netlify/test/functions/prerender.test.js b/packages/integrations/netlify/test/functions/prerender.test.js index a571dd76e4..9718df083c 100644 --- a/packages/integrations/netlify/test/functions/prerender.test.js +++ b/packages/integrations/netlify/test/functions/prerender.test.js @@ -46,6 +46,9 @@ describe('Mixed Hybrid rendering with SSR', () => { fixture = await loadFixture({ root: new URL('./fixtures/prerender/', import.meta.url).toString(), output: 'hybrid', + experimental: { + hybridOutput: true, + }, adapter: netlifyAdapter({ dist: new URL('./fixtures/prerender/dist/', import.meta.url), }), diff --git a/packages/integrations/node/test/prerender.test.js b/packages/integrations/node/test/prerender.test.js index 4b5522a319..751ed2ae71 100644 --- a/packages/integrations/node/test/prerender.test.js +++ b/packages/integrations/node/test/prerender.test.js @@ -140,6 +140,9 @@ describe('Hybrid rendering', () => { base: '/some-base', root: './fixtures/prerender/', output: 'hybrid', + experimental: { + hybridOutput: true, + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); @@ -196,6 +199,9 @@ describe('Hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/prerender/', output: 'hybrid', + experimental: { + hybridOutput: true, + }, adapter: nodejs({ mode: 'standalone' }), }); await fixture.build(); diff --git a/packages/integrations/vercel/src/lib/prerender.ts b/packages/integrations/vercel/src/lib/prerender.ts index f69f3b5d47..9265c80bf0 100644 --- a/packages/integrations/vercel/src/lib/prerender.ts +++ b/packages/integrations/vercel/src/lib/prerender.ts @@ -1,5 +1,5 @@ import type { AstroConfig } from 'astro'; -export function isServerLikeOutput(config: AstroConfig) { - return config.output === 'server' || config.output === 'hybrid'; +export function isHybridOutput(config: AstroConfig) { + return config.experimental.hybridOutput && config.output === 'hybrid'; } diff --git a/packages/integrations/vercel/src/static/adapter.ts b/packages/integrations/vercel/src/static/adapter.ts index ccbf26e570..0b3579cdd1 100644 --- a/packages/integrations/vercel/src/static/adapter.ts +++ b/packages/integrations/vercel/src/static/adapter.ts @@ -8,7 +8,7 @@ import { } from '../image/shared.js'; import { exposeEnv } from '../lib/env.js'; import { emptyDir, getVercelOutput, writeJson } from '../lib/fs.js'; -import { isServerLikeOutput } from '../lib/prerender.js'; +import { isHybridOutput } from '../lib/prerender.js'; import { getRedirects } from '../lib/redirects.js'; const PACKAGE_NAME = '@astrojs/vercel/static'; @@ -55,7 +55,7 @@ export default function vercelStatic({ setAdapter(getAdapter()); _config = config; - if (isServerLikeOutput(config)) { + if (config.output === 'server' || isHybridOutput(config)) { throw new Error(`${PACKAGE_NAME} should be used with output: 'static'`); } }, diff --git a/packages/integrations/vercel/test/serverless-prerender.test.js b/packages/integrations/vercel/test/serverless-prerender.test.js index 18b1653404..94d9081f41 100644 --- a/packages/integrations/vercel/test/serverless-prerender.test.js +++ b/packages/integrations/vercel/test/serverless-prerender.test.js @@ -27,6 +27,9 @@ describe('Serverless hybrid rendering', () => { fixture = await loadFixture({ root: './fixtures/serverless-prerender/', output: 'hybrid', + experimental: { + hybridOutput: true, + }, }); });