Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/content/2.usage/1.nuxt-img.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ Set `loading="lazy"` to defer loading of an image until it appears in the viewpo
<NuxtImg src="/nuxt-icon.png" loading="lazy" />
```

### `nonce`
### `nonce` [DEPRECATED]

This is a [native](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) global attribute that defines a cryptographic nonce (number used once) that can be used by Content Security Policy to determine whether or not a given fetch will be allowed to proceed for a given element.
Providing a nonce allows you to avoid using the CSP `unsafe-inline` directive, which would allowlist *all* inline script or styles.
Expand All @@ -399,6 +399,13 @@ Providing a nonce allows you to avoid using the CSP `unsafe-inline` directive, w
const nonce = useNonce()
</script>
```
::warning
This property was available in Nuxt Image v1, but is deprecated in Nuxt Image v2.

Having `nonce` be configurable introduces significant security risks as there is no guarantee the provided nonce is cryptographfically secure, generated according to the specification, and unique across the app.

It's best to let battle-tested security modules like [Nuxt Security](https://nuxt.com/modules/security) handle the nonce generation.
::

## Events

Expand Down
1 change: 0 additions & 1 deletion src/runtime/components/NuxtImg.vue
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ if (import.meta.server && props.preload) {
link: [{
rel: 'preload',
as: 'image',
nonce: props.nonce,
crossorigin: normalizedAttrs.value.crossorigin,
href: isResponsive ? sizes.value.src : src.value,
...(sizes.value.sizes && { imagesizes: sizes.value.sizes }),
Expand Down
3 changes: 1 addition & 2 deletions src/runtime/components/NuxtPicture.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const emit = defineEmits<{
}>()

const _attrs = useAttrs()
const imageAttrNames = new Set(['alt', 'referrerpolicy', 'usemap', 'longdesc', 'ismap', 'loading', 'crossorigin', 'decoding', 'nonce'])
const imageAttrNames = new Set(['alt', 'referrerpolicy', 'usemap', 'longdesc', 'ismap', 'loading', 'crossorigin', 'decoding'])
const attrs = computed(() => {
const attrs: Record<'img' | 'picture', Record<string, unknown>> = {
img: {
Expand Down Expand Up @@ -130,7 +130,6 @@ if (import.meta.server && props.preload) {
rel: 'preload',
as: 'image',
imagesrcset: firstSource.srcset,
nonce: props.nonce,
...(typeof props.preload !== 'boolean' && props.preload?.fetchPriority
? { fetchpriority: props.preload.fetchPriority }
: {}),
Expand Down
4 changes: 0 additions & 4 deletions src/runtime/utils/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ export interface BaseImageProps<Provider extends keyof ConfiguredImageProviders>
width?: string | number
height?: string | number
crossorigin?: 'anonymous' | 'use-credentials' | boolean

// csp
nonce?: string
}

export const useImageProps = <Provider extends keyof ConfiguredImageProviders>(props: BaseImageProps<Provider>) => {
Expand All @@ -45,7 +42,6 @@ export const useImageProps = <Provider extends keyof ConfiguredImageProviders>(p
width: parseSize(props.width),
height: parseSize(props.height),
crossorigin: props.crossorigin === true ? 'anonymous' : props.crossorigin || undefined,
nonce: props.nonce,
}))

const imageModifiers = computed(() => {
Expand Down
12 changes: 0 additions & 12 deletions test/nuxt/image.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,23 +144,11 @@ describe('Renders simple image', () => {
expect(img.html()).toMatchInlineSnapshot(`"<img width="300" height="400" data-nuxt-img="" srcset="/_ipx/s_300x400/image.png 1x, /_ipx/s_600x800/image.png 2x, /_ipx/s_900x1200/image.png 3x" src="/_ipx/s_300x400/image.png">"`)
})

it('with nonce', () => {
const img = mountImage({
src: '/image.png',
width: 300,
height: 400,
nonce: 'stub-nonce',
})
const domNonce = img.element.getAttribute('nonce')
expect(domNonce).toBe('stub-nonce')
})

it('can access imgEl underlying img HTMLImageElement', () => {
const img = mountImage({
src: '/image.png',
width: 300,
height: 400,
nonce: 'stub-nonce',
})
expect(img.getCurrentComponent().exposed?.imgEl).toBeDefined()
expect(img.getCurrentComponent().exposed?.imgEl.value).toBeInstanceOf(HTMLImageElement)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/bundle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe.skipIf(process.env.ECOSYSTEM_CI || isWindows)('nuxt image bundle size',
}),
])

expect(roundToKilobytes(withImage.totalBytes - withoutImage.totalBytes)).toMatchInlineSnapshot(`"12.6k"`)
expect(roundToKilobytes(withImage.totalBytes - withoutImage.totalBytes)).toMatchInlineSnapshot(`"12.5k"`)
})
})

Expand Down
Loading