From 4e5cc5aadd7d864bc5194ee67dc2ea74dbe80473 Mon Sep 17 00:00:00 2001 From: Kevin <46791833+kevinzunigacuellar@users.noreply.github.com> Date: Wed, 28 Aug 2024 05:31:32 -0400 Subject: [PATCH] Add base to paginate (#11253) * add base to `paginate()` * update tests * remove condicional cache * add missing base param * add missing leading slash in tests * remove default * fix: add missing trailing slash in pagination root test * Add feedback from code review * add changeset * rebase and run format code * Update .changeset/twenty-cobras-push.md Co-authored-by: Sarah Rainsberger * add code diff * fix rebase * Apply suggestions from code review Co-authored-by: Sarah Rainsberger * chore: merge next * update changeset --------- Co-authored-by: Emanuele Stoppa Co-authored-by: Sarah Rainsberger --- .changeset/twenty-cobras-push.md | 32 +++++++++++++++++++ packages/astro/src/core/build/generate.ts | 3 +- packages/astro/src/core/render-context.ts | 3 +- packages/astro/src/core/render/paginate.ts | 24 ++++++++------ .../astro/src/core/render/params-and-props.ts | 4 ++- packages/astro/src/core/render/route-cache.ts | 6 ++-- .../src/vite-plugin-astro-server/route.ts | 1 + .../test/astro-pagination-root-spread.test.js | 6 ++-- packages/astro/test/astro-pagination.test.js | 4 +-- 9 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 .changeset/twenty-cobras-push.md diff --git a/.changeset/twenty-cobras-push.md b/.changeset/twenty-cobras-push.md new file mode 100644 index 0000000000..5555cdc613 --- /dev/null +++ b/.changeset/twenty-cobras-push.md @@ -0,0 +1,32 @@ +--- +'astro': major +--- + +Changes the data returned for `page.url.current`, `page.url.next`, `page.url.prev`, `page.url.first` and `page.url.last` to include the value set for `base` in your Astro config. + +Previously, you had to manually prepend your configured value for `base` to the URL path. Now, Astro automatically includes your `base` value in `next` and `prev` URLs. + +If you are using the `paginate()` function for "previous" and "next" URLs, remove any existing `base` value as it is now added for you: + +```diff +--- +export async function getStaticPaths({ paginate }) { + const astronautPages = [{ + astronaut: 'Neil Armstrong', + }, { + astronaut: 'Buzz Aldrin', + }, { + astronaut: 'Sally Ride', + }, { + astronaut: 'John Glenn', + }]; + return paginate(astronautPages, { pageSize: 1 }); +} +const { page } = Astro.props; +// `base: /'docs'` configured in `astro.config.mjs` +- const prev = "/docs" + page.url.prev; ++ const prev = page.url.prev; +--- + +``` + diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 5c9ee20b6c..15121d9c22 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -220,7 +220,7 @@ async function getPathsForRoute( pipeline: BuildPipeline, builtPaths: Set, ): Promise> { - const { logger, options, routeCache, serverLike } = pipeline; + const { logger, options, routeCache, serverLike, config } = pipeline; let paths: Array = []; if (route.pathname) { paths.push(route.pathname); @@ -232,6 +232,7 @@ async function getPathsForRoute( routeCache, logger, ssr: serverLike, + base: config.base, }).catch((err) => { logger.error('build', `Failed to call getStaticPaths for ${route.component}`); throw err; diff --git a/packages/astro/src/core/render-context.ts b/packages/astro/src/core/render-context.ts index 6e40c93241..1c0017c301 100644 --- a/packages/astro/src/core/render-context.ts +++ b/packages/astro/src/core/render-context.ts @@ -109,7 +109,7 @@ export class RenderContext { slots: Record = {}, ): Promise { const { cookies, middleware, pipeline } = this; - const { logger, serverLike, streaming } = pipeline; + const { logger, serverLike, streaming, manifest } = pipeline; const props = Object.keys(this.props).length > 0 @@ -121,6 +121,7 @@ export class RenderContext { pathname: this.pathname, logger, serverLike, + base: manifest.base, }); const apiContext = this.createAPIContext(props); diff --git a/packages/astro/src/core/render/paginate.ts b/packages/astro/src/core/render/paginate.ts index c462cd4b86..77ee5e9fbd 100644 --- a/packages/astro/src/core/render/paginate.ts +++ b/packages/astro/src/core/render/paginate.ts @@ -5,11 +5,14 @@ import type { Params, Props, } from '../../types/public/common.js'; +import type { AstroConfig } from '../../types/public/index.js'; import type { RouteData } from '../../types/public/internal.js'; import { AstroError, AstroErrorData } from '../errors/index.js'; +import { joinPaths } from '../path.js'; export function generatePaginateFunction( routeMatch: RouteData, + base: AstroConfig['base'], ): (...args: Parameters) => ReturnType { return function paginateUtility( data: any[], @@ -41,34 +44,36 @@ export function generatePaginateFunction( ...additionalParams, [paramName]: includesFirstPageNumber || pageNum > 1 ? String(pageNum) : undefined, }; - const current = correctIndexRoute(routeMatch.generate({ ...params })); + const current = addRouteBase(routeMatch.generate({ ...params }), base); const next = pageNum === lastPage ? undefined - : correctIndexRoute(routeMatch.generate({ ...params, page: String(pageNum + 1) })); + : addRouteBase(routeMatch.generate({ ...params, page: String(pageNum + 1) }), base); const prev = pageNum === 1 ? undefined - : correctIndexRoute( + : addRouteBase( routeMatch.generate({ ...params, page: !includesFirstPageNumber && pageNum - 1 === 1 ? undefined : String(pageNum - 1), }), + base, ); const first = pageNum === 1 ? undefined - : correctIndexRoute( + : addRouteBase( routeMatch.generate({ ...params, page: includesFirstPageNumber ? '1' : undefined, }), + base, ); const last = pageNum === lastPage ? undefined - : correctIndexRoute(routeMatch.generate({ ...params, page: String(lastPage) })); + : addRouteBase(routeMatch.generate({ ...params, page: String(lastPage) }), base); return { params, props: { @@ -90,12 +95,11 @@ export function generatePaginateFunction( }; } -function correctIndexRoute(route: string) { +function addRouteBase(route: string, base: AstroConfig['base']) { // `routeMatch.generate` avoids appending `/` // unless `trailingSlash: 'always'` is configured. // This means an empty string is possible for the index route. - if (route === '') { - return '/'; - } - return route; + let routeWithBase = joinPaths(base, route); + if (routeWithBase === '') routeWithBase = '/'; + return routeWithBase; } diff --git a/packages/astro/src/core/render/params-and-props.ts b/packages/astro/src/core/render/params-and-props.ts index a45fb16a80..0beebda794 100644 --- a/packages/astro/src/core/render/params-and-props.ts +++ b/packages/astro/src/core/render/params-and-props.ts @@ -16,10 +16,11 @@ interface GetParamsAndPropsOptions { pathname: string; logger: Logger; serverLike: boolean; + base: string; } export async function getProps(opts: GetParamsAndPropsOptions): Promise { - const { logger, mod, routeData: route, routeCache, pathname, serverLike } = opts; + const { logger, mod, routeData: route, routeCache, pathname, serverLike, base } = opts; // If there's no route, or if there's a pathname (e.g. a static `src/pages/normal.astro` file), // then we know for sure they don't have params and props, return a fallback value. @@ -49,6 +50,7 @@ export async function getProps(opts: GetParamsAndPropsOptions): Promise { routeCache, logger, ssr: serverLike, + base, }); const matchedStaticPath = findPathItemByKey(staticPaths, params, route, logger); diff --git a/packages/astro/src/core/render/route-cache.ts b/packages/astro/src/core/render/route-cache.ts index 3329c42cd3..247f3aa235 100644 --- a/packages/astro/src/core/render/route-cache.ts +++ b/packages/astro/src/core/render/route-cache.ts @@ -6,7 +6,7 @@ import type { PaginateFunction, Params, } from '../../types/public/common.js'; -import type { RuntimeMode } from '../../types/public/config.js'; +import type { AstroConfig, RuntimeMode } from '../../types/public/config.js'; import type { RouteData } from '../../types/public/internal.js'; import type { Logger } from '../logger/core.js'; @@ -20,6 +20,7 @@ interface CallGetStaticPathsOptions { routeCache: RouteCache; logger: Logger; ssr: boolean; + base: AstroConfig['base']; } export async function callGetStaticPaths({ @@ -28,6 +29,7 @@ export async function callGetStaticPaths({ routeCache, logger, ssr, + base, }: CallGetStaticPathsOptions): Promise { const cached = routeCache.get(route); if (!mod) { @@ -57,7 +59,7 @@ export async function callGetStaticPaths({ staticPaths = await mod.getStaticPaths({ // Q: Why the cast? // A: So users downstream can have nicer typings, we have to make some sacrifice in our internal typings, which necessitate a cast here - paginate: generatePaginateFunction(route) as PaginateFunction, + paginate: generatePaginateFunction(route, base) as PaginateFunction, }); validateGetStaticPathsResult(staticPaths, logger, route); diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index c59af5c80c..e60024e4b7 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -66,6 +66,7 @@ export async function matchRoute( pathname: pathname, logger, serverLike, + base: config.base, }); return { route: maybeRoute, diff --git a/packages/astro/test/astro-pagination-root-spread.test.js b/packages/astro/test/astro-pagination-root-spread.test.js index 3accbb2266..3aad4d6419 100644 --- a/packages/astro/test/astro-pagination-root-spread.test.js +++ b/packages/astro/test/astro-pagination-root-spread.test.js @@ -17,9 +17,9 @@ describe('Pagination root', () => { it('correct prev url in root spread', async () => { const prevMap = { - '/4/': '/3', - '/3/': '/2', - '/2/': '/', + '/4/': '/blog/3', + '/3/': '/blog/2', + '/2/': '/blog/', '/': undefined, }; diff --git a/packages/astro/test/astro-pagination.test.js b/packages/astro/test/astro-pagination.test.js index ed3b2fc473..f89fcb4f62 100644 --- a/packages/astro/test/astro-pagination.test.js +++ b/packages/astro/test/astro-pagination.test.js @@ -58,10 +58,10 @@ describe('Pagination', () => { } if (color === 'blue' && p === '1') { assert.equal(prevHref, undefined); - assert.equal(nextHref, '/posts/blue/2'); + assert.equal(nextHref, '/blog/posts/blue/2'); } if (color === 'blue' && p === '2') { - assert.equal(prevHref, '/posts/blue/1'); + assert.equal(prevHref, '/blog/posts/blue/1'); assert.equal(nextHref, undefined); } }),