Skip to content

Commit

Permalink
Warn when getStaticPaths exists without a prerender statement (#7713
Browse files Browse the repository at this point in the history
)

* wip: warning on getStaticPaths without prerender

* refactor: move getStaticPaths warning to scanner plugin

* chore: do not add to test fixture

* chore: remove legacy getStaticPaths validation

* refactor: update warning message

* chore: typo

* chore: add changeset

* chore: remove unused variables

* refactor: make settings optional

* chore: fix lint

* chore: update message to include reason
  • Loading branch information
natemoo-re authored Jul 19, 2023
1 parent 4eba967 commit d088351
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-plums-appear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Update warning when `getStaticPaths` is detected but a route is not prerendered.
2 changes: 1 addition & 1 deletion packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export async function createVite(
mode === 'dev' && astroIntegrationsContainerPlugin({ settings, logging }),
astroScriptsPageSSRPlugin({ settings }),
astroHeadPlugin(),
astroScannerPlugin({ settings }),
astroScannerPlugin({ settings, logging }),
astroInjectEnvTsPlugin({ settings, logging, fs }),
astroContentVirtualModPlugin({ settings }),
astroContentImportPlugin({ fs, settings }),
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/render/route-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function callGetStaticPaths({
const cached = routeCache.get(route);
if (cached?.staticPaths) return cached.staticPaths;

validateDynamicRouteModule(mod, { ssr, logging, route });
validateDynamicRouteModule(mod, { ssr, route });

// No static paths in SSR mode. Return an empty RouteCacheEntry.
if (ssr && !route.prerender) {
Expand Down
12 changes: 1 addition & 11 deletions packages/astro/src/core/routing/validation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { bold } from 'kleur/colors';
import type { ComponentInstance, GetStaticPathsResult, RouteData } from '../../@types/astro';
import { AstroError, AstroErrorData } from '../errors/index.js';
import type { LogOptions } from '../logger/core';
Expand All @@ -19,26 +18,17 @@ export function validateGetStaticPathsParameter([key, value]: [string, any], rou
}
}

/** Warn or error for deprecated or malformed route components */
/** Error for deprecated or malformed route components */
export function validateDynamicRouteModule(
mod: ComponentInstance,
{
ssr,
logging,
route,
}: {
ssr: boolean;
logging: LogOptions;
route: RouteData;
}
) {
if (ssr && mod.getStaticPaths && !route.prerender) {
warn(
logging,
'getStaticPaths',
`getStaticPaths() in ${bold(route.component)} is ignored when "output: server" is set.`
);
}
if ((!ssr || route.prerender) && !mod.getStaticPaths) {
throw new AstroError({
...AstroErrorData.GetStaticPathsRequired,
Expand Down
25 changes: 20 additions & 5 deletions packages/astro/src/vite-plugin-scanner/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { normalizePath, type Plugin as VitePlugin } from 'vite';
import type { Plugin as VitePlugin } from 'vite';
import type { AstroSettings } from '../@types/astro.js';
import { isEndpoint, isPage } from '../core/util.js';
import { type LogOptions } from '../core/logger/core.js';

import { getPrerenderDefault } from '../prerender/utils.js';
import { normalizePath } from 'vite';
import { bold } from 'kleur/colors';
import { warn } from '../core/logger/core.js';
import { isEndpoint, isPage, rootRelativePath } from '../core/util.js';
import { getPrerenderDefault, isServerLikeOutput } from '../prerender/utils.js';
import { scan } from './scan.js';

export default function astroScannerPlugin({ settings }: { settings: AstroSettings }): VitePlugin {
export interface AstroPluginScannerOptions {
settings: AstroSettings;
logging: LogOptions;
}

export default function astroScannerPlugin({ settings, logging }: AstroPluginScannerOptions): VitePlugin {
return {
name: 'astro:scanner',
enforce: 'post',
Expand All @@ -26,11 +35,17 @@ export default function astroScannerPlugin({ settings }: { settings: AstroSettin
const fileIsEndpoint = isEndpoint(fileURL, settings);
if (!(fileIsPage || fileIsEndpoint)) return;
const defaultPrerender = getPrerenderDefault(settings.config);
const pageOptions = await scan(code, id, settings.config.output === 'hybrid');
const pageOptions = await scan(code, id, settings);

if (typeof pageOptions.prerender === 'undefined') {
pageOptions.prerender = defaultPrerender;
}

// `getStaticPaths` warning is just a string check, should be good enough for most cases
if (!pageOptions.prerender && isServerLikeOutput(settings.config) && code.includes('getStaticPaths')) {
const reason = ` because \`output: "${settings.config.output}"\` is set`
warn(logging, "getStaticPaths", `The getStaticPaths() statement in ${bold(rootRelativePath(settings.config.root, fileURL, true))} has been ignored${reason}.\n\nAdd \`export const prerender = true;\` to prerender this page.`);
}

const { meta = {} } = this.getModuleInfo(id) ?? {};
return {
Expand Down
10 changes: 7 additions & 3 deletions packages/astro/src/vite-plugin-scanner/scan.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { PageOptions } from '../vite-plugin-astro/types.js';
import type { AstroSettings } from '../@types/astro.js';

import * as eslexer from 'es-module-lexer';
import { AstroError, AstroErrorData } from '../core/errors/index.js';
import type { PageOptions } from '../vite-plugin-astro/types.js';

const BOOLEAN_EXPORTS = new Set(['prerender']);

Expand Down Expand Up @@ -34,14 +36,15 @@ function isFalsy(value: string) {

let didInit = false;

export async function scan(code: string, id: string, isHybridOutput = false): Promise<PageOptions> {
export async function scan(code: string, id: string, settings?: AstroSettings): Promise<PageOptions> {
if (!includesExport(code)) return {};
if (!didInit) {
await eslexer.init;
didInit = true;
}

const [, exports] = eslexer.parse(code, id);

let pageOptions: PageOptions = {};
for (const _export of exports) {
const { n: name, le: endOfLocalName } = _export;
Expand All @@ -62,13 +65,14 @@ export async function scan(code: string, id: string, isHybridOutput = false): Pr
if (prefix !== 'const' || !(isTruthy(suffix) || isFalsy(suffix))) {
throw new AstroError({
...AstroErrorData.InvalidPrerenderExport,
message: AstroErrorData.InvalidPrerenderExport.message(prefix, suffix, isHybridOutput),
message: AstroErrorData.InvalidPrerenderExport.message(prefix, suffix, settings?.config.output === 'hybrid' ?? false),
location: { file: id },
});
} else {
pageOptions[name as keyof PageOptions] = isTruthy(suffix);
}
}
}

return pageOptions;
}

0 comments on commit d088351

Please sign in to comment.