summaryrefslogtreecommitdiff
path: root/packages/integrations/vercel/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/vercel/src')
-rw-r--r--packages/integrations/vercel/src/image/build-service.ts5
-rw-r--r--packages/integrations/vercel/src/image/dev-service.ts43
-rw-r--r--packages/integrations/vercel/src/image/shared-dev-service.ts33
-rw-r--r--packages/integrations/vercel/src/image/shared.ts28
-rw-r--r--packages/integrations/vercel/src/image/squoosh-dev-service.ts31
-rw-r--r--packages/integrations/vercel/src/serverless/adapter.ts11
-rw-r--r--packages/integrations/vercel/src/static/adapter.ts11
7 files changed, 119 insertions, 43 deletions
diff --git a/packages/integrations/vercel/src/image/build-service.ts b/packages/integrations/vercel/src/image/build-service.ts
index 0e45167d4..bd58d3af6 100644
--- a/packages/integrations/vercel/src/image/build-service.ts
+++ b/packages/integrations/vercel/src/image/build-service.ts
@@ -40,8 +40,9 @@ const service: ExternalImageService = {
};
},
getURL(options) {
- const fileSrc =
- typeof options.src === 'string' ? options.src : removeLeadingForwardSlash(options.src.src);
+ const fileSrc = isESMImportedImage(options.src)
+ ? removeLeadingForwardSlash(options.src.src)
+ : options.src;
const searchParams = new URLSearchParams();
searchParams.append('url', fileSrc);
diff --git a/packages/integrations/vercel/src/image/dev-service.ts b/packages/integrations/vercel/src/image/dev-service.ts
index a335c8d23..c9702cff9 100644
--- a/packages/integrations/vercel/src/image/dev-service.ts
+++ b/packages/integrations/vercel/src/image/dev-service.ts
@@ -1,10 +1,9 @@
import type { LocalImageService } from 'astro';
-import squooshService from 'astro/assets/services/squoosh';
-import { sharedValidateOptions } from './shared.js';
+import sharpService from 'astro/assets/services/sharp';
+import { baseDevService } from './shared-dev-service.js';
const service: LocalImageService = {
- validateOptions: (options, serviceOptions) =>
- sharedValidateOptions(options, serviceOptions.service.config, 'development'),
+ ...baseDevService,
getHTMLAttributes(options, serviceOptions) {
const { inputtedWidth, ...props } = options;
@@ -13,45 +12,19 @@ const service: LocalImageService = {
props.width = inputtedWidth;
}
- return squooshService.getHTMLAttributes
- ? squooshService.getHTMLAttributes(props, serviceOptions)
+ return sharpService.getHTMLAttributes
+ ? sharpService.getHTMLAttributes(props, serviceOptions)
: {};
},
- getURL(options) {
- const fileSrc = typeof options.src === 'string' ? options.src : options.src.src;
-
- const searchParams = new URLSearchParams();
- searchParams.append('href', fileSrc);
-
- options.width && searchParams.append('w', options.width.toString());
- options.quality && searchParams.append('q', options.quality.toString());
-
- return '/_image?' + searchParams;
- },
- parseURL(url) {
- const params = url.searchParams;
-
- if (!params.has('href')) {
- return undefined;
- }
-
- const transform = {
- src: params.get('href')!,
- width: params.has('w') ? parseInt(params.get('w')!) : undefined,
- quality: params.get('q'),
- };
-
- return transform;
- },
transform(inputBuffer, transform, serviceOptions) {
// NOTE: Hardcoding webp here isn't accurate to how the Vercel Image Optimization API works, normally what we should
// do is setup a custom endpoint that sniff the user's accept-content header and serve the proper format based on the
// user's Vercel config. However, that's: a lot of work for: not much. The dev service is inaccurate to the prod service
// in many more ways, this is one of the less offending cases and is, imo, okay, erika - 2023-04-27
- transform.format = 'webp';
+ transform.format = transform.src.endsWith('svg') ? 'svg' : 'webp';
- // The base Squoosh service works the same way as the Vercel Image Optimization API, so it's a safe fallback in local
- return squooshService.transform(inputBuffer, transform, serviceOptions);
+ // The base sharp service works the same way as the Vercel Image Optimization API, so it's a safe fallback in local
+ return sharpService.transform(inputBuffer, transform, serviceOptions);
},
};
diff --git a/packages/integrations/vercel/src/image/shared-dev-service.ts b/packages/integrations/vercel/src/image/shared-dev-service.ts
new file mode 100644
index 000000000..4251603a7
--- /dev/null
+++ b/packages/integrations/vercel/src/image/shared-dev-service.ts
@@ -0,0 +1,33 @@
+import type { LocalImageService } from 'astro';
+import { sharedValidateOptions } from './shared.js';
+
+export const baseDevService: Omit<LocalImageService, 'transform'> = {
+ validateOptions: (options, serviceOptions) =>
+ sharedValidateOptions(options, serviceOptions.service.config, 'development'),
+ getURL(options) {
+ const fileSrc = typeof options.src === 'string' ? options.src : options.src.src;
+
+ const searchParams = new URLSearchParams();
+ searchParams.append('href', fileSrc);
+
+ options.width && searchParams.append('w', options.width.toString());
+ options.quality && searchParams.append('q', options.quality.toString());
+
+ return '/_image?' + searchParams;
+ },
+ parseURL(url) {
+ const params = url.searchParams;
+
+ if (!params.has('href')) {
+ return undefined;
+ }
+
+ const transform = {
+ src: params.get('href')!,
+ width: params.has('w') ? parseInt(params.get('w')!) : undefined,
+ quality: params.get('q'),
+ };
+
+ return transform;
+ },
+};
diff --git a/packages/integrations/vercel/src/image/shared.ts b/packages/integrations/vercel/src/image/shared.ts
index f6cace2a2..079186e18 100644
--- a/packages/integrations/vercel/src/image/shared.ts
+++ b/packages/integrations/vercel/src/image/shared.ts
@@ -12,6 +12,10 @@ export function getDefaultImageConfig(astroImageConfig: AstroConfig['image']): V
export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata {
return typeof src === 'object';
}
+
+// eslint-disable-next-line @typescript-eslint/ban-types
+export type DevImageService = 'sharp' | 'squoosh' | (string & {});
+
// https://vercel.com/docs/build-output-api/v3/configuration#images
type ImageFormat = 'image/avif' | 'image/webp';
@@ -64,16 +68,32 @@ export function getAstroImageConfig(
images: boolean | undefined,
imagesConfig: VercelImageConfig | undefined,
command: string,
+ devImageService: DevImageService,
astroImageConfig: AstroConfig['image']
) {
+ let devService = '@astrojs/vercel/dev-image-service';
+
+ switch (devImageService) {
+ case 'sharp':
+ devService = '@astrojs/vercel/dev-image-service';
+ break;
+ case 'squoosh':
+ devService = '@astrojs/vercel/squoosh-dev-image-service';
+ break;
+ default:
+ if (typeof devImageService === 'string') {
+ devService = devImageService;
+ } else {
+ devService = '@astrojs/vercel/dev-image-service';
+ }
+ break;
+ }
+
if (images) {
return {
image: {
service: {
- entrypoint:
- command === 'dev'
- ? '@astrojs/vercel/dev-image-service'
- : '@astrojs/vercel/build-image-service',
+ entrypoint: command === 'dev' ? devService : '@astrojs/vercel/build-image-service',
config: imagesConfig ? imagesConfig : getDefaultImageConfig(astroImageConfig),
},
},
diff --git a/packages/integrations/vercel/src/image/squoosh-dev-service.ts b/packages/integrations/vercel/src/image/squoosh-dev-service.ts
new file mode 100644
index 000000000..d3b05bb11
--- /dev/null
+++ b/packages/integrations/vercel/src/image/squoosh-dev-service.ts
@@ -0,0 +1,31 @@
+import type { LocalImageService } from 'astro';
+import squooshService from 'astro/assets/services/squoosh';
+import { baseDevService } from './shared-dev-service.js';
+
+const service: LocalImageService = {
+ ...baseDevService,
+ getHTMLAttributes(options, serviceOptions) {
+ const { inputtedWidth, ...props } = options;
+
+ // If `validateOptions` returned a different width than the one of the image, use it for attributes
+ if (inputtedWidth) {
+ props.width = inputtedWidth;
+ }
+
+ return squooshService.getHTMLAttributes
+ ? squooshService.getHTMLAttributes(props, serviceOptions)
+ : {};
+ },
+ transform(inputBuffer, transform, serviceOptions) {
+ // NOTE: Hardcoding webp here isn't accurate to how the Vercel Image Optimization API works, normally what we should
+ // do is setup a custom endpoint that sniff the user's accept-content header and serve the proper format based on the
+ // user's Vercel config. However, that's: a lot of work for: not much. The dev service is inaccurate to the prod service
+ // in many more ways, this is one of the less offending cases and is, imo, okay, erika - 2023-04-27
+ transform.format = transform.src.endsWith('svg') ? 'svg' : 'webp';
+
+ // The base squoosh service works the same way as the Vercel Image Optimization API, so it's a safe fallback in local
+ return squooshService.transform(inputBuffer, transform, serviceOptions);
+ },
+};
+
+export default service;
diff --git a/packages/integrations/vercel/src/serverless/adapter.ts b/packages/integrations/vercel/src/serverless/adapter.ts
index 1c0eb9530..22785abf5 100644
--- a/packages/integrations/vercel/src/serverless/adapter.ts
+++ b/packages/integrations/vercel/src/serverless/adapter.ts
@@ -12,6 +12,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
import {
getAstroImageConfig,
getDefaultImageConfig,
+ type DevImageService,
type VercelImageConfig,
} from '../image/shared.js';
import { exposeEnv } from '../lib/env.js';
@@ -68,6 +69,7 @@ export interface VercelServerlessConfig {
analytics?: boolean;
imageService?: boolean;
imagesConfig?: VercelImageConfig;
+ devImageService?: DevImageService;
edgeMiddleware?: boolean;
functionPerRoute?: boolean;
}
@@ -78,6 +80,7 @@ export default function vercelServerless({
analytics,
imageService,
imagesConfig,
+ devImageService = 'sharp',
functionPerRoute = true,
edgeMiddleware = false,
}: VercelServerlessConfig = {}): AstroIntegration {
@@ -147,7 +150,13 @@ export default function vercelServerless({
external: ['@vercel/nft'],
},
},
- ...getAstroImageConfig(imageService, imagesConfig, command, config.image),
+ ...getAstroImageConfig(
+ imageService,
+ imagesConfig,
+ command,
+ devImageService,
+ config.image
+ ),
});
},
'astro:config:done': ({ setAdapter, config, logger }) => {
diff --git a/packages/integrations/vercel/src/static/adapter.ts b/packages/integrations/vercel/src/static/adapter.ts
index 2908dbf58..27bc2fe2d 100644
--- a/packages/integrations/vercel/src/static/adapter.ts
+++ b/packages/integrations/vercel/src/static/adapter.ts
@@ -3,6 +3,7 @@ import type { AstroAdapter, AstroConfig, AstroIntegration } from 'astro';
import {
getAstroImageConfig,
getDefaultImageConfig,
+ type DevImageService,
type VercelImageConfig,
} from '../image/shared.js';
import { exposeEnv } from '../lib/env.js';
@@ -36,12 +37,14 @@ export interface VercelStaticConfig {
analytics?: boolean;
imageService?: boolean;
imagesConfig?: VercelImageConfig;
+ devImageService?: DevImageService;
}
export default function vercelStatic({
analytics,
imageService,
imagesConfig,
+ devImageService = 'sharp',
}: VercelStaticConfig = {}): AstroIntegration {
let _config: AstroConfig;
@@ -63,7 +66,13 @@ export default function vercelStatic({
vite: {
define: viteDefine,
},
- ...getAstroImageConfig(imageService, imagesConfig, command, config.image),
+ ...getAstroImageConfig(
+ imageService,
+ imagesConfig,
+ command,
+ devImageService,
+ config.image
+ ),
});
},
'astro:config:done': ({ setAdapter, config }) => {