fix(vite): handle emitted assets with relative urls and dynamic base (#2851)

This commit is contained in:
Daniel Roe 2022-01-24 12:57:24 +00:00 committed by GitHub
parent 0b0e56ae4f
commit b803fdb4f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 4 deletions

View File

@ -5,14 +5,14 @@ import vuePlugin from '@vitejs/plugin-vue'
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
import type { Connect } from 'vite'
import { joinURL, withoutLeadingSlash } from 'ufo'
import { joinURL } from 'ufo'
import { cacheDirPlugin } from './plugins/cache-dir'
import { analyzePlugin } from './plugins/analyze'
import { wpfs } from './utils/wpfs'
import type { ViteBuildContext, ViteOptions } from './vite'
import { writeManifest } from './manifest'
import { devStyleSSRPlugin } from './plugins/dev-ssr-css'
import { DynamicBasePlugin } from './plugins/dynamic-base'
import { DynamicBasePlugin, RelativeAssetPlugin } from './plugins/dynamic-base'
export async function buildClient (ctx: ViteBuildContext) {
const clientConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
@ -27,7 +27,6 @@ export async function buildClient (ctx: ViteBuildContext) {
}
},
build: {
assetsDir: ctx.nuxt.options.dev ? withoutLeadingSlash(ctx.nuxt.options.app.buildAssetsDir) : '.',
rollupOptions: {
output: {
chunkFileNames: ctx.nuxt.options.dev ? undefined : '[name]-[hash].mjs',
@ -42,6 +41,7 @@ export async function buildClient (ctx: ViteBuildContext) {
vuePlugin(ctx.config.vue),
viteJsxPlugin(),
DynamicBasePlugin.vite({ env: 'client', devAppConfig: ctx.nuxt.options.app }),
RelativeAssetPlugin(),
devStyleSSRPlugin({
rootDir: ctx.nuxt.options.rootDir,
buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir)

View File

@ -1,4 +1,5 @@
import { createUnplugin } from 'unplugin'
import type { Plugin } from 'vite'
interface DynamicBasePluginOptions {
env: 'dev' | 'server' | 'client'
@ -6,6 +7,31 @@ interface DynamicBasePluginOptions {
globalPublicPath?: string
}
const escapeRE = (str: string) => str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
export const RelativeAssetPlugin = function (): Plugin {
return {
name: 'nuxt:vite-relative-asset',
generateBundle (_, bundle) {
const generatedAssets = Object.entries(bundle).filter(([_, asset]) => asset.type === 'asset').map(([key]) => escapeRE(key))
const assetRE = new RegExp(`\\/__NUXT_BASE__\\/(${generatedAssets.join('|')})`, 'g')
for (const file in bundle) {
const asset = bundle[file]
if (asset.type === 'asset') {
const depth = file.split('/').length - 1
const assetBase = depth === 0 ? '.' : Array.from({ length: depth }).map(() => '..').join('/')
asset.source = asset.source.toString().replace(assetRE, r => r.replace(/\/__NUXT_BASE__/g, assetBase))
const publicBase = Array.from({ length: depth + 1 }).map(() => '..').join('/')
asset.source = asset.source.toString().replace(/\/__NUXT_BASE__/g, publicBase)
}
}
}
}
}
const VITE_ASSET_RE = /^export default ["'](__VITE_ASSET.*)["']$/
export const DynamicBasePlugin = createUnplugin(function (options: DynamicBasePluginOptions) {
return {
name: 'nuxt:dynamic-base-path',
@ -13,6 +39,7 @@ export const DynamicBasePlugin = createUnplugin(function (options: DynamicBasePl
if (id.startsWith('/__NUXT_BASE__')) {
return id.replace('/__NUXT_BASE__', '')
}
return null
},
enforce: 'post',
transform (code, id) {
@ -21,6 +48,12 @@ export const DynamicBasePlugin = createUnplugin(function (options: DynamicBasePl
`${options.globalPublicPath} = joinURL(NUXT_BASE, NUXT_CONFIG.app.buildAssetsDir);` + code
}
const assetId = code.match(VITE_ASSET_RE)
if (assetId) {
code = 'import { joinURL } from "ufo";' +
`export default joinURL(NUXT_BASE, NUXT_CONFIG.app.buildAssetsDir, "${assetId[1]}".replace("/__NUXT_BASE__", ""));`
}
if (code.includes('NUXT_BASE') && !code.includes('const NUXT_BASE =')) {
code = 'const NUXT_BASE = NUXT_CONFIG.app.cdnURL || NUXT_CONFIG.app.baseURL;' + code

View File

@ -74,7 +74,7 @@ export async function bundle (nuxt: Nuxt) {
},
clearScreen: false,
build: {
assetsDir: withoutLeadingSlash(nuxt.options.app.buildAssetsDir),
assetsDir: nuxt.options.dev ? withoutLeadingSlash(nuxt.options.app.buildAssetsDir) : '.',
emptyOutDir: false,
rollupOptions: {
input: resolve(nuxt.options.appDir, 'entry'),