diff options
author | 2022-07-01 15:47:48 +0000 | |
---|---|---|
committer | 2022-07-01 15:47:48 +0000 | |
commit | e8593e7eadcf2bfbbbdef879c148ff47235591cc (patch) | |
tree | eb60be06a5de3b017cd60c7cfa3a6d80b407efa5 /packages/integrations/image/src/utils.ts | |
parent | 0f73ece26bfc03570a7cab100255de4fbbb1ecfa (diff) | |
download | astro-e8593e7eadcf2bfbbbdef879c148ff47235591cc.tar.gz astro-e8593e7eadcf2bfbbbdef879c148ff47235591cc.tar.zst astro-e8593e7eadcf2bfbbbdef879c148ff47235591cc.zip |
Adds an `@astrojs/image` integration for optimizing images (#3694)
* initial commit
* WIP: starting to define interfaces for images and transformers
* WIP: basic sharp service to test out the API setup
* adding a few tests for sharp.toImageSrc
* Adding tests for sharp.parseImageSrc
* hooking up basic SSR support
* updating image services to return width/height
* simplifying config setup for v1
* hooking up basic SSR + SSG support (dev & build)
* refactor: a bit of code cleanup and commenting
* WIP: migrating local files to ESM + vite plugin
* WIP: starting to hook up user-provided loaderEntryPoints
* chore: update lock file
* chore: update merged lockfile
* refactor: code cleanup and type docs
* pulling over the README template for first-party integrations
* moving metadata out to the loader
* updating the test for the refactored import
* revert: remove unrelated webapi formatting
* revert: remove unrelated change
* fixing up the existing sharp tests
* fix: vite plugin wasn't dynamically loading the image service properly
* refactor: minor API renaming, removing last hard-coded use of sharp loader
* don't manipulate src for hosted image services
* Adding support for automatically calculating dimensions by aspect ratio, if needed
* a few bug fixes + renaming the aspect ratio search param to "ar"
* Adding ETag support, removing need for loaders to parse file metadata
* using the battle tested `etag` package
* Adding support for dynamically calculating partial sizes
* refactor: moving to the packages/integrations dir, Astro Labs TBD later
* refactor: renaming parse/serialize functions
* Adding tests for SSG image optimizations
* refactor: clean up outdated names related to ImageProps
* nit: reusing cached SSG filename
* chore: update pnpm lock file
* handling file URLs when resolving local image imports
* updating image file resolution to use file URLs
* increasing test timeout for image build tests
* fixing eslint error in sharp test
* adding slash for windows compat in src URLs
* chore: update lockfile after merge
* Adding README content
* adding a readme call to action for configuration options
* review: A few of the quick updates from the PR review
* hack: adds a one-off check to allow query params for the _image route
* Adds support for src={import("...")}, and named component exports
* adding SSR tests
* nit: adding a bit more comments
* limiting the query params in SSG dev to the images integration
Diffstat (limited to 'packages/integrations/image/src/utils.ts')
-rw-r--r-- | packages/integrations/image/src/utils.ts | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/packages/integrations/image/src/utils.ts b/packages/integrations/image/src/utils.ts new file mode 100644 index 000000000..48249aff1 --- /dev/null +++ b/packages/integrations/image/src/utils.ts @@ -0,0 +1,62 @@ +import fs from 'fs'; +import path from 'path'; +import type { OutputFormat, TransformOptions } from './types'; + + export function isOutputFormat(value: string): value is OutputFormat { + return ['avif', 'jpeg', 'png', 'webp'].includes(value); +} + +export function isAspectRatioString(value: string): value is `${number}:${number}` { + return /^\d*:\d*$/.test(value); +} + +export function ensureDir(dir: string) { + fs.mkdirSync(dir, { recursive: true }); +} + +export function isRemoteImage(src: string) { + return /^http(s?):\/\//.test(src); +} + +export async function loadLocalImage(src: string) { + try { + return await fs.promises.readFile(src); + } catch { + return undefined; + } +} + +export async function loadRemoteImage(src: string) { + try { + const res = await fetch(src); + + if (!res.ok) { + return undefined; + } + + return Buffer.from(await res.arrayBuffer()); + } catch { + return undefined; + } +} + +export async function loadImage(src: string) { + return isRemoteImage(src) + ? await loadRemoteImage(src) + : await loadLocalImage(src); +} + +export function propsToFilename({ src, width, height, format }: TransformOptions) { + const ext = path.extname(src); + let filename = src.replace(ext, ''); + + if (width && height) { + return `${filename}_${width}x${height}.${format}`; + } else if (width) { + return `${filename}_${width}w.${format}`; + } else if (height) { + return `${filename}_${height}h.${format}`; + } + + return format ? src.replace(ext, format) : src; +} |