/* * This loader is responsible for extracting the metadata image info for rendering in html */ import fs from "fs/promises"; import path from "path"; import loaderUtils from "next/dist/compiled/loader-utils3"; import { getImageSize } from "../../../server/image-optimizer"; import { imageExtMimeTypeMap } from "../../../lib/mime-type"; import { fileExists } from "../../../lib/file-exists"; import { WEBPACK_RESOURCE_QUERIES } from "../../../lib/constants"; import { normalizePathSep } from "../../../shared/lib/page-path/normalize-path-sep"; // [NOTE] For turbopack // refer loader_tree's write_static|dynamic_metadata for corresponding features async function nextMetadataImageLoader(content) { const options = this.getOptions(); const { type, segment, pageExtensions, basePath } = options; const { resourcePath, rootContext: context } = this; const { name: fileNameBase, ext } = path.parse(resourcePath); const useNumericSizes = type === "twitter" || type === "openGraph"; let extension = ext.slice(1); if (extension === "jpg") { extension = "jpeg"; } const opts = { context, content }; // No hash query for favicon.ico const contentHash = type === "favicon" ? "" : loaderUtils.interpolateName(this, "[contenthash]", opts); const interpolatedName = loaderUtils.interpolateName(this, "[name].[ext]", opts); const isDynamicResource = pageExtensions.includes(extension); const pageSegment = isDynamicResource ? fileNameBase : interpolatedName; const hashQuery = contentHash ? "?" + contentHash : ""; const pathnamePrefix = normalizePathSep(path.join(basePath, segment)); if (isDynamicResource) { var _mod_dependencies; const mod = await new Promise((res, rej)=>{ this.loadModule(resourcePath, (err, _source, _sourceMap, module)=>{ if (err) { return rej(err); } res(module); }); }); const exportedFieldsExcludingDefault = ((_mod_dependencies = mod.dependencies) == null ? void 0 : _mod_dependencies.filter((dep)=>{ return [ "HarmonyExportImportedSpecifierDependency", "HarmonyExportSpecifierDependency" ].includes(dep.constructor.name) && "name" in dep && dep.name !== "default"; }).map((dep)=>{ return dep.name; })) || []; // re-export and spread as `exportedImageData` to avoid non-exported error return `\ import { ${exportedFieldsExcludingDefault.map((field)=>`${field} as _${field}`).join(",")} } from ${JSON.stringify(// This is an arbitrary resource query to ensure it's a new request, instead // of sharing the same module with next-metadata-route-loader. // Since here we only need export fields such as `size`, `alt` and // `generateImageMetadata`, avoid sharing the same module can make this entry // smaller. resourcePath + "?" + WEBPACK_RESOURCE_QUERIES.metadataImageMeta)} import { fillMetadataSegment } from 'next/dist/lib/metadata/get-metadata-route' const imageModule = { ${exportedFieldsExcludingDefault.map((field)=>`${field}: _${field}`).join(",")} } export default async function (props) { const { __metadata_id__: _, ...params } = props.params const imageUrl = fillMetadataSegment(${JSON.stringify(pathnamePrefix)}, params, ${JSON.stringify(pageSegment)}) const { generateImageMetadata } = imageModule function getImageMetadata(imageMetadata, idParam) { const data = { alt: imageMetadata.alt, type: imageMetadata.contentType || 'image/png', url: imageUrl + (idParam ? ('/' + idParam) : '') + ${JSON.stringify(hashQuery)}, } const { size } = imageMetadata if (size) { ${type === "twitter" || type === "openGraph" ? "data.width = size.width; data.height = size.height;" : 'data.sizes = size.width + "x" + size.height;'} } return data } if (generateImageMetadata) { const imageMetadataArray = await generateImageMetadata({ params }) return imageMetadataArray.map((imageMetadata, index) => { const idParam = (imageMetadata.id || index) + '' return getImageMetadata(imageMetadata, idParam) }) } else { return [getImageMetadata(imageModule, '')] } }`; } const imageSize = await getImageSize(content, extension).catch((err)=>err); if (imageSize instanceof Error) { const err = imageSize; err.name = "InvalidImageFormatError"; throw err; } const imageData = { ...extension in imageExtMimeTypeMap && { type: imageExtMimeTypeMap[extension] }, ...useNumericSizes && imageSize.width != null && imageSize.height != null ? imageSize : { sizes: // For SVGs, skip sizes and use "any" to let it scale automatically based on viewport, // For the images doesn't provide the size properly, use "any" as well. // If the size is presented, use the actual size for the image. extension !== "svg" && imageSize.width != null && imageSize.height != null ? `${imageSize.width}x${imageSize.height}` : "any" } }; if (type === "openGraph" || type === "twitter") { const altPath = path.join(path.dirname(resourcePath), fileNameBase + ".alt.txt"); if (await fileExists(altPath)) { imageData.alt = await fs.readFile(altPath, "utf8"); } } return `\ import { fillMetadataSegment } from 'next/dist/lib/metadata/get-metadata-route' export default (props) => { const imageData = ${JSON.stringify(imageData)} const imageUrl = fillMetadataSegment(${JSON.stringify(pathnamePrefix)}, props.params, ${JSON.stringify(pageSegment)}) return [{ ...imageData, url: imageUrl + ${JSON.stringify(type === "favicon" ? "" : hashQuery)}, }] }`; } export const raw = true; export default nextMetadataImageLoader; //# sourceMappingURL=next-metadata-image-loader.js.map