-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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: add dynamic image optimization #10323
base: main
Are you sure you want to change the base?
Changes from all commits
a4d5eca
3bf5d7f
7e258fe
7855995
8c6eeef
1a9a930
a22daf0
a6fe421
987eef7
c761719
30d1fd9
e2a3ae6
d5b3f18
09e3ad2
5f4ae65
92851ce
1ad9e80
940cfaa
aab14c0
7cad350
655953a
906a194
0252485
4695a6e
3c2063e
eec30ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/** | ||
* https://vercel.com/docs/concepts/image-optimization | ||
*/ | ||
export default function loader( | ||
src: string, | ||
width: number, | ||
image_options?: { quality?: number } | ||
): string; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// https://vercel.com/docs/concepts/image-optimization | ||
|
||
/** | ||
* @param {string} src | ||
* @param {number} width | ||
* @param {{ quality?: number }} [image_options] | ||
*/ | ||
export default function loader(src, width, image_options) { | ||
const url = new URL(src, 'http://n'); // If the base is a relative URL, we need to add a dummy host to the URL | ||
|
||
if (url.pathname === '/_vercel/image') { | ||
set_param(url, 'w', width); | ||
if (image_options?.quality) { | ||
set_param(url, 'q', image_options.quality, false); | ||
} | ||
} else { | ||
url.pathname = '_vercel/image'; | ||
set_param(url, 'url', src); | ||
set_param(url, 'w', width); | ||
if (image_options?.quality) { | ||
set_param(url, 'q', image_options.quality); | ||
} | ||
} | ||
|
||
return src === url.href ? url.href : relative_url(url); | ||
} | ||
|
||
/** | ||
* @param {URL} url | ||
*/ | ||
function relative_url(url) { | ||
const { pathname, search } = url; | ||
return `${pathname}${search}`; | ||
} | ||
/** | ||
* @param {URL} url | ||
* @param {string} param | ||
* @param {any} value | ||
* @param {boolean} [override] | ||
*/ | ||
function set_param(url, param, value, override = true) { | ||
if (value === undefined) { | ||
return; | ||
} | ||
|
||
if (value === null) { | ||
if (override || url.searchParams.has(param)) { | ||
url.searchParams.delete(param); | ||
} | ||
} else { | ||
if (override || !url.searchParams.has(param)) { | ||
url.searchParams.set(param, value); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,42 @@ | ||
import { Adapter } from '@sveltejs/kit'; | ||
import './ambient.js'; | ||
|
||
export default function plugin(config?: Config): Adapter; | ||
export default function plugin( | ||
config?: Config & { | ||
/** | ||
* Enable or disable Vercel's image optimization. This is enabled by default if you have | ||
* defined the Vercel loader in `kit.images.loader`, else disabled by default. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It'd be nice to show how to do this. E.g. do you set |
||
* https://vercel.com/docs/concepts/image-optimization | ||
*/ | ||
images?: ImageConfig; | ||
} | ||
): Adapter; | ||
|
||
/** | ||
* Define how Vercel should optimize your images. Links to the documentation: | ||
* - https://vercel.com/docs/concepts/image-optimization | ||
* - https://vercel.com/docs/build-output-api/v3/configuration#images | ||
*/ | ||
export interface ImageConfig { | ||
/** Only set this if you're not using SvelteKit's `getImage` from `$app/images` */ | ||
sizes?: number[]; | ||
domains?: string[]; | ||
remotePatterns?: RemotePattern[]; | ||
minimumCacheTTL?: number; | ||
formats?: ImageFormat[]; | ||
dangerouslyAllowSVG?: boolean; | ||
contentSecurityPolicy?: string; | ||
contentDispositionType?: string; | ||
} | ||
|
||
type ImageFormat = 'image/avif' | 'image/webp'; | ||
|
||
type RemotePattern = { | ||
protocol?: 'http' | 'https'; | ||
hostname: string; | ||
port?: string; | ||
pathname?: string; | ||
}; | ||
|
||
export interface ServerlessConfig { | ||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -430,6 +430,27 @@ export interface KitConfig { | |
*/ | ||
errorTemplate?: string; | ||
}; | ||
/** | ||
* Image optimization configuration | ||
*/ | ||
images?: { | ||
/** | ||
* Path to a module that contains a loader that will be used to generate the an image URL out of the given source and width. | ||
* It optionally also takes third parameter for options. Can be either a relative path or a reference to an npm packe. | ||
* | ||
* ```ts | ||
* export default function loader(src: string, width: number, opts: any) { | ||
* return `https://example.com/${src}?w=${width}&q=${opts.quality || 75}`; | ||
* } | ||
* ``` | ||
*/ | ||
loader: string; | ||
/** | ||
* Which srcset sizes to generate | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this description correct? I thought it was the screen sizes. I know you had a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You have to tell Vercel (and some other image optimization providers, too) which image widths / sizes / call-it-whatever-you-want are allowed to be generated. 3840 may sound like a big number, but it really isn't when you think about a 4k resolution laptop screen. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main problem with this config and the domain config is that image optimization providers may have specific settings / requirements. The question now is - how do you make it so that you don't have to duplicate the config? Either you put a common denominator inside the Kit config, and adapters can read from that config, or you provide that config through the adapters, but then we need a way to get the config from the adapter into Kit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd not have any common config. E.g. the
I don't think it's bad if you end up having the same config in different implementations. And in fact it might be helpful because different implementations might have config with the same name that behaves slightly differently |
||
* @default [48, 128, 256, 540, 768, 1080, 1366, 1536, 1920, 2560, 3000, 4096, 5120] | ||
*/ | ||
widths?: number[]; | ||
}; | ||
/** | ||
* Inline CSS inside a `<style>` block at the head of the HTML. This option is a number that specifies the maximum length of a CSS file in UTF-16 code units, as specified by the [String.length](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length) property, to be inlined. All CSS files needed for the page and smaller than this value are merged and inlined in a `<style>` block. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.