astro/packages/integrations/image/src/index.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

118 lines
3.4 KiB
TypeScript
Raw Normal View History

import type { AstroConfig, AstroIntegration } from 'astro';
import { ssgBuild } from './build/ssg.js';
import type { ImageService, TransformOptions } from './loaders/index.js';
import type { LoggerLevel } from './utils/logger.js';
import { joinPaths, prependForwardSlash, propsToFilename } from './utils/paths.js';
2022-08-30 21:12:45 +00:00
import { createPlugin } from './vite-plugin-astro-image.js';
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
2022-07-01 15:47:48 +00:00
export { getImage } from './lib/get-image.js';
export { getPicture } from './lib/get-picture.js';
const PKG_NAME = '@astrojs/image';
const ROUTE_PATTERN = '/_image';
interface ImageIntegration {
loader?: ImageService;
addStaticImage?: (transform: TransformOptions) => string;
}
declare global {
// eslint-disable-next-line no-var
var astroImage: ImageIntegration | undefined;
}
export interface IntegrationOptions {
/**
* Entry point for the @type {HostedImageService} or @type {LocalImageService} to be used.
*/
serviceEntryPoint?: string;
logLevel?: LoggerLevel;
}
export default function integration(options: IntegrationOptions = {}): AstroIntegration {
const resolvedOptions = {
serviceEntryPoint: '@astrojs/image/sharp',
logLevel: 'info' as LoggerLevel,
...options,
};
let _config: AstroConfig;
// During SSG builds, this is used to track all transformed images required.
const staticImages = new Map<string, Map<string, TransformOptions>>();
function getViteConfiguration() {
return {
plugins: [createPlugin(_config, resolvedOptions)],
optimizeDeps: {
include: ['image-size', 'sharp'],
},
ssr: {
noExternal: ['@astrojs/image', resolvedOptions.serviceEntryPoint],
},
};
}
return {
name: PKG_NAME,
hooks: {
'astro:config:setup': ({ command, config, updateConfig, injectRoute }) => {
_config = config;
updateConfig({ vite: getViteConfiguration() });
if (command === 'dev' || config.output === 'server') {
injectRoute({
pattern: ROUTE_PATTERN,
entryPoint: '@astrojs/image/endpoint',
});
}
},
'astro:build:setup': () => {
// Used to cache all images rendered to HTML
// Added to globalThis to share the same map in Node and Vite
function addStaticImage(transform: TransformOptions) {
const srcTranforms = staticImages.has(transform.src)
? staticImages.get(transform.src)!
: new Map<string, TransformOptions>();
const filename = propsToFilename(transform);
srcTranforms.set(filename, transform);
staticImages.set(transform.src, srcTranforms);
// Prepend the Astro config's base path, if it was used.
// Doing this here makes sure that base is ignored when building
// staticImages to /dist, but the rendered HTML will include the
// base prefix for `src`.
return prependForwardSlash(joinPaths(_config.base, 'assets', filename));
}
// Helpers for building static images should only be available for SSG
globalThis.astroImage =
_config.output === 'static'
? {
addStaticImage,
}
: {};
},
'astro:build:done': async ({ dir }) => {
if (_config.output === 'static') {
// for SSG builds, build all requested image transforms to dist
const loader = globalThis?.astroImage?.loader;
if (loader && 'transform' in loader && staticImages.size > 0) {
2022-08-22 19:15:35 +00:00
await ssgBuild({
loader,
staticImages,
config: _config,
2022-08-22 19:15:35 +00:00
outDir: dir,
logLevel: resolvedOptions.logLevel,
});
}
}
2022-08-30 21:12:45 +00:00
},
},
};
}