UNPKG

astro

Version:

Astro is a modern site builder with web best practices, performance, and DX front-of-mind.

73 lines (72 loc) • 3.13 kB
import { fileURLToPath } from "node:url"; import { IMAGE_SERVICE_ENVIRONMENT_NAME, VIRTUAL_SERVICE_ID } from "../../assets/consts.js"; import { isLocalService } from "../../assets/services/service.js"; import { getImageServiceConfig } from "../../assets/utils/service-config.js"; import { getPrerenderOutputDirectory } from "../../prerender/utils.js"; import { AstroError, AstroErrorData } from "../errors/index.js"; import { viteBuildReturnToRolldownOutputs } from "./util.js"; const IMAGE_SERVICE_ENTRY_NAME = "image-service"; const IMAGE_SERVICE_ENTRY_ID = "virtual:astro:image-service-entry"; const RESOLVED_IMAGE_SERVICE_ENTRY_ID = "\0" + IMAGE_SERVICE_ENTRY_ID; function getImageServiceOutputDirectory(settings) { return new URL(`${IMAGE_SERVICE_ENTRY_NAME}/`, getPrerenderOutputDirectory(settings)); } export function getImageServiceEnvironmentOptions(settings) { return { consumer: "server", // Keeps linked packages external too, so `sharp` resolves from `astro`. resolve: { external: true }, build: { outDir: fileURLToPath(getImageServiceOutputDirectory(settings)), emitAssets: false, ssr: true, rolldownOptions: { // A string, so it replaces any shared `input` instead of being merged with it. input: IMAGE_SERVICE_ENTRY_ID, // Hashed, so a rebuild in the same process doesn't import a cached module. output: { entryFileNames: `${IMAGE_SERVICE_ENTRY_NAME}.[hash].mjs`, format: "esm" } } } }; } // An entry can't be external, so this one re-exports the service. export function pluginImageServiceEntry() { return { name: "@astro/plugin-image-service-entry", applyToEnvironment: (environment) => environment.name === IMAGE_SERVICE_ENVIRONMENT_NAME, resolveId: { filter: { id: new RegExp(`^${IMAGE_SERVICE_ENTRY_ID}$`) }, handler: () => RESOLVED_IMAGE_SERVICE_ENTRY_ID }, load: { filter: { id: new RegExp(`^${RESOLVED_IMAGE_SERVICE_ENTRY_ID}$`) }, handler: () => `export { default } from ${JSON.stringify(VIRTUAL_SERVICE_ID)};` } }; } export async function loadBuildImageService(builder, settings) { const { entrypoint } = getImageServiceConfig(settings.config.image.service, "build"); let service; try { const output = await builder.build(builder.environments[IMAGE_SERVICE_ENVIRONMENT_NAME]); const entry = viteBuildReturnToRolldownOutputs(output).flatMap((o) => o.output).find((chunk) => chunk.type === "chunk" && chunk.isEntry); if (!entry) throw new Error("The image service build produced no entry chunk."); const url = new URL(entry.fileName, getImageServiceOutputDirectory(settings)); service = (await import(url.href)).default; } catch (cause) { throw new AstroError({ ...AstroErrorData.InvalidImageService, message: `Could not load the image service \`${entrypoint}\` to generate images in Node.` }, { cause }); } if (!isLocalService(service)) { throw new AstroError({ ...AstroErrorData.InvalidImageService, message: `The image service \`${entrypoint}\` generates prerendered images during the build, but it is not a local service: it doesn't implement \`transform()\`.` }); } return service; }