summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/dry-worms-knock.md18
-rw-r--r--packages/astro/src/assets/endpoint/config.ts32
-rw-r--r--packages/astro/src/assets/services/service.ts4
-rw-r--r--packages/astro/src/assets/vite-plugin-assets.ts2
-rw-r--r--packages/astro/src/core/build/generate.ts1
-rw-r--r--packages/astro/src/core/config/schema.ts11
-rw-r--r--packages/astro/src/core/request.ts1
-rw-r--r--packages/astro/src/types/public/config.ts20
-rw-r--r--packages/astro/src/vite-plugin-astro-server/route.ts2
-rw-r--r--packages/astro/test/core-image.test.js4
10 files changed, 72 insertions, 23 deletions
diff --git a/.changeset/dry-worms-knock.md b/.changeset/dry-worms-knock.md
new file mode 100644
index 000000000..e8412e3be
--- /dev/null
+++ b/.changeset/dry-worms-knock.md
@@ -0,0 +1,18 @@
+---
+'astro': major
+---
+
+The `image.endpoint` config now allow customizing the route of the image endpoint in addition to the entrypoint. This can be useful in niche situations where the default route `/_image` conflicts with an existing route or your local server setup.
+
+```js
+import { defineConfig } from "astro/config";
+
+defineConfig({
+ image: {
+ endpoint: {
+ route: "/image",
+ entrypoint: "./src/image_endpoint.ts"
+ }
+ },
+})
+```
diff --git a/packages/astro/src/assets/endpoint/config.ts b/packages/astro/src/assets/endpoint/config.ts
index 382645d6e..a910df25c 100644
--- a/packages/astro/src/assets/endpoint/config.ts
+++ b/packages/astro/src/assets/endpoint/config.ts
@@ -1,4 +1,9 @@
+import {
+ removeLeadingForwardSlash,
+ removeTrailingForwardSlash,
+} from '@astrojs/internal-helpers/path';
import { resolveInjectedRoute } from '../../core/routing/manifest/create.js';
+import { getPattern } from '../../core/routing/manifest/pattern.js';
import type { AstroSettings, ManifestData } from '../../types/astro.js';
import type { RouteData } from '../../types/public/internal.js';
@@ -28,19 +33,34 @@ function getImageEndpointData(
cwd?: string,
): RouteData {
const endpointEntrypoint =
- settings.config.image.endpoint ??
- (mode === 'dev' ? 'astro/assets/endpoint/node' : 'astro/assets/endpoint/generic');
+ settings.config.image.endpoint.entrypoint === undefined // If not set, use default endpoint
+ ? mode === 'dev'
+ ? 'astro/assets/endpoint/node'
+ : 'astro/assets/endpoint/generic'
+ : settings.config.image.endpoint.entrypoint;
+
+ const segments = [
+ [
+ {
+ content: removeTrailingForwardSlash(
+ removeLeadingForwardSlash(settings.config.image.endpoint.route),
+ ),
+ dynamic: false,
+ spread: false,
+ },
+ ],
+ ];
return {
type: 'endpoint',
isIndex: false,
- route: '/_image',
- pattern: /^\/_image$/,
- segments: [[{ content: '_image', dynamic: false, spread: false }]],
+ route: settings.config.image.endpoint.route,
+ pattern: getPattern(segments, settings.config.base, settings.config.trailingSlash),
+ segments,
params: [],
component: resolveInjectedRoute(endpointEntrypoint, settings.config.root, cwd).component,
generate: () => '',
- pathname: '/_image',
+ pathname: settings.config.image.endpoint.route,
prerender: false,
fallbackRoutes: [],
};
diff --git a/packages/astro/src/assets/services/service.ts b/packages/astro/src/assets/services/service.ts
index f798e1dfd..e22bada89 100644
--- a/packages/astro/src/assets/services/service.ts
+++ b/packages/astro/src/assets/services/service.ts
@@ -33,7 +33,7 @@ interface SharedServiceProps<T extends Record<string, any> = Record<string, any>
/**
* Return the URL to the endpoint or URL your images are generated from.
*
- * For a local service, your service should expose an endpoint handling the image requests, or use Astro's at `/_image`.
+ * For a local service, your service should expose an endpoint handling the image requests, or use Astro's which by default, is located at `/_image`.
*
* For external services, this should point to the URL your images are coming from, for instance, `/_vercel/image`
*
@@ -343,7 +343,7 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
options[key] && searchParams.append(param, options[key].toString());
});
- const imageEndpoint = joinPaths(import.meta.env.BASE_URL, '/_image');
+ const imageEndpoint = joinPaths(import.meta.env.BASE_URL, imageConfig.endpoint.route);
return `${imageEndpoint}?${searchParams}`;
},
parseURL(url) {
diff --git a/packages/astro/src/assets/vite-plugin-assets.ts b/packages/astro/src/assets/vite-plugin-assets.ts
index 5c40d98b4..7c60a34a2 100644
--- a/packages/astro/src/assets/vite-plugin-assets.ts
+++ b/packages/astro/src/assets/vite-plugin-assets.ts
@@ -101,7 +101,7 @@ export default function assets({
};
return [
- // Expose the components and different utilities from `astro:assets` and handle serving images from `/_image` in dev
+ // Expose the components and different utilities from `astro:assets`
{
name: 'astro:assets',
async resolveId(id) {
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index d59e9966e..9eaf4ff1d 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -412,7 +412,6 @@ async function generatePath(
);
const request = createRequest({
- base: config.base,
url,
headers: new Headers(),
logger,
diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts
index 60427a19e..924c10f8f 100644
--- a/packages/astro/src/core/config/schema.ts
+++ b/packages/astro/src/core/config/schema.ts
@@ -65,6 +65,7 @@ export const ASTRO_CONFIG_DEFAULTS = {
inlineStylesheets: 'auto',
},
image: {
+ endpoint: { entrypoint: undefined, route: '/_image' },
service: { entrypoint: 'astro/assets/services/sharp', config: {} },
},
devToolbar: {
@@ -240,7 +241,15 @@ export const AstroConfigSchema = z.object({
.optional(),
image: z
.object({
- endpoint: z.string().optional(),
+ endpoint: z
+ .object({
+ route: z
+ .literal('/_image')
+ .or(z.string())
+ .default(ASTRO_CONFIG_DEFAULTS.image.endpoint.route),
+ entrypoint: z.string().optional(),
+ })
+ .default(ASTRO_CONFIG_DEFAULTS.image.endpoint),
service: z
.object({
entrypoint: z
diff --git a/packages/astro/src/core/request.ts b/packages/astro/src/core/request.ts
index 78d2979b5..3ace80ba8 100644
--- a/packages/astro/src/core/request.ts
+++ b/packages/astro/src/core/request.ts
@@ -5,7 +5,6 @@ type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
type RequestBody = ArrayBuffer | Blob | ReadableStream | URLSearchParams | FormData;
export interface CreateRequestOptions {
- base: string;
url: URL | string;
clientAddress?: string | undefined;
headers: HeaderType;
diff --git a/packages/astro/src/types/public/config.ts b/packages/astro/src/types/public/config.ts
index 365b3a75d..7a712eb5c 100644
--- a/packages/astro/src/types/public/config.ts
+++ b/packages/astro/src/types/public/config.ts
@@ -904,24 +904,28 @@ export interface AstroUserConfig {
/**
* @docs
* @name image.endpoint
- * @type {string}
- * @default `undefined`
+ * @type {{route: string, entrypoint: undefined | string}}
+ * @default `{route: '/_image', entrypoint: undefined}`
* @version 3.1.0
* @description
- * Set the endpoint to use for image optimization in dev and SSR. Set to `undefined` to use the default endpoint.
- *
- * The endpoint will always be injected at `/_image`.
+ * Set the endpoint to use for image optimization in dev and SSR. The `entrypoint` property can be set to `undefined` to use the default image endpoint.
*
* ```js
* {
* image: {
- * // Example: Use a custom image endpoint
- * endpoint: './src/image-endpoint.ts',
+ * // Example: Use a custom image endpoint at `/custom_endpoint`
+ * endpoint: {
+ * route: '/custom_endpoint',
+ * entrypoint: 'src/my_endpoint.ts',
+ * },
* },
* }
* ```
*/
- endpoint?: string;
+ endpoint?: {
+ route: '/_image' | (string & {});
+ entrypoint: undefined | string;
+ };
/**
* @docs
diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts
index 2bf5a31e4..8df09b898 100644
--- a/packages/astro/src/vite-plugin-astro-server/route.ts
+++ b/packages/astro/src/vite-plugin-astro-server/route.ts
@@ -166,9 +166,9 @@ export async function handleRoute({
const filePath: URL | undefined = matchedRoute.filePath;
const { preloadedComponent } = matchedRoute;
route = matchedRoute.route;
+
// Allows adapters to pass in locals in dev mode.
request = createRequest({
- base: config.base,
url,
headers: incomingRequest.headers,
method: incomingRequest.method,
diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js
index 303bcc7f0..c3490a503 100644
--- a/packages/astro/test/core-image.test.js
+++ b/packages/astro/test/core-image.test.js
@@ -646,7 +646,7 @@ describe('astro:image', () => {
customEndpointFixture = await loadFixture({
root: './fixtures/core-image/',
image: {
- endpoint: './src/custom-endpoint.ts',
+ endpoint: { entrypoint: './src/custom-endpoint.ts' },
service: testImageService({ foo: 'bar' }),
domains: ['avatars.githubusercontent.com'],
},
@@ -1133,7 +1133,7 @@ describe('astro:image', () => {
outDir: './dist/server-prod',
adapter: testAdapter(),
image: {
- endpoint: 'astro/assets/endpoint/node',
+ endpoint: { entrypoint: 'astro/assets/endpoint/node' },
service: testImageService(),
},
});