mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
fix(vite): respect baseURL
for public assets in dev (#28482)
This commit is contained in:
parent
68e153c71a
commit
4d36810334
@ -1,77 +1,112 @@
|
|||||||
import { existsSync } from 'node:fs'
|
import { existsSync } from 'node:fs'
|
||||||
import { useNitro } from '@nuxt/kit'
|
import { useNitro } from '@nuxt/kit'
|
||||||
import { createUnplugin } from 'unplugin'
|
import { createUnplugin } from 'unplugin'
|
||||||
|
import type { UnpluginOptions } from 'unplugin'
|
||||||
import { withLeadingSlash, withTrailingSlash } from 'ufo'
|
import { withLeadingSlash, withTrailingSlash } from 'ufo'
|
||||||
import { dirname, relative } from 'pathe'
|
import { dirname, relative } from 'pathe'
|
||||||
import MagicString from 'magic-string'
|
import MagicString from 'magic-string'
|
||||||
|
import { isCSSRequest } from 'vite'
|
||||||
|
|
||||||
const PREFIX = 'virtual:public?'
|
const PREFIX = 'virtual:public?'
|
||||||
const CSS_URL_RE = /url\((\/[^)]+)\)/g
|
const CSS_URL_RE = /url\((\/[^)]+)\)/g
|
||||||
|
const CSS_URL_SINGLE_RE = /url\(\/[^)]+\)/
|
||||||
|
|
||||||
export const VitePublicDirsPlugin = createUnplugin((options: { sourcemap?: boolean }) => {
|
interface VitePublicDirsPluginOptions {
|
||||||
|
dev?: boolean
|
||||||
|
sourcemap?: boolean
|
||||||
|
baseURL?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VitePublicDirsPlugin = createUnplugin((options: VitePublicDirsPluginOptions) => {
|
||||||
const { resolveFromPublicAssets } = useResolveFromPublicAssets()
|
const { resolveFromPublicAssets } = useResolveFromPublicAssets()
|
||||||
|
|
||||||
return {
|
const devTransformPlugin: UnpluginOptions = {
|
||||||
name: 'nuxt:vite-public-dir-resolution',
|
name: 'nuxt:vite-public-dir-resolution-dev',
|
||||||
vite: {
|
vite: {
|
||||||
load: {
|
transform (code, id) {
|
||||||
enforce: 'pre',
|
if (!isCSSRequest(id) || !CSS_URL_SINGLE_RE.test(code)) { return }
|
||||||
handler (id) {
|
|
||||||
if (id.startsWith(PREFIX)) {
|
|
||||||
return `import { publicAssetsURL } from '#internal/nuxt/paths';export default publicAssetsURL(${JSON.stringify(decodeURIComponent(id.slice(PREFIX.length)))})`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
resolveId: {
|
|
||||||
enforce: 'post',
|
|
||||||
handler (id) {
|
|
||||||
if (id === '/__skip_vite' || id[0] !== '/' || id.startsWith('/@fs')) { return }
|
|
||||||
|
|
||||||
if (resolveFromPublicAssets(id)) {
|
|
||||||
return PREFIX + encodeURIComponent(id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
renderChunk (code, chunk) {
|
|
||||||
if (!chunk.facadeModuleId?.includes('?inline&used')) { return }
|
|
||||||
|
|
||||||
const s = new MagicString(code)
|
const s = new MagicString(code)
|
||||||
const q = code.match(/(?<= = )['"`]/)?.[0] || '"'
|
|
||||||
for (const [full, url] of code.matchAll(CSS_URL_RE)) {
|
for (const [full, url] of code.matchAll(CSS_URL_RE)) {
|
||||||
if (url && resolveFromPublicAssets(url)) {
|
if (url && resolveFromPublicAssets(url)) {
|
||||||
s.replace(full, `url(${q} + publicAssetsURL(${q}${url}${q}) + ${q})`)
|
s.replace(full, `url(${options.baseURL}${url})`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s.hasChanged()) {
|
if (s.hasChanged()) {
|
||||||
s.prepend(`import { publicAssetsURL } from '#internal/nuxt/paths';`)
|
|
||||||
return {
|
return {
|
||||||
code: s.toString(),
|
code: s.toString(),
|
||||||
map: options.sourcemap ? s.generateMap({ hires: true }) : undefined,
|
map: options.sourcemap ? s.generateMap({ hires: true }) : undefined,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
generateBundle (_outputOptions, bundle) {
|
|
||||||
for (const file in bundle) {
|
|
||||||
const chunk = bundle[file]!
|
|
||||||
if (!file.endsWith('.css') || chunk.type !== 'asset') { continue }
|
|
||||||
|
|
||||||
let css = chunk.source.toString()
|
|
||||||
let wasReplaced = false
|
|
||||||
for (const [full, url] of css.matchAll(CSS_URL_RE)) {
|
|
||||||
if (url && resolveFromPublicAssets(url)) {
|
|
||||||
const relativeURL = relative(withLeadingSlash(dirname(file)), url)
|
|
||||||
css = css.replace(full, `url(${relativeURL})`)
|
|
||||||
wasReplaced = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wasReplaced) {
|
|
||||||
chunk.source = css
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
...(options.dev && options.baseURL && options.baseURL !== '/' ? [devTransformPlugin] : []),
|
||||||
|
{
|
||||||
|
name: 'nuxt:vite-public-dir-resolution',
|
||||||
|
vite: {
|
||||||
|
load: {
|
||||||
|
enforce: 'pre',
|
||||||
|
handler (id) {
|
||||||
|
if (id.startsWith(PREFIX)) {
|
||||||
|
return `import { publicAssetsURL } from '#internal/nuxt/paths';export default publicAssetsURL(${JSON.stringify(decodeURIComponent(id.slice(PREFIX.length)))})`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resolveId: {
|
||||||
|
enforce: 'post',
|
||||||
|
handler (id) {
|
||||||
|
if (id === '/__skip_vite' || id[0] !== '/' || id.startsWith('/@fs')) { return }
|
||||||
|
|
||||||
|
if (resolveFromPublicAssets(id)) {
|
||||||
|
return PREFIX + encodeURIComponent(id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
renderChunk (code, chunk) {
|
||||||
|
if (!chunk.facadeModuleId?.includes('?inline&used')) { return }
|
||||||
|
|
||||||
|
const s = new MagicString(code)
|
||||||
|
const q = code.match(/(?<= = )['"`]/)?.[0] || '"'
|
||||||
|
for (const [full, url] of code.matchAll(CSS_URL_RE)) {
|
||||||
|
if (url && resolveFromPublicAssets(url)) {
|
||||||
|
s.replace(full, `url(${q} + publicAssetsURL(${q}${url}${q}) + ${q})`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.hasChanged()) {
|
||||||
|
s.prepend(`import { publicAssetsURL } from '#internal/nuxt/paths';`)
|
||||||
|
return {
|
||||||
|
code: s.toString(),
|
||||||
|
map: options.sourcemap ? s.generateMap({ hires: true }) : undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
generateBundle (_outputOptions, bundle) {
|
||||||
|
for (const file in bundle) {
|
||||||
|
const chunk = bundle[file]!
|
||||||
|
if (!file.endsWith('.css') || chunk.type !== 'asset') { continue }
|
||||||
|
|
||||||
|
let css = chunk.source.toString()
|
||||||
|
let wasReplaced = false
|
||||||
|
for (const [full, url] of css.matchAll(CSS_URL_RE)) {
|
||||||
|
if (url && resolveFromPublicAssets(url)) {
|
||||||
|
const relativeURL = relative(withLeadingSlash(dirname(file)), url)
|
||||||
|
css = css.replace(full, `url(${relativeURL})`)
|
||||||
|
wasReplaced = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wasReplaced) {
|
||||||
|
chunk.source = css
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
export function useResolveFromPublicAssets () {
|
export function useResolveFromPublicAssets () {
|
||||||
|
@ -99,7 +99,11 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
// add resolver for files in public assets directories
|
// add resolver for files in public assets directories
|
||||||
VitePublicDirsPlugin.vite({ sourcemap: !!nuxt.options.sourcemap.server }),
|
VitePublicDirsPlugin.vite({
|
||||||
|
dev: nuxt.options.dev,
|
||||||
|
sourcemap: !!nuxt.options.sourcemap.server,
|
||||||
|
baseURL: nuxt.options.app.baseURL,
|
||||||
|
}),
|
||||||
composableKeysPlugin.vite({
|
composableKeysPlugin.vite({
|
||||||
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
|
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
|
||||||
rootDir: nuxt.options.rootDir,
|
rootDir: nuxt.options.rootDir,
|
||||||
|
Loading…
Reference in New Issue
Block a user