Skip to content

Commit

Permalink
feat: support cloudinary fetch base url (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
harlan-zw committed Apr 19, 2021
1 parent 81f8dc7 commit 31bef1e
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 5 deletions.
47 changes: 46 additions & 1 deletion docs/content/en/4.providers/cloudinary.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,57 @@ To use this provider you just need to specify the base url of your project in cl
export default {
image: {
cloudinary: {
baseURL: 'https://res.cloudinary.com/nuxt/image/upload/'
baseURL: 'https://res.cloudinary.com/<your-cloud-name>/image/upload/'
}
}
}
```

## Remote Images

To handle remote image data, you can either use [fetch](https://cloudinary.com/documentation/fetch_remote_images#remote_image_fetch_url)
or [upload](https://cloudinary.com/documentation/fetch_remote_images#auto_upload_remote_resources). Consult the cloudinary [documentation](https://cloudinary.com/documentation/fetch_remote_images#comparing_fetch_to_auto_upload)
for the difference between the two.


### Fetch


```js{}[nuxt.config.js]
export default {
image: {
cloudinary: {
baseURL: 'https://res.cloudinary.com/<your-cloud-name>/image/fetch/'
}
}
}
```

```vue
<NuxtImg provider="cloudinary" src="https://upload.wikimedia.org/wikipedia/commons/a/ae/Olympic_flag.jpg" width="300" height="200" />
```

Note: You will need to configure your "Allowed fetch domains" to do the above.

### Upload

```js{}[nuxt.config.js]
export default {
image: {
cloudinary: {
baseURL: 'https://res.cloudinary.com/<your-cloud-name>/image/upload/<mapping-folder>'
}
}
}
```

```vue
<NuxtImg provider="cloudinary" src="/commons/a/ae/Olympic_flag.jpg" width="300" height="200" />
```

Note: You will need to configure your "Auto upload mapping" to do the above.


## Cloudinary `fit` values

Beside [the standard values for `fit` property](/components/nuxt-img#fit) of Nuxt image and Nuxt picture, Cloudinary offers the following for extra resizing experience:
Expand Down
27 changes: 23 additions & 4 deletions src/runtime/providers/cloudinary.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import type { ProviderGetImage } from 'src'
import { joinURL } from 'ufo'
import { joinURL, encodePath } from 'ufo'
import { createOperationsGenerator } from '~image'

const convertHextoRGBFormat = (value: string) => value.startsWith('#') ? value.replace('#', 'rgb_') : value
const removePathExtension = (value: string) => value.replace(/\.[^/.]+$/, '')

const operationsGenerator = createOperationsGenerator({
keyMap: {
Expand Down Expand Up @@ -77,11 +78,29 @@ const defaultModifiers = {

export const getImage: ProviderGetImage = (src, { modifiers = {}, baseURL = '/' } = {}) => {
const mergeModifiers = { ...defaultModifiers, ...modifiers }

const srcWithoutExtension = src.replace(/\.[^/.]+$/, '')
const operations = operationsGenerator(mergeModifiers as any)

let remoteFolderMapping = baseURL.match(/\/image\/upload\/(.*)/)
// Handle delivery remote media file URLs
// see: https://cloudinary.com/documentation/fetch_remote_images
// Note: Non-remote images will pass into this function if the baseURL is not using a sub directory
if (remoteFolderMapping?.length >= 1) {
// need to do some weird logic to get the remote folder after image/upload after the operations and before the src
const remoteFolder = remoteFolderMapping[1]
const baseURLWithoutRemoteFolder = baseURL.replace(remoteFolder, '')

return {
url: joinURL(baseURLWithoutRemoteFolder, operations, remoteFolder, src)
}
} else if (/\/image\/fetch\/?/.test(baseURL)) {
// need to encode the src as a path in case it contains special characters
src = encodePath(src)
} else {
// If the src is not a remote media file then we need to remove the extension (if it exists)
src = removePathExtension(src)
}

return {
url: joinURL(baseURL, operations, srcWithoutExtension)
url: joinURL(baseURL, operations, src)
}
}
47 changes: 47 additions & 0 deletions test/unit/providers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,53 @@ describe('Providers', () => {
}
})

test('cloudinary fetch', async () => {
const providerOptions = {
baseURL: 'https://res.cloudinary.com/demo/image/fetch/'
}
const providerDataExpectedkeys = ['runtime', 'runtimeOptions']
const providerData = cloudinary(providerOptions)

expect(Object.keys(providerData)).toEqual(expect.arrayContaining(providerDataExpectedkeys))

const runtime = (await import(providerData.runtime))

// see: https://cloudinary.com/documentation/fetch_remote_images#remote_image_fetch_url
const generated = runtime.getImage(
'https://upload.wikimedia.org/wikipedia/commons/1/13/Benedict_Cumberbatch_2011.png',
{ modifiers: {
width: 300,
height: 300,
}, ...providerData.runtimeOptions }
)
expect(generated).toMatchObject({
url: '/w_300,h_300/https://upload.wikimedia.org/wikipedia/commons/1/13/Benedict_Cumberbatch_2011.png'
})
})

test('cloudinary upload', async () => {
const providerOptions = {
baseURL: 'https://res.cloudinary.com/demo/image/upload/remote'
}
const providerDataExpectedkeys = ['runtime', 'runtimeOptions']
const providerData = cloudinary(providerOptions)

expect(Object.keys(providerData)).toEqual(expect.arrayContaining(providerDataExpectedkeys))

const runtime = (await import(providerData.runtime))

const generated = runtime.getImage(
'1/13/Benedict_Cumberbatch_2011.png',
{ modifiers: {
width: 300,
height: 300,
}, ...providerData.runtimeOptions }
)
expect(generated).toMatchObject({
url: '/w_300,h_300/remote/1/13/Benedict_Cumberbatch_2011.png'
})
})

test('twicpics', async () => {
const providerOptions = {
baseURL: ''
Expand Down

0 comments on commit 31bef1e

Please sign in to comment.