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,
|
RouteType,
|
||||||
SSRError,
|
SSRError,
|
||||||
SSRLoadedRenderer,
|
SSRLoadedRenderer,
|
||||||
|
SSRManifest,
|
||||||
} from '../../@types/astro';
|
} from '../../@types/astro';
|
||||||
import {
|
import {
|
||||||
generateImage as generateImageInternal,
|
generateImage as generateImageInternal,
|
||||||
|
@ -148,9 +149,27 @@ export async function generatePages(opts: StaticBuildOptions, internals: BuildIn
|
||||||
for (const [pageData, filePath] of eachPageDataFromEntryPoint(internals)) {
|
for (const [pageData, filePath] of eachPageDataFromEntryPoint(internals)) {
|
||||||
if (pageData.route.prerender) {
|
if (pageData.route.prerender) {
|
||||||
const ssrEntryURLPage = createEntryURL(filePath, outFolder);
|
const ssrEntryURLPage = createEntryURL(filePath, outFolder);
|
||||||
const ssrEntryPage: SinglePageBuiltModule = await import(ssrEntryURLPage.toString());
|
const ssrEntryPage = await import(ssrEntryURLPage.toString());
|
||||||
|
if (opts.settings.config.build.split) {
|
||||||
await generatePage(opts, internals, pageData, ssrEntryPage, builtPaths);
|
// 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)) {
|
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 type { PageOptions } from '../../vite-plugin-astro/types';
|
||||||
import { prependForwardSlash, removeFileExtension } from '../path.js';
|
import { prependForwardSlash, removeFileExtension } from '../path.js';
|
||||||
import { viteID } from '../util.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 { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
|
||||||
import type { PageBuildData, StylesheetAsset, ViteID } from './types';
|
import type { PageBuildData, StylesheetAsset, ViteID } from './types';
|
||||||
|
import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
|
||||||
|
|
||||||
export interface BuildInternals {
|
export interface BuildInternals {
|
||||||
/**
|
/**
|
||||||
|
@ -234,7 +238,13 @@ export function* eachPageDataFromEntryPoint(
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): Generator<[PageBuildData, string]> {
|
): Generator<[PageBuildData, string]> {
|
||||||
for (const [entryPoint, filePath] of internals.entrySpecifierToBundleMap) {
|
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 [, pageName] = entryPoint.split(':');
|
||||||
const pageData = internals.pagesByComponent.get(
|
const pageData = internals.pagesByComponent.get(
|
||||||
`${pageName.replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.')}`
|
`${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 testAdapter from './test-adapter.js';
|
||||||
import * as cheerio from 'cheerio';
|
import * as cheerio from 'cheerio';
|
||||||
import { fileURLToPath } from 'node:url';
|
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', () => {
|
describe('astro:ssr-manifest, split', () => {
|
||||||
/** @type {import('./test-utils').Fixture} */
|
/** @type {import('./test-utils').Fixture} */
|
||||||
|
@ -35,15 +36,34 @@ describe('astro:ssr-manifest, split', () => {
|
||||||
const html = await response.text();
|
const html = await response.text();
|
||||||
|
|
||||||
const $ = cheerio.load(html);
|
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 () => {
|
it('should give access to entry points that exists on file system', async () => {
|
||||||
// number of the pages inside src/
|
// number of the pages inside src/
|
||||||
expect(entryPoints.size).to.equal(4);
|
expect(entryPoints.size).to.equal(5);
|
||||||
for (const fileUrl of entryPoints.values()) {
|
for (const fileUrl of entryPoints.values()) {
|
||||||
let filePath = fileURLToPath(fileUrl);
|
let filePath = fileURLToPath(fileUrl);
|
||||||
expect(existsSync(filePath)).to.be.true;
|
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 virtualModule = getVirtualModulePageNameFromPath(RESOLVED_SPLIT_MODULE_ID, pagePath);
|
||||||
const filePath = makeSplitEntryPointFileName(virtualModule, routes);
|
const filePath = makeSplitEntryPointFileName(virtualModule, routes);
|
||||||
const url = new URL(`./server/${filePath}?id=${fixtureId}`, config.outDir);
|
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);
|
const app = createApp(streaming);
|
||||||
app.manifest = manifest;
|
app.manifest = manifest;
|
||||||
return app;
|
return app;
|
||||||
|
|
|
@ -29,7 +29,7 @@ describe('Prerendering', () => {
|
||||||
adapter: nodejs({ mode: 'standalone' }),
|
adapter: nodejs({ mode: 'standalone' }),
|
||||||
});
|
});
|
||||||
await fixture.build();
|
await fixture.build();
|
||||||
const { startServer } = await await load();
|
const { startServer } = await load();
|
||||||
let res = startServer();
|
let res = startServer();
|
||||||
server = res.server;
|
server = res.server;
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue