Skip to content
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

fix: correctly handle prerender pages in split mode #7509

Merged
merged 1 commit into from
Jun 28, 2023
Merged
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
5 changes: 5 additions & 0 deletions .changeset/unlucky-paws-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Correctly emit pre-rendered pages when `build.split` is set to `true`
25 changes: 22 additions & 3 deletions packages/astro/src/core/build/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
RouteType,
SSRError,
SSRLoadedRenderer,
SSRManifest,
} from '../../@types/astro';
import {
generateImage as generateImageInternal,
Expand Down Expand Up @@ -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)) {
Expand Down
14 changes: 12 additions & 2 deletions packages/astro/src/core/build/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/**
Expand Down Expand Up @@ -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, '.')}`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
export const prerender = true
---

<html>
<head>
<title>Pre render me</title>
</head>
<body>

</body>
</html>
26 changes: 23 additions & 3 deletions packages/astro/test/ssr-split-manifest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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} */
Expand Down Expand Up @@ -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;
});
});
2 changes: 1 addition & 1 deletion packages/astro/test/test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion packages/integrations/node/test/prerender.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
Expand Down