Skip to content

Commit 38d3301

Browse files
committed
fix(vite): prefix public asset virtuals with null byte
(cherry picked from commit ec3888f)
1 parent dea31b1 commit 38d3301

2 files changed

Lines changed: 49 additions & 2 deletions

File tree

packages/vite/src/plugins/public-dirs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import MagicString from 'magic-string'
66
import { isCSSRequest } from 'vite'
77
import type { Plugin } from 'vite'
88

9-
const PREFIX = 'virtual:public?'
10-
const PREFIX_RE = /^virtual:public\?/
9+
const PREFIX = '\0virtual:public?'
10+
const PREFIX_RE = /^\0virtual:public\?/
1111
const CSS_URL_RE = /url\((\/[^)]+)\)/g
1212
const CSS_URL_SINGLE_RE = /url\(\/[^)]+\)/
1313
const RENDER_CHUNK_RE = /(?<= = )['"`]/
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { mkdirSync, rmSync, writeFileSync } from 'node:fs'
2+
import { tmpdir } from 'node:os'
3+
import { join } from 'node:path'
4+
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
5+
6+
const publicDir = join(tmpdir(), `nuxt-public-dirs-test-${Date.now()}`)
7+
8+
vi.mock('@nuxt/kit', () => ({
9+
useNitro: () => ({
10+
options: {
11+
publicAssets: [{ baseURL: '/', dir: publicDir }],
12+
},
13+
}),
14+
}))
15+
16+
const { PublicDirsPlugin } = await import('../src/plugins/public-dirs')
17+
18+
beforeAll(() => {
19+
mkdirSync(publicDir, { recursive: true })
20+
writeFileSync(join(publicDir, 'logo.svg'), '<svg/>')
21+
})
22+
23+
afterAll(() => {
24+
rmSync(publicDir, { recursive: true, force: true })
25+
})
26+
27+
describe('PublicDirsPlugin', () => {
28+
const [, plugin] = PublicDirsPlugin({})
29+
const resolveId = typeof plugin.resolveId === 'function' ? plugin.resolveId : plugin.resolveId!.handler
30+
const load = typeof plugin.load === 'function' ? plugin.load : plugin.load!.handler
31+
32+
it('resolves public asset ids with a `\\0` prefix so Vite skips its fs deny check', () => {
33+
// see https://github.com/nuxt/nuxt/issues/35107 — Vite 7.3.2+ denies transform of
34+
// ids containing `.svg`/`?url`/`?raw`/`?inline` unless they start with `\0`
35+
const resolved = (resolveId as any).call({}, '/logo.svg', undefined, {})
36+
expect(resolved).toBeTypeOf('string')
37+
expect(resolved.startsWith('\0')).toBe(true)
38+
expect(resolved).toBe('\0virtual:public?' + encodeURIComponent('/logo.svg'))
39+
})
40+
41+
it('loads the resolved virtual id back into a publicAssetsURL import', () => {
42+
const id = '\0virtual:public?' + encodeURIComponent('/logo.svg')
43+
const result = (load as any).call({}, id)
44+
expect(result).toContain('publicAssetsURL')
45+
expect(result).toContain(JSON.stringify('/logo.svg'))
46+
})
47+
})

0 commit comments

Comments
 (0)