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

feat: redirect trailing slashes on on-demand rendered pages #12994

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

ascorbic
Copy link
Contributor

@ascorbic ascorbic commented Jan 16, 2025

Changes

When the trailingSlash option is set to always or never, on-demand rendered pages will now redirect to the correct URL when the trailing slash is incorrect. This was previously the case for static pages, but now works for on-demand pages as well. There are some exceptions:

  • when the request matches a static path or file, it is not redirected
  • when trailingSlash is ignore then it is not redirected
  • when the request looks like it is for a file, it is not redirected, even if there is no matching file. e.g. a request for a nonexistent /favicon.ico will not redirect to /favicon.ico/
  • requests for paths starting with /_ with not redirect, because these are usually special internal paths

In dev we don't redirect so it's more obvious that a link is incorrect. Instead I have updated the 404 page to give a bit more information if there's a trailing slash mismatch, and suggest goign to the version with the correct slash:

image

Fixes #12532
Fixes #12833
Fixes #11575

Testing

Added a big test suite. Refer to it for more examples.

Docs

This will need docs

Copy link

changeset-bot bot commented Jan 16, 2025

🦋 Changeset detected

Latest commit: 25a0847

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions bot added pkg: astro Related to the core `astro` package (scope) semver: minor Change triggers a `minor` release labels Jan 16, 2025
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is blocked because it contains a minor changeset. A reviewer will merge this at the next release if approved.

Copy link

codspeed-hq bot commented Jan 16, 2025

CodSpeed Performance Report

Merging #12994 will not alter performance

Comparing trailing-magic (25a0847) with main (df90e6d)

Summary

✅ 6 untouched benchmarks

packages/astro/src/core/app/index.ts Outdated Show resolved Hide resolved
Comment on lines 108 to 111
const withFileExt = /\/[^/]+\.\w+$/;

export function hasFileExtension(path: string) {
return withFileExt.test(path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const withFileExt = /\/[^/]+\.\w+$/;
export function hasFileExtension(path: string) {
return withFileExt.test(path);
const WITH_FILE_EXT = /\/[^/]+\.\w+$/;
export function hasFileExtension(path: string) {
return WITH_FILE_EXT.test(path);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have the fileExtension, so can't we use that? The result would be an empty string 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do, but fileExtension will need a rewrite to use regex and not split though, because it isn't robust in cases where there's no extension. A dot anywhere in the path will give a false positive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this would be the right approach. It's running on every request, so I don't think it makes sense to use a function that does more than is needed.

packages/astro/src/core/app/index.ts Outdated Show resolved Hide resolved
packages/astro/src/core/app/index.ts Show resolved Hide resolved
packages/astro/src/core/app/index.ts Show resolved Hide resolved
@ascorbic
Copy link
Contributor Author

I wonder if this is a significant enough change to be behind an experimental flag.

@ematipico
Copy link
Member

ematipico commented Jan 16, 2025

I wonder if this is a significant enough change to be behind an experimental flag.

This features seems to be mostly a change for adapters. In this case, you might want to add a new Astro feature:

export type AstroAdapterFeatureMap = {
/**
* The adapter is able serve static pages
*/
staticOutput?: AdapterSupport;
/**
* The adapter is able to serve pages that are static or rendered via server
*/
hybridOutput?: AdapterSupport;
/**
* The adapter is able to serve SSR pages
*/
serverOutput?: AdapterSupport;
/**
* The adapter is able to support i18n domains
*/
i18nDomains?: AdapterSupport;
/**
* The adapter is able to support `getSecret` exported from `astro:env/server`
*/
envGetSecret?: AdapterSupport;
/**
* The adapter supports image transformation using the built-in Sharp image service
*/
sharpImageService?: AdapterSupport;
};

Like this, adapters can opt-in and "break" things as much as they want, using their own versioning. What do you think?

@ascorbic
Copy link
Contributor Author

I don't think so. This will work without any change on the adapter's part.

Copy link
Member

@bluwy bluwy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me 👍 I don't think this could break things so probably don't need an experimental option

packages/astro/src/vite-plugin-astro-server/base.ts Outdated Show resolved Hide resolved
@ematipico
Copy link
Member

ematipico commented Jan 16, 2025

I don't think so. This will work without any change on the adapter's part.

That I know. I was suggesting an experimental path without necessarily having one in core, since this is a change that affects only on-demand pages with an adapter, and I would prefer this way because we don't know if users have already fixed this on their end.

@matthewp
Copy link
Contributor

@ematipico why do you think this is breaking?

@ascorbic
Copy link
Contributor Author

!preview trailing-slash-redirect

Copy link
Contributor

Snapshots have been released for the following packages:

  • astro@experimental--trailing-slash-redirect
Publish Log
🦋  warn ===============================IMPORTANT!===============================
🦋  warn Packages will be released under the experimental--trailing-slash-redirect tag
🦋  warn ----------------------------------------------------------------------
🦋  info npm info astro
🦋  info npm info @astrojs/prism
🦋  info npm info @astrojs/rss
🦋  info npm info create-astro
🦋  info npm info @astrojs/db
🦋  info npm info @astrojs/alpinejs
🦋  info npm info @astrojs/markdoc
🦋  info npm info @astrojs/mdx
🦋  info npm info @astrojs/partytown
🦋  info npm info @astrojs/preact
🦋  info npm info @astrojs/react
🦋  info npm info @astrojs/sitemap
🦋  info npm info @astrojs/solid-js
🦋  info npm info @astrojs/svelte
🦋  info npm info @astrojs/tailwind
🦋  info npm info @astrojs/vue
🦋  info npm info @astrojs/web-vitals
🦋  info npm info @astrojs/internal-helpers
🦋  info npm info @astrojs/markdown-remark
🦋  info npm info @astrojs/studio
🦋  info npm info @astrojs/telemetry
🦋  info npm info @astrojs/underscore-redirects
🦋  info npm info @astrojs/upgrade
🦋  info astro is being published because our local version (0.0.0-trailing-slash-redirect-20250121123511) has not been published on npm
🦋  warn @astrojs/prism is not being published because version 3.2.0 is already published on npm
🦋  warn @astrojs/rss is not being published because version 4.0.11 is already published on npm
🦋  warn create-astro is not being published because version 4.11.0 is already published on npm
🦋  warn @astrojs/db is not being published because version 0.14.5 is already published on npm
🦋  warn @astrojs/alpinejs is not being published because version 0.4.1 is already published on npm
🦋  warn @astrojs/markdoc is not being published because version 0.12.6 is already published on npm
🦋  warn @astrojs/mdx is not being published because version 4.0.6 is already published on npm
🦋  warn @astrojs/partytown is not being published because version 2.1.3 is already published on npm
🦋  warn @astrojs/preact is not being published because version 4.0.2 is already published on npm
🦋  warn @astrojs/react is not being published because version 4.1.5 is already published on npm
🦋  warn @astrojs/sitemap is not being published because version 3.2.1 is already published on npm
🦋  warn @astrojs/solid-js is not being published because version 5.0.3 is already published on npm
🦋  warn @astrojs/svelte is not being published because version 7.0.3 is already published on npm
🦋  warn @astrojs/tailwind is not being published because version 5.1.4 is already published on npm
🦋  warn @astrojs/vue is not being published because version 5.0.5 is already published on npm
🦋  warn @astrojs/web-vitals is not being published because version 3.0.1 is already published on npm
🦋  warn @astrojs/internal-helpers is not being published because version 0.4.2 is already published on npm
🦋  warn @astrojs/markdown-remark is not being published because version 6.0.2 is already published on npm
🦋  warn @astrojs/studio is not being published because version 0.1.3 is already published on npm
🦋  warn @astrojs/telemetry is not being published because version 3.2.0 is already published on npm
🦋  warn @astrojs/underscore-redirects is not being published because version 0.6.0 is already published on npm
🦋  warn @astrojs/upgrade is not being published because version 0.4.3 is already published on npm
🦋  info Publishing "astro" at "0.0.0-trailing-slash-redirect-20250121123511"
🦋  success packages published successfully:
🦋  [email protected]
🦋  Creating git tag...
🦋  New tag:  [email protected]
Build Log

> [email protected] build /home/runner/work/astro/astro
> turbo run build --filter=astro --filter=create-astro --filter="@astrojs/*" --filter="@benchmark/*"

• Packages in scope: @astrojs/alpinejs, @astrojs/cloudflare, @astrojs/db, @astrojs/internal-helpers, @astrojs/markdoc, @astrojs/markdown-remark, @astrojs/mdx, @astrojs/netlify, @astrojs/node, @astrojs/partytown, @astrojs/preact, @astrojs/prism, @astrojs/react, @astrojs/rss, @astrojs/sitemap, @astrojs/solid-js, @astrojs/studio, @astrojs/svelte, @astrojs/tailwind, @astrojs/telemetry, @astrojs/underscore-redirects, @astrojs/upgrade, @astrojs/vercel, @astrojs/vue, @astrojs/web-vitals, @benchmark/adapter, @benchmark/timer, astro, create-astro
• Running build in 29 packages
• Remote caching enabled
::group::@astrojs/telemetry:build
cache miss, executing d876d471dc4084c3

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/telemetry
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/internal-helpers:build
cache miss, executing a2645d5c274fb4f7

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/internal-helpers
> astro-scripts build "src/**/*.ts" && tsc -p tsconfig.json

::endgroup::
::group::create-astro:build
cache miss, executing a513ef99a7061599

> [email protected] build /home/runner/work/astro/astro/packages/create-astro
> astro-scripts build "src/index.ts" --bundle && tsc

::endgroup::
::group::@astrojs/upgrade:build
cache miss, executing d633ad364f73ba09

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/upgrade
> astro-scripts build "src/index.ts" --bundle && tsc

::endgroup::
::group::@astrojs/prism:build
cache miss, executing 03f2919d025425f4

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/astro-prism
> astro-scripts build "src/**/*.ts" && tsc -p ./tsconfig.json

::endgroup::
::group::@astrojs/markdown-remark:build
cache miss, executing 765afdc94755514e

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/markdown/remark
> astro-scripts build "src/**/*.ts" && tsc -p tsconfig.json

::endgroup::
::group::astro:build
cache miss, executing 317f0e9d79a67fe0

> [email protected] build /home/runner/work/astro/astro/packages/astro
> pnpm run prebuild && astro-scripts build "src/**/*.{ts,js}" --copy-wasm && tsc


> [email protected] prebuild /home/runner/work/astro/astro/packages/astro
> astro-scripts prebuild --to-string "src/runtime/server/astro-island.ts" "src/runtime/client/{idle,load,media,only,visible}.ts"

::endgroup::
::group::@astrojs/studio:build
cache miss, executing 3777e5fa0a5bcbe8

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/studio
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/alpinejs:build
cache miss, executing ccd4db1e1aa94a59

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/alpinejs
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/rss:build
cache miss, executing 4efd35f98a9c20d4

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/astro-rss
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/partytown:build
cache miss, executing eb6045f12825aae5

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/partytown
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@benchmark/adapter:build
cache miss, executing 3c7b39c696d7dc86

> @benchmark/[email protected] build /home/runner/work/astro/astro/benchmark/packages/adapter
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/svelte:build
cache miss, executing 7441636da8213514

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/svelte
> astro-scripts build "src/index.ts" && astro-scripts build "src/editor.cts" --force-cjs --no-clean-dist && tsc

::endgroup::
::group::@astrojs/react:build
cache miss, executing 94fda5aa6d00ecf1

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/react
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/tailwind:build
cache miss, executing 9f42babf21ae4520

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/tailwind
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/vue:build
cache miss, executing bd1b260a8dbb0b18

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/vue
> astro-scripts build "src/index.ts" && astro-scripts build "src/editor.cts" --force-cjs --no-clean-dist && tsc

::endgroup::
::group::@astrojs/mdx:build
cache miss, executing 3bc5a795432ddb38

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/mdx
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@benchmark/timer:build
cache miss, executing 72027d5354b9c330

> @benchmark/[email protected] build /home/runner/work/astro/astro/benchmark/packages/timer
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/underscore-redirects:build
cache miss, executing b9667b3402a7facb

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/underscore-redirects
> astro-scripts build "src/**/*.ts" && tsc -p tsconfig.json

::endgroup::
::group::@astrojs/markdoc:build
cache miss, executing b6b03356271c58d7

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/markdoc
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/sitemap:build
cache miss, executing e7919ab24e15764e

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/sitemap
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/solid-js:build
cache miss, executing 63df8cdba110cc70

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/solid
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/preact:build
cache miss, executing d2c12e381ec2fe94

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/preact
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::
::group::@astrojs/db:build
cache miss, executing e9382d391d1c0ee9

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/db
> astro-scripts build "src/**/*.ts" && tsc && pnpm types:virtual


> @astrojs/[email protected] types:virtual /home/runner/work/astro/astro/packages/db
> tsc -p ./tsconfig.virtual.json

::endgroup::
::group::@astrojs/web-vitals:build
cache miss, executing 9c9e132a2421953e

> @astrojs/[email protected] build /home/runner/work/astro/astro/packages/integrations/web-vitals
> astro-scripts build "src/**/*.ts" && tsc

::endgroup::

 Tasks:    25 successful, 25 total
Cached:    0 cached, 25 total
  Time:    46.75s 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: astro Related to the core `astro` package (scope) semver: minor Change triggers a `minor` release
Projects
None yet
4 participants