Files
Webklar.com/node_modules/next/dist/esm/build/webpack/loaders/next-metadata-image-loader.js
Basilosaurusrex f027651f9b main repo
2025-11-24 18:09:40 +01:00

137 lines
6.0 KiB
JavaScript

/*
* 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