fix: correctly handle prerender pages in split mode (#7509)
This commit is contained in:
parent
1a9b644e20
commit
f4fea3b02b
7 changed files with 76 additions and 10 deletions
5
.changeset/unlucky-paws-own.md
Normal file
5
.changeset/unlucky-paws-own.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Correctly emit pre-rendered pages when `build.split` is set to `true`
|
|
@ -17,6 +17,7 @@ import type {
|
|||
RouteType,
|
||||
SSRError,
|
||||
SSRLoadedRenderer,
|
||||
SSRManifest,
|
||||
} from '../../@types/astro';
|
||||
import {
|
||||
generateImage as generateImageInternal,
|
||||
|
@ -148,9 +149,27 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
|
|||
for (const [pageData, filePath] of eachPageDataFromEntryPoint(internals)) {
|
||||
if (pageData.route.prerender) {
|
||||
const ssrEntryURLPage = createEntryURL(filePath, outFolder);
|
||||
const ssrEntryPage: SinglePageBuiltModule = await import(ssrEntryURLPage.toString());
|
||||
|
||||
await generatePage(opts, internals, pageData, ssrEntryPage, builtPaths);
|
||||
const ssrEntryPage = await import(ssrEntryURLPage.toString());
|
||||
if (opts.settings.config.build.split) {
|
||||
// forcing to use undefined, so we fail in an expected way if the module is not even there.
|
||||
const manifest: SSRManifest | undefined = ssrEntryPage.manifest;
|
||||
const ssrEntry = manifest?.pageModule;
|
||||
if (ssrEntry) {
|
||||
await generatePage(opts, internals, pageData, ssrEntry, builtPaths);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unable to find the manifest for the module ${ssrEntryURLPage.toString()}. This is unexpected and likely a bug in Astro, please report.`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await generatePage(
|
||||
opts,
|
||||
internals,
|
||||
pageData,
|
||||
ssrEntryPage as SinglePageBuiltModule,
|
||||
builtPaths
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const pageData of eachRedirectPageData(internals)) {
|
||||
|
|
|
@ -3,9 +3,13 @@ import type { RouteData, SSRResult } from '../../@types/astro';
|
|||
import type { PageOptions } from '../../vite-plugin-astro/types';
|
||||
import { prependForwardSlash, removeFileExtension } from '../path.js';
|
||||
import { viteID } from '../util.js';
|
||||
import { ASTRO_PAGE_MODULE_ID, getVirtualModulePageIdFromPath } from './plugins/plugin-pages.js';
|
||||
import {
|
||||
ASTRO_PAGE_RESOLVED_MODULE_ID,
|
||||
getVirtualModulePageIdFromPath,
|
||||
} from './plugins/plugin-pages.js';
|
||||
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
|
||||
import type { PageBuildData, StylesheetAsset, ViteID } from './types';
|
||||
import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
|
||||
|
||||
export interface BuildInternals {
|
||||
/**
|
||||
|
@ -234,7 +238,13 @@ export function* eachPageDataFromEntryPoint(
|
|||
internals: BuildInternals
|
||||
): Generator<[PageBuildData, string]> {
|
||||
for (const [entryPoint, filePath] of internals.entrySpecifierToBundleMap) {
|
||||
if (entryPoint.includes(ASTRO_PAGE_MODULE_ID)) {
|
||||
// virtual pages can be emitted with different prefixes:
|
||||
// - the classic way are pages emitted with prefix ASTRO_PAGE_RESOLVED_MODULE_ID -> plugin-pages
|
||||
// - pages emitted using `build.split`, in this case pages are emitted with prefix RESOLVED_SPLIT_MODULE_ID
|
||||
if (
|
||||
entryPoint.includes(ASTRO_PAGE_RESOLVED_MODULE_ID) ||
|
||||
entryPoint.includes(RESOLVED_SPLIT_MODULE_ID)
|
||||
) {
|
||||
const [, pageName] = entryPoint.split(':');
|
||||
const pageData = internals.pagesByComponent.get(
|
||||
`${pageName.replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.')}`
|
||||
|
|
12
packages/astro/test/fixtures/ssr-split-manifest/src/pages/prerender.astro
vendored
Normal file
12
packages/astro/test/fixtures/ssr-split-manifest/src/pages/prerender.astro
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
export const prerender = true
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Pre render me</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -3,7 +3,8 @@ import { loadFixture } from './test-utils.js';
|
|||
import testAdapter from './test-adapter.js';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
describe('astro:ssr-manifest, split', () => {
|
||||
/** @type {import('./test-utils').Fixture} */
|
||||
|
@ -35,15 +36,34 @@ describe('astro:ssr-manifest, split', () => {
|
|||
const html = await response.text();
|
||||
|
||||
const $ = cheerio.load(html);
|
||||
expect($('#assets').text()).to.equal('["/_astro/index.a8a337e4.css"]');
|
||||
expect($('#assets').text()).to.equal('["/_astro/index.a8a337e4.css","/prerender/index.html"]');
|
||||
});
|
||||
|
||||
it('should give access to entry points that exists on file system', async () => {
|
||||
// number of the pages inside src/
|
||||
expect(entryPoints.size).to.equal(4);
|
||||
expect(entryPoints.size).to.equal(5);
|
||||
for (const fileUrl of entryPoints.values()) {
|
||||
let filePath = fileURLToPath(fileUrl);
|
||||
expect(existsSync(filePath)).to.be.true;
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly emit the the pre render page', async () => {
|
||||
const text = readFileSync(
|
||||
resolve('./test/fixtures/ssr-split-manifest/dist/client/prerender/index.html'),
|
||||
{
|
||||
encoding: 'utf8',
|
||||
}
|
||||
);
|
||||
expect(text.includes('<title>Pre render me</title>')).to.be.true;
|
||||
});
|
||||
|
||||
it('should emit an entry point to request the pre-rendered page', async () => {
|
||||
const pagePath = 'src/pages/prerender.astro';
|
||||
const app = await fixture.loadEntryPoint(pagePath, currentRoutes);
|
||||
const request = new Request('http://example.com/');
|
||||
const response = await app.render(request);
|
||||
const html = await response.text();
|
||||
expect(html.includes('<title>Pre render me</title>')).to.be.true;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -252,7 +252,7 @@ export async function loadFixture(inlineConfig) {
|
|||
const virtualModule = getVirtualModulePageNameFromPath(RESOLVED_SPLIT_MODULE_ID, pagePath);
|
||||
const filePath = makeSplitEntryPointFileName(virtualModule, routes);
|
||||
const url = new URL(`./server/${filePath}?id=${fixtureId}`, config.outDir);
|
||||
const { createApp, manifest, middleware } = await import(url);
|
||||
const { createApp, manifest } = await import(url);
|
||||
const app = createApp(streaming);
|
||||
app.manifest = manifest;
|
||||
return app;
|
||||
|
|
|
@ -29,7 +29,7 @@ describe('Prerendering', () => {
|
|||
adapter: nodejs({ mode: 'standalone' }),
|
||||
});
|
||||
await fixture.build();
|
||||
const { startServer } = await await load();
|
||||
const { startServer } = await load();
|
||||
let res = startServer();
|
||||
server = res.server;
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue