Skip to content

Commit

Permalink
fix: correctly handle prerender pages in split mode
Browse files Browse the repository at this point in the history
  • Loading branch information
ematipico committed Jun 28, 2023
1 parent 1a9b644 commit 0ded7a4
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 10 deletions.
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

0 comments on commit 0ded7a4

Please sign in to comment.