2022-10-12 21:25:51 +00:00
|
|
|
import type { AstroConfig, AstroIntegration } from 'astro';
|
2022-07-27 15:39:05 +00:00
|
|
|
import { ssgBuild } from './build/ssg.js';
|
2022-09-22 19:48:14 +00:00
|
|
|
import type { ImageService, SSRImageService, TransformOptions } from './loaders/index.js';
|
2022-08-22 19:13:19 +00:00
|
|
|
import type { LoggerLevel } from './utils/logger.js';
|
2022-08-30 21:09:44 +00:00
|
|
|
import { joinPaths, prependForwardSlash, propsToFilename } from './utils/paths.js';
|
2022-09-22 19:48:14 +00:00
|
|
|
import { copyWasmFiles } from './vendor/squoosh/copy-wasm.js';
|
2022-09-22 19:50:47 +00:00
|
|
|
import { createPlugin } from './vite-plugin-astro-image.js';
|
2022-07-01 15:47:48 +00:00
|
|
|
|
2022-07-27 15:39:05 +00:00
|
|
|
export { getImage } from './lib/get-image.js';
|
|
|
|
export { getPicture } from './lib/get-picture.js';
|
2022-08-30 21:09:44 +00:00
|
|
|
|
|
|
|
const PKG_NAME = '@astrojs/image';
|
|
|
|
const ROUTE_PATTERN = '/_image';
|
2022-07-27 15:39:05 +00:00
|
|
|
|
2022-10-12 21:25:51 +00:00
|
|
|
interface BuildConfig {
|
|
|
|
client: URL;
|
|
|
|
server: URL;
|
|
|
|
}
|
|
|
|
|
2022-07-27 15:39:05 +00:00
|
|
|
interface ImageIntegration {
|
|
|
|
loader?: ImageService;
|
2022-09-22 19:48:14 +00:00
|
|
|
defaultLoader: SSRImageService;
|
2022-08-30 21:09:44 +00:00
|
|
|
addStaticImage?: (transform: TransformOptions) => string;
|
2022-07-27 15:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
declare global {
|
|
|
|
// eslint-disable-next-line no-var
|
2022-09-22 19:48:14 +00:00
|
|
|
var astroImage: ImageIntegration;
|
2022-07-27 15:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface IntegrationOptions {
|
|
|
|
/**
|
|
|
|
* Entry point for the @type {HostedImageService} or @type {LocalImageService} to be used.
|
|
|
|
*/
|
2022-09-29 21:20:48 +00:00
|
|
|
serviceEntryPoint?: '@astrojs/image/squoosh' | '@astrojs/image/sharp' | string;
|
2022-08-22 19:13:19 +00:00
|
|
|
logLevel?: LoggerLevel;
|
2022-09-29 21:20:48 +00:00
|
|
|
cacheDir?: false | string;
|
2022-07-27 15:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export default function integration(options: IntegrationOptions = {}): AstroIntegration {
|
|
|
|
const resolvedOptions = {
|
2022-09-22 19:48:14 +00:00
|
|
|
serviceEntryPoint: '@astrojs/image/squoosh',
|
2022-08-22 19:13:19 +00:00
|
|
|
logLevel: 'info' as LoggerLevel,
|
2022-09-29 21:20:48 +00:00
|
|
|
cacheDir: './node_modules/.astro/image',
|
2022-07-27 15:39:05 +00:00
|
|
|
...options,
|
|
|
|
};
|
|
|
|
|
2022-08-30 21:09:44 +00:00
|
|
|
let _config: AstroConfig;
|
2022-09-22 19:48:14 +00:00
|
|
|
let _buildConfig: BuildConfig;
|
2022-10-12 21:25:51 +00:00
|
|
|
let needsBuildConfig = false;
|
2022-08-30 21:09:44 +00:00
|
|
|
|
2022-07-27 15:39:05 +00:00
|
|
|
// 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)],
|
2022-09-22 19:48:14 +00:00
|
|
|
build: {
|
2022-09-22 19:50:47 +00:00
|
|
|
rollupOptions: {
|
|
|
|
external: ['sharp'],
|
|
|
|
},
|
|
|
|
},
|
2022-07-27 15:39:05 +00:00
|
|
|
ssr: {
|
|
|
|
noExternal: ['@astrojs/image', resolvedOptions.serviceEntryPoint],
|
2022-10-10 15:35:48 +00:00
|
|
|
// CJS dependencies used by `serviceEntryPoint`
|
|
|
|
external: ['http-cache-semantics', 'image-size', 'mime'],
|
2022-07-27 15:39:05 +00:00
|
|
|
},
|
2022-09-22 19:50:47 +00:00
|
|
|
assetsInclude: ['**/*.wasm'],
|
2022-07-27 15:39:05 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
name: PKG_NAME,
|
|
|
|
hooks: {
|
2022-09-22 19:48:14 +00:00
|
|
|
'astro:config:setup': async ({ command, config, updateConfig, injectRoute }) => {
|
2022-10-12 21:25:51 +00:00
|
|
|
needsBuildConfig = !config.build?.server;
|
2022-07-27 15:39:05 +00:00
|
|
|
_config = config;
|
|
|
|
updateConfig({ vite: getViteConfiguration() });
|
|
|
|
|
2022-08-30 21:09:44 +00:00
|
|
|
if (command === 'dev' || config.output === 'server') {
|
2022-07-27 15:39:05 +00:00
|
|
|
injectRoute({
|
|
|
|
pattern: ROUTE_PATTERN,
|
2022-08-30 21:09:44 +00:00
|
|
|
entryPoint: '@astrojs/image/endpoint',
|
2022-07-27 15:39:05 +00:00
|
|
|
});
|
|
|
|
}
|
2022-09-22 19:50:47 +00:00
|
|
|
|
|
|
|
const { default: defaultLoader } = await import(
|
|
|
|
resolvedOptions.serviceEntryPoint === '@astrojs/image/sharp'
|
|
|
|
? './loaders/sharp.js'
|
|
|
|
: './loaders/squoosh.js'
|
2022-09-22 19:48:14 +00:00
|
|
|
);
|
2022-09-22 19:50:47 +00:00
|
|
|
|
2022-09-22 19:48:14 +00:00
|
|
|
globalThis.astroImage = {
|
2022-09-22 19:50:47 +00:00
|
|
|
defaultLoader,
|
|
|
|
};
|
2022-09-22 19:48:14 +00:00
|
|
|
},
|
2022-10-12 21:25:51 +00:00
|
|
|
'astro:config:done': ({ config }) => {
|
|
|
|
_config = config;
|
|
|
|
_buildConfig = config.build;
|
|
|
|
},
|
|
|
|
'astro:build:start': ({ buildConfig }) => {
|
|
|
|
// Backwards compat
|
2022-10-12 21:27:56 +00:00
|
|
|
if (needsBuildConfig) {
|
2022-10-12 21:25:51 +00:00
|
|
|
_buildConfig = buildConfig;
|
|
|
|
}
|
2022-07-27 15:39:05 +00:00
|
|
|
},
|
2022-09-22 19:48:14 +00:00
|
|
|
'astro:build:setup': async () => {
|
2022-07-27 15:39:05 +00:00
|
|
|
// 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>();
|
|
|
|
|
2022-08-30 21:09:44 +00:00
|
|
|
const filename = propsToFilename(transform);
|
2022-07-27 15:39:05 +00:00
|
|
|
|
2022-08-30 21:09:44 +00:00
|
|
|
srcTranforms.set(filename, transform);
|
2022-07-27 15:39:05 +00:00
|
|
|
staticImages.set(transform.src, srcTranforms);
|
2022-08-30 21:09:44 +00:00
|
|
|
|
|
|
|
// 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`.
|
2022-09-08 18:41:17 +00:00
|
|
|
return prependForwardSlash(joinPaths(_config.base, 'assets', filename));
|
2022-07-27 15:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Helpers for building static images should only be available for SSG
|
2022-08-30 21:09:44 +00:00
|
|
|
if (_config.output === 'static') {
|
2022-09-22 19:48:14 +00:00
|
|
|
globalThis.astroImage.addStaticImage = addStaticImage;
|
2022-07-27 15:39:05 +00:00
|
|
|
}
|
2022-08-30 21:12:45 +00:00
|
|
|
},
|
2022-09-22 19:48:14 +00:00
|
|
|
'astro:build:generated': async ({ dir }) => {
|
|
|
|
// for SSG builds, build all requested image transforms to dist
|
|
|
|
const loader = globalThis?.astroImage?.loader;
|
|
|
|
|
|
|
|
if (resolvedOptions.serviceEntryPoint === '@astrojs/image/squoosh') {
|
|
|
|
// For the Squoosh service, copy all wasm files to dist/chunks.
|
|
|
|
// Because the default loader is dynamically imported (above),
|
|
|
|
// Vite will bundle squoosh to dist/chunks and expect to find the wasm files there
|
|
|
|
await copyWasmFiles(new URL('./chunks', dir));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (loader && 'transform' in loader && staticImages.size > 0) {
|
2022-09-29 21:22:49 +00:00
|
|
|
const cacheDir = !!resolvedOptions.cacheDir
|
|
|
|
? new URL(resolvedOptions.cacheDir, _config.root)
|
|
|
|
: undefined;
|
2022-09-29 21:20:48 +00:00
|
|
|
|
2022-09-22 19:48:14 +00:00
|
|
|
await ssgBuild({
|
|
|
|
loader,
|
|
|
|
staticImages,
|
|
|
|
config: _config,
|
|
|
|
outDir: dir,
|
|
|
|
logLevel: resolvedOptions.logLevel,
|
2022-09-29 21:20:48 +00:00
|
|
|
cacheDir,
|
2022-09-22 19:48:14 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'astro:build:ssr': async () => {
|
|
|
|
if (resolvedOptions.serviceEntryPoint === '@astrojs/image/squoosh') {
|
|
|
|
await copyWasmFiles(_buildConfig.server);
|
|
|
|
}
|
2022-09-22 19:50:47 +00:00
|
|
|
},
|
2022-08-30 21:12:45 +00:00
|
|
|
},
|
|
|
|
};
|
2022-07-27 15:39:05 +00:00
|
|
|
}
|