nuxt / image

Plug-and-play image optimization for Nuxt applications.
https://image.nuxt.com
MIT License
1.32k stars 268 forks source link

Prismic provider doesn't play well with Unsplash urls from Prismic API #1172

Open GlennBergmans opened 8 months ago

GlennBergmans commented 8 months ago

With the new Slice Machine and Slice Simulator upgrade, Prismic returns images directly from Unsplash. Particularly in the slice simulator, it is only possible to use Unsplash urls. The prismic provider however always optimises the URL using the Prismic imgix domain, causing invalid urls for the Unsplash source urls from the API. Although in production Unsplash urls are not likely used, in development this gives problems in generating screenshots using the slice simulator. It is therefore not possible to use values returned by the Prismic API directly in the prismic provider.

There are a few solutions possible:

I'm not sure which philosophy best matches the Nuxt/Image approach.

GlennBergmans commented 8 months ago

For those here looking for a solution, this is a custom provider I wrote to solve this (temporarily). It's basically a merge of the prismic and unsplash providers. It's not very clean code, but it works.

// ~/utils/providers/PrismicUnsplash.ts

import { joinURL, parseQuery, parseURL, stringifyQuery, withQuery, withBase, getQuery } from 'ufo'
import type { ProviderGetImage } from '@nuxt/image'
import { createOperationsGenerator } from '#image'

const operationsGenerator = createOperationsGenerator()
const PRISMIC_IMGIX_BUCKET = 'https://images.prismic.io'
const unsplashCDN = 'https://images.unsplash.com/'

// This provider merges the `prismic` and `unsplash` providers, because the Prismic API returns either a
// Prismic Imgix or an Unsplash value. Unsplash values are used primarily in Slice Simulator.

// Prismic image bucket is left configurable in order to test on other environments
export const getImage: ProviderGetImage = (
  src,
  { modifiers = {}, baseURL = PRISMIC_IMGIX_BUCKET } = {}
) => {
  const operations = operationsGenerator(modifiers)
  const parsedURL = parseURL(src)

  // If it's an unsplash image
  if (parsedURL.host == 'images.unsplash.com') {
    return {
      url: withQuery(withBase(src, unsplashCDN), getQuery('?' + operations))
    }
  }

  return {
    url: joinURL(
      baseURL,
      parsedURL.pathname + '?' +
      // Remove duplicated keys, prioritizing override from developers
      stringifyQuery(Object.assign(parseQuery(parsedURL.search), parseQuery(operations)))
    )
  }
}

Then add this to the nuxt/image configuration in nuxt.config.ts:

image: {
  providers: {
    PrismicUnsplash: {
      provider: '~/utils/providers/PrismicUnsplash.ts', // Path to custom provider
    }
  },
  provider: 'PrismicUnsplash',
}