diff --git a/src/module.ts b/src/module.ts index a25d65b0b..910a4849e 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,6 +1,6 @@ import { resolve } from 'upath' import defu from 'defu' - +import { parseURL } from 'ufo' import type { Module } from '@nuxt/types' import { setupStaticGeneration } from './generate' import { resolveProviders, detectProvider } from './provider' @@ -34,6 +34,11 @@ const imageModule: Module = async function imageModule (moduleOpt const options: ModuleOptions = defu(moduleOptions, nuxt.options.image, defaults) + // Normalize domains to hostname + options.domains = options.domains + .map(domain => parseURL(domain, 'https://').host) + .filter(Boolean) as string[] + options.provider = detectProvider(options.provider, nuxt.options.target === 'static') options[options.provider] = options[options.provider] || {} diff --git a/src/provider.ts b/src/provider.ts index 171514caf..5f9f3d526 100644 --- a/src/provider.ts +++ b/src/provider.ts @@ -1,6 +1,5 @@ import { normalize, resolve, dirname } from 'upath' import { writeJson, mkdirp } from 'fs-extra' -import { parseURL } from 'ufo' import { hash } from './utils' import type { ModuleOptions, InputProvider, ImageModuleProvider, ProviderSetup } from './types' import { ipxSetup } from './ipx' @@ -31,7 +30,7 @@ export const providerSetup: Record = { const imagesConfig = resolve(nuxt.options.rootDir, '.vercel_build_output/config/images.json') await mkdirp(dirname(imagesConfig)) await writeJson(imagesConfig, { - domains: moduleOptions.domains.map(domain => parseURL(domain, 'https://').host), + domains: moduleOptions.domains, sizes: Array.from(new Set(Object.values(moduleOptions.screens || {}))) }) } diff --git a/src/runtime/image.ts b/src/runtime/image.ts index 505a78397..eca37fad6 100644 --- a/src/runtime/image.ts +++ b/src/runtime/image.ts @@ -1,4 +1,5 @@ import defu from 'defu' +import { hasProtocol, parseURL } from 'ufo' import type { ImageOptions, ImageSizesOptions, CreateImageOptions, ResolvedImage, MapToStatic, ImageCTX, $Img } from '../types/image' import { imageMeta } from './utils/meta' import { parseSize } from './utils' @@ -98,6 +99,17 @@ function resolveImage (ctx: ImageCTX, input: string, options: ImageOptions): Res const { provider, defaults } = getProvider(ctx, options.provider || ctx.options.provider) const preset = getPreset(ctx, options.preset) + // Externalize remote images if domain does not match with `domains` + if (provider.validateDomains && hasProtocol(input)) { + const inputHost = parseURL(input).host + // Domains are normalized to hostname in module + if (!ctx.options.domains.find(d => d === inputHost)) { + return { + url: input + } + } + } + const _options: ImageOptions = defu(options, preset, defaults) _options.modifiers = { ..._options.modifiers } const expectedFormat = _options.modifiers.format diff --git a/src/runtime/providers/ipx.ts b/src/runtime/providers/ipx.ts index ffe56880e..eecac935d 100644 --- a/src/runtime/providers/ipx.ts +++ b/src/runtime/providers/ipx.ts @@ -1,5 +1,5 @@ import { ProviderGetImage } from 'src' -import { joinURL, encodeQueryItem, encodePath, hasProtocol } from 'ufo' +import { joinURL, encodeQueryItem, encodePath } from 'ufo' import { createOperationsGenerator } from '~image' const operationsGenerator = createOperationsGenerator({ @@ -16,7 +16,7 @@ const operationsGenerator = createOperationsGenerator({ formatter: (key, val) => encodeQueryItem(key, val) }) -export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/_ipx' } = {}, { options: { domains = [] } }) => { +export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/_ipx' } = {}) => { if (modifiers.width && modifiers.height) { modifiers.resize = `${modifiers.width}_${modifiers.height}` delete modifiers.width @@ -25,15 +25,9 @@ export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/_i const params = operationsGenerator(modifiers) - if (hasProtocol(src)) { - if (!domains.find((d: string) => src.startsWith(d))) { - return { - url: src - } - } - } - return { url: joinURL(baseURL, encodePath(src) + (params ? '?' + params : '')) } } + +export const validateDomains = true diff --git a/src/runtime/providers/vercel.ts b/src/runtime/providers/vercel.ts index 4b91d043f..68e6b02a1 100644 --- a/src/runtime/providers/vercel.ts +++ b/src/runtime/providers/vercel.ts @@ -34,3 +34,5 @@ export const getImage: ProviderGetImage = (src, { modifiers, baseURL = '/_vercel }) } } + +export const validateDomains = true diff --git a/src/types/image.ts b/src/types/image.ts index 30669cf79..5faf341f7 100644 --- a/src/types/image.ts +++ b/src/types/image.ts @@ -23,6 +23,7 @@ export type ProviderGetImage = (src: string, options: ImageOptions, ctx: ImageCT export interface ImageProvider { defaults?: any getImage: ProviderGetImage + validateDomains?: Boolean } export interface CreateImageOptions { @@ -35,7 +36,7 @@ export interface CreateImageOptions { presets: { [name: string]: ImageOptions } provider: string screens?: Record, - domains?: string[] + domains: string[] } export interface ImageInfo {