Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nuxt-picture: allow parsing format as array #886

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
50c8e66
feat: :sparkles: Add logic to handle multiple formats
marcelxpfeifer Dec 17, 2022
8980005
feat: :memo: Add documentation
marcelxpfeifer Dec 17, 2022
4679830
feat: :rewind: This reverts some changes to work like the original code
marcelxpfeifer Dec 17, 2022
24df170
feat: :rewind: svg should only have a srcset
marcelxpfeifer Dec 17, 2022
cbe7367
feat: :sparkles: Use src as srcset if the image is an svg
marcelxpfeifer Dec 17, 2022
57e0b7a
docs: :memo: Update documentation
marcelxpfeifer Dec 23, 2022
0935131
feat: :twisted_rightwards_arrows: Merge newest changes
marcelxpfeifer Feb 11, 2023
9f00f9a
fix: :bug: Use all sources
marcelxpfeifer Feb 11, 2023
c5c8e3a
style: :bug: Use eslint config
marcelxpfeifer Feb 11, 2023
ee3054d
Merge branch 'nuxt:main' into main
marcelxpfeifer Mar 19, 2023
510b786
feat: :twisted_rightwards_arrows: Merge rc1
marcelxpfeifer Jun 6, 2023
0ffbdcb
Merge branch 'develop'
marcelxpfeifer Jun 6, 2023
92731e8
refactor: :rotating_light: Linting
marcelxpfeifer Jun 6, 2023
047d257
refactor: Import order and remove type
marcelxpfeifer Jun 7, 2023
0ad807f
refactor: Import order
marcelxpfeifer Jun 7, 2023
453109f
refactor: import order
marcelxpfeifer Jun 7, 2023
906c4da
refactor: Linebreaks
marcelxpfeifer Jun 7, 2023
96c4103
fix: :bug: svg setup
marcelxpfeifer Jun 7, 2023
c627d18
refactor: formatting
marcelxpfeifer Jun 7, 2023
9e5d845
feat: Imporve svg handling
marcelxpfeifer Jun 7, 2023
36b2ecb
fix: Linitng
marcelxpfeifer Jun 7, 2023
f1c45ad
Merge branch 'main' into main
marcelxpfeifer Jun 7, 2023
026c567
test: Add tests for multiple formats
marcelxpfeifer Jun 7, 2023
6c965d8
fix:
marcelxpfeifer Jun 7, 2023
b8974d5
fix: remove invalid format
marcelxpfeifer Jun 7, 2023
43702c5
Update docs/content/3.components/2.nuxt-picture.md
marcelxpfeifer Jun 7, 2023
d83f3ed
fix: preload most desired image
marcelxpfeifer Jun 7, 2023
a6cd5a1
Merge remote-tracking branch 'refs/remotes/origin/main'
marcelxpfeifer Jun 7, 2023
9002dfe
fix: remove src from source tag
marcelxpfeifer Jun 7, 2023
5aee165
Merge branch 'main' into main
marcelxpfeifer Jun 7, 2023
765388b
test:
marcelxpfeifer Jun 7, 2023
19b0c87
style: liniting error
marcelxpfeifer Jun 7, 2023
f032658
style: linting
marcelxpfeifer Jun 7, 2023
714f3a2
style: linting
marcelxpfeifer Jun 7, 2023
d40af57
Merge remote-tracking branch 'upstream/main' into develop
marcelxpfeifer Jun 21, 2023
cdcd1a7
merge
marcelxpfeifer Jun 21, 2023
bf1fae6
feat: :sparkles: Allow generation of images via array
marcelxpfeifer Jun 21, 2023
7823b72
feat: :sparkles: Update docs
marcelxpfeifer Jun 21, 2023
5a11310
Merge pull request #3 from wolvessoftware/develop
marcelxpfeifer Jun 21, 2023
16dffb3
feat: :label: Improve types
marcelxpfeifer Jun 22, 2023
9c7b53f
Merge remote-tracking branch 'upstream/main' into develop
marcelxpfeifer Sep 12, 2023
21a2ae9
feat: :sparkles: Update docs
marcelxpfeifer Sep 12, 2023
ffdeb75
feat: :sparkles: Update tag
marcelxpfeifer Sep 12, 2023
3ac2ab1
fix: :bug: Failing test
marcelxpfeifer Sep 12, 2023
4f36dd4
fix: :lipstick: Linting
marcelxpfeifer Sep 12, 2023
93dbf92
Merge pull request #4 from wolvessoftware/develop
marcelxpfeifer Sep 12, 2023
ed2e268
Merge branch 'main' into main
marcelxpfeifer Sep 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 25 additions & 4 deletions docs/content/2.usage/2.nuxt-picture.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: '<NuxtPicture>'
title: "<NuxtPicture>"
description: Discover how to use and configure the Nuxt Picture component.
---

Expand All @@ -17,13 +17,34 @@ See props supported by[`<NuxtImg>`](/usage/nuxt-img#props)</a>

### `format`

Format on pictures can be used to serve images in multiple formats. A legacy format will be generated automatically. So in the example below avif, webp and png would be generated. They will be added in the same order they are added to the format attribute.
You can use this option to configure the format of your images. The available formats are webp, avif, jpeg, jpg, png, and gif. The order of the formats is important, as the first format that is supported by the browser will be used. You can pass multiple values like ['avif', 'webp'] or as a comma-separated string like 'avif,webp'.

A legacy format will be generated automatically. They will be added in the order of the formats array, the legacy format will be added last.

```html
<NuxtPicture format="avif,webp" src="/nuxt-icon.png" ... />
// generates avif, webp and png
<NuxtPicture
:format="['avif','webp']"
src="/nuxt-icon.png"
...
/>

// generates avif, webp and jepg
<NuxtPicture
format="avif,webp"
src="/nuxt-icon.jpg"
...
/>

// generates wepb and png
<NuxtPicture
format="webp"
src="/nuxt-icon.png"
...
/>
```

Available formats are `webp`, `avif`, `jpeg`, `jpg`, `png` and `gif`. If the format is not specified, it will respect the default image format.
If the format is not specified, it will respect the default image format.

### `legacyFormat`

Expand Down
2 changes: 1 addition & 1 deletion playground/pages/picture.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div>
<nuxt-picture src="/images/colors.jpg" format="avif,webp" width="500" height="500" @load="isLoaded = true" />
<nuxt-picture src="/images/colors.jpg" :format="['avif','webp']" width="500" height="500" @load="isLoaded = true" />
<p>Received onLoad event: {{ isLoaded }}</p>
</div>
</template>
Expand Down
53 changes: 53 additions & 0 deletions src/runtime/components/_base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ export const baseImageProps = {
}
}

export const basePictureProps = {
...baseImageProps,
format: { type: [String, Array] as unknown as () => string | string[], default: undefined }
}

export interface BaseImageAttrs {
width?: number
height?: number
Expand All @@ -66,6 +71,10 @@ export interface BaseImageModifiers {
[key: string]: any
}

export interface BasePictureModifiers extends Omit<BaseImageModifiers, 'format'> {
format?: string | string[];
}

export const useBaseImage = (props: ExtractPropTypes<typeof baseImageProps>) => {
const options = computed(() => {
return {
Expand Down Expand Up @@ -109,3 +118,47 @@ export const useBaseImage = (props: ExtractPropTypes<typeof baseImageProps>) =>
modifiers
}
}

export const useBasePicture = (props: ExtractPropTypes<typeof basePictureProps>) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For simplicity and reduced bundle size, do you think we can avoid splitting out useBasePicture and instead override the props directly in nuxt-img?

const options = computed(() => {
return {
provider: props.provider,
preset: props.preset
}
})

const attrs = computed<BaseImageAttrs>(() => {
return <BaseImageAttrs> {
width: parseSize(props.width),
height: parseSize(props.height),
alt: props.alt,
referrerpolicy: props.referrerpolicy,
usemap: props.usemap,
longdesc: props.longdesc,
ismap: props.ismap,
crossorigin: props.crossorigin === true ? 'anonymous' : props.crossorigin || undefined,
loading: props.loading,
decoding: props.decoding
}
})

const $img = useImage()

const modifiers = computed<BasePictureModifiers>(() => {
return <BasePictureModifiers> {
...props.modifiers,
width: parseSize(props.width),
height: parseSize(props.height),
format: props.format,
quality: props.quality || $img.options.quality,
background: props.background,
fit: props.fit
}
})

return {
options,
attrs,
modifiers
}
}
8 changes: 4 additions & 4 deletions src/runtime/components/nuxt-picture.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { h, defineComponent, ref, computed, onMounted } from 'vue'
import { prerenderStaticImages } from '../utils/prerender'
import { useBaseImage, baseImageProps } from './_base'
import { baseImageProps, useBasePicture } from './_base'
import { useImage, useHead, useNuxtApp } from '#imports'
import { getFileExtension } from '#image'

export const pictureProps = {
...baseImageProps,
format: { type: [String, Array<string>], default: undefined },
legacyFormat: { type: String, default: null },
imgAttrs: { type: Object, default: null }
}
Expand All @@ -16,7 +17,7 @@ export default defineComponent({
emits: ['load'],
setup: (props, ctx) => {
const $img = useImage()
const _base = useBaseImage(props)
const _base = useBasePicture(props)

const originalFormat = computed(() => getFileExtension(props.src))
const isTransparent = computed(() => ['png', 'webp', 'gif', 'svg'].includes(originalFormat.value))
Expand All @@ -28,7 +29,7 @@ export default defineComponent({

type Source = { srcset?: string, src?: string, type?: string, sizes?: string }
const sources = computed<Source[]>(() => {
const formats = props.format?.split(',') || (originalFormat.value === 'svg' ? ['svg'] : ($img.options.format?.length ? [...$img.options.format] : ['webp']))
const formats = (Array.isArray(props.format) ? props.format : props.format?.split(',') || (originalFormat.value === 'svg' ? ['svg'] : ($img.options.format?.length ? [...$img.options.format] : ['webp']))) as string[]
if (formats[0] === 'svg') {
return [<Source>{ src: props.src }]
}
Expand All @@ -44,7 +45,6 @@ export default defineComponent({
const { srcset, sizes, src } = $img.getSizes(props.src!, {
..._base.options.value,
sizes: props.sizes || $img.options.screens,
densities: props.densities,
modifiers: { ..._base.modifiers.value, format }
})

Expand Down
18 changes: 18 additions & 0 deletions test/unit/picture.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ describe('Renders simple image', () => {
}
})
expect(img.find('source[type="image/avif"]').exists()).toBe(true)
expect(img.findAll('source').length).toBe(1)
expect(img.find('img').exists()).toBe(true)
})

Expand All @@ -92,6 +93,7 @@ describe('Renders simple image', () => {
})
expect(img.find('source[type="image/avif"]').exists()).toBe(true)
expect(img.find('source[type="image/webp"]').exists()).toBe(true)
expect(img.findAll('source').length).toBe(2)
expect(img.find('img').exists()).toBe(true)
})

Expand All @@ -106,6 +108,22 @@ describe('Renders simple image', () => {
})
expect(img.find('source[type="image/avif"]').exists()).toBe(true)
expect(img.find('source[type="image/gif"]').exists()).toBe(true)
expect(img.findAll('source').length).toBe(2)
expect(img.find('img').exists()).toBe(true)
})

it('checks that multiple formats can also be parsed as array', () => {
const img = mount(NuxtPicture, {
propsData: {
width: 200,
height: 200,
format: ['avif', 'webp'],
src
}
})
expect(img.find('source[type="image/avif"]').exists()).toBe(true)
expect(img.find('source[type="image/webp"]').exists()).toBe(true)
expect(img.findAll('source').length).toBe(2)
expect(img.find('img').exists()).toBe(true)
})

Expand Down