Bugfix: fix getStaticPaths() cache miss (#1602)

This commit is contained in:
Drew Powers 2021-10-20 08:45:52 -06:00 committed by Drew Powers
parent d1f42353e8
commit e1b52506f7
4 changed files with 50 additions and 56 deletions

View file

@ -1,3 +1,4 @@
import type { InputHTMLOptions } from '@web/rollup-plugin-html';
import type { AstroConfig, ComponentInstance, GetStaticPathsResult, ManifestData, RouteCache, RouteData, RSSResult } from '../../@types/astro-core';
import type { LogOptions } from '../logger';
@ -69,49 +70,46 @@ class AstroBuilder {
const viteServer = await vite.createServer(viteConfig);
// 2. get all routes
const allPages: Promise<{ html: string; name: string }>[] = [];
const input: InputHTMLOptions[] = [];
const assets: Record<string, string> = {}; // additional assets to be written
await Promise.all(
this.manifest.routes.map(async (route) => {
const { pathname } = route;
const filePath = new URL(`./${route.component}`, this.config.projectRoot);
// static pages
if (pathname) {
allPages.push(
ssr({ astroConfig: this.config, filePath, logging, mode: 'production', origin, route, routeCache: this.routeCache, pathname, viteServer }).then((html) => ({
html,
name: pathname.replace(/\/?$/, '/index.html').replace(/^\//, ''),
}))
for (const route of this.manifest.routes) {
const { pathname } = route;
const filePath = new URL(`./${route.component}`, this.config.projectRoot);
// static pages (note: should these be )
if (pathname) {
input.push(
await ssr({ astroConfig: this.config, filePath, logging, mode: 'production', origin, route, routeCache: this.routeCache, pathname, viteServer }).then((html) => ({
html,
name: pathname.replace(/\/?$/, '/index.html').replace(/^\//, ''),
}))
);
}
// dynamic pages
else {
const staticPaths = await this.getStaticPathsForRoute(route, viteServer);
// handle RSS (TODO: improve this?)
if (staticPaths.rss && staticPaths.rss.xml) {
const rssFile = new URL(staticPaths.rss.url.replace(/^\/?/, './'), this.config.dist);
if (assets[fileURLToPath(rssFile)]) {
throw new Error(
`[getStaticPaths] RSS feed ${staticPaths.rss.url} already exists.\nUse \`rss(data, {url: '...'})\` to choose a unique, custom URL. (${route.component})`
);
}
assets[fileURLToPath(rssFile)] = staticPaths.rss.xml;
}
// TODO: throw error if conflict
for (const staticPath of staticPaths.paths) {
input.push(
await ssr({ astroConfig: this.config, filePath, logging, mode: 'production', origin, route, routeCache: this.routeCache, pathname: staticPath, viteServer }).then(
(html) => ({
html,
name: staticPath.replace(/\/?$/, '/index.html').replace(/^\//, ''),
})
)
);
}
// dynamic pages
else {
const staticPaths = await this.getStaticPathsForRoute(route, viteServer);
// handle RSS (TODO: improve this?)
if (staticPaths.rss && staticPaths.rss.xml) {
const rssFile = new URL(staticPaths.rss.url.replace(/^\/?/, './'), this.config.dist);
if (assets[fileURLToPath(rssFile)]) {
throw new Error(
`[getStaticPaths] RSS feed ${staticPaths.rss.url} already exists.\nUse \`rss(data, {url: '...'})\` to choose a unique, custom URL. (${route.component})`
);
}
assets[fileURLToPath(rssFile)] = staticPaths.rss.xml;
}
// TODO: throw error if conflict
staticPaths.paths.forEach((staticPath) => {
allPages.push(
ssr({ astroConfig: this.config, filePath, logging, mode: 'production', origin, route, routeCache: this.routeCache, pathname: staticPath, viteServer }).then(
(html) => ({
html,
name: staticPath.replace(/\/?$/, '/index.html').replace(/^\//, ''),
})
)
);
});
}
})
);
const input = await Promise.all(allPages);
}
}
// 3. build with Vite
await vite.build({
@ -177,6 +175,7 @@ class AstroBuilder {
validateGetStaticPathsModule(mod);
const rss = generateRssFunction(this.config.buildOptions.site, route);
const staticPaths: GetStaticPathsResult = (await mod.getStaticPaths!({ paginate: generatePaginateFunction(route), rss: rss.generator })).flat();
this.routeCache[route.component] = staticPaths;
validateGetStaticPathsResult(staticPaths, this.logging);
return {
paths: staticPaths.map((staticPath) => staticPath.params && route.generate(staticPath.params)).filter(Boolean),

View file

@ -77,10 +77,10 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
// Important this happens before load module in case a renderer provides polyfills.
const renderers = await resolveRenderers(viteServer, astroConfig.renderers);
// 1.5. load module
// 2. load module
const mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
// 2. handle dynamic routes
// 3. handle dynamic routes
let params: Params = {};
let pageProps: Props = {};
if (route && !route.pathname) {
@ -91,9 +91,8 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
}
}
validateGetStaticPathsModule(mod);
routeCache[route.component] =
routeCache[route.component] ||
(
if (!routeCache[route.component]) {
routeCache[route.component] = await (
await mod.getStaticPaths!({
paginate: generatePaginateFunction(route),
rss: () => {
@ -101,6 +100,7 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
},
})
).flat();
}
validateGetStaticPathsResult(routeCache[route.component], logging);
const routePathParams: GetStaticPathsResult = routeCache[route.component];
const matchedStaticPath = routePathParams.find(({ params: _params }) => JSON.stringify(_params) === JSON.stringify(params));
@ -110,7 +110,7 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
pageProps = { ...matchedStaticPath.props } || {};
}
// 3. render page
// 4. render page
const Component = await mod.default;
if (!Component) throw new Error(`Expected an exported Astro component but received typeof ${typeof Component}`);
@ -144,12 +144,12 @@ export async function ssr({ astroConfig, filePath, logging, mode, origin, pathna
let html = await renderPage(result, Component, pageProps, null);
// 4. modify response
// 5. modify response
if (mode === 'development') {
html = await viteServer.transformIndexHtml(fileURLToPath(filePath), html, pathname);
}
// 5. finish
// 6. finish
return html;
} catch (e: any) {
viteServer.ssrFixStacktrace(e);

View file

@ -1,7 +1,5 @@
/**
* UNCOMMENT: fix "Error: can only be called once!"
import { expect } from 'chai';
import { loadFixture } from './test-utils';
import { loadFixture } from './test-utils.js';
let fixture;
@ -22,6 +20,3 @@ describe('getStaticPaths()', () => {
expect(true).to.equal(true);
});
});
*/
it.skip('is skipped', () => {});

View file

@ -1,5 +1,5 @@
---
export function getStaticPaths({paginate}) {
export function getStaticPaths({ paginate }) {
if (globalThis.isCalledOnce) {
throw new Error("Can only be called once!");
}
@ -10,7 +10,7 @@ export function getStaticPaths({paginate}) {
{params: {test: 'c'}},
];
}
const { params} = Astro.request;
const { params } = Astro.request;
---
<html>