mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
fix(nuxt): use starting index when transforming islands (#21795)
This commit is contained in:
parent
3550893227
commit
4a7134f9b4
@ -4,18 +4,23 @@ import { parseURL } from 'ufo'
|
|||||||
import { createUnplugin } from 'unplugin'
|
import { createUnplugin } from 'unplugin'
|
||||||
import MagicString from 'magic-string'
|
import MagicString from 'magic-string'
|
||||||
import { ELEMENT_NODE, parse, walk } from 'ultrahtml'
|
import { ELEMENT_NODE, parse, walk } from 'ultrahtml'
|
||||||
|
import { isVue } from '../core/utils'
|
||||||
|
|
||||||
interface ServerOnlyComponentTransformPluginOptions {
|
interface ServerOnlyComponentTransformPluginOptions {
|
||||||
getComponents: () => Component[]
|
getComponents: () => Component[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCRIPT_RE = /<script[^>]*>/g
|
const SCRIPT_RE = /<script[^>]*>/g
|
||||||
|
const HAS_SLOT_RE = /<slot[ /]/
|
||||||
|
const TEMPLATE_RE = /<template>([\s\S]*)<\/template>/
|
||||||
|
|
||||||
export const islandsTransform = createUnplugin((options: ServerOnlyComponentTransformPluginOptions) => {
|
export const islandsTransform = createUnplugin((options: ServerOnlyComponentTransformPluginOptions) => {
|
||||||
return {
|
return {
|
||||||
name: 'server-only-component-transform',
|
name: 'server-only-component-transform',
|
||||||
enforce: 'pre',
|
enforce: 'pre',
|
||||||
transformInclude (id) {
|
transformInclude (id) {
|
||||||
|
if (!isVue(id)) { return false }
|
||||||
|
|
||||||
const components = options.getComponents()
|
const components = options.getComponents()
|
||||||
const islands = components.filter(component =>
|
const islands = components.filter(component =>
|
||||||
component.island || (component.mode === 'server' && !components.some(c => c.pascalName === component.pascalName && c.mode === 'client'))
|
component.island || (component.mode === 'server' && !components.some(c => c.pascalName === component.pascalName && c.mode === 'client'))
|
||||||
@ -24,9 +29,10 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran
|
|||||||
return islands.some(c => c.filePath === pathname)
|
return islands.some(c => c.filePath === pathname)
|
||||||
},
|
},
|
||||||
async transform (code, id) {
|
async transform (code, id) {
|
||||||
if (!code.includes('<slot ')) { return }
|
if (!HAS_SLOT_RE.test(code)) { return }
|
||||||
const template = code.match(/<template>([\s\S]*)<\/template>/)
|
const template = code.match(TEMPLATE_RE)
|
||||||
if (!template) { return }
|
if (!template) { return }
|
||||||
|
const startingIndex = template.index || 0
|
||||||
const s = new MagicString(code)
|
const s = new MagicString(code)
|
||||||
|
|
||||||
s.replace(SCRIPT_RE, (full) => {
|
s.replace(SCRIPT_RE, (full) => {
|
||||||
@ -51,25 +57,25 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran
|
|||||||
const bindings = getBindings(attributes, vfor)
|
const bindings = getBindings(attributes, vfor)
|
||||||
|
|
||||||
if (isSelfClosingTag) {
|
if (isSelfClosingTag) {
|
||||||
s.overwrite(loc[0].start, loc[0].end, `<div style="display: contents;" nuxt-ssr-slot-name="${slotName}" ${bindings}/>`)
|
s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, `<div style="display: contents;" nuxt-ssr-slot-name="${slotName}" ${bindings}/>`)
|
||||||
} else {
|
} else {
|
||||||
s.overwrite(loc[0].start, loc[0].end, `<div style="display: contents;" nuxt-ssr-slot-name="${slotName}" ${bindings}>`)
|
s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, `<div style="display: contents;" nuxt-ssr-slot-name="${slotName}" ${bindings}>`)
|
||||||
s.overwrite(loc[1].start, loc[1].end, '</div>')
|
s.overwrite(startingIndex + loc[1].start, startingIndex + loc[1].end, '</div>')
|
||||||
|
|
||||||
if (children.length > 1) {
|
if (children.length > 1) {
|
||||||
// need to wrap instead of applying v-for on each child
|
// need to wrap instead of applying v-for on each child
|
||||||
const wrapperTag = `<div ${vfor ? `v-for="${vfor[0]} in ${vfor[1]}"` : ''} style="display: contents;">`
|
const wrapperTag = `<div ${vfor ? `v-for="${vfor[0]} in ${vfor[1]}"` : ''} style="display: contents;">`
|
||||||
s.appendRight(loc[0].end, `<div nuxt-slot-fallback-start="${slotName}"/>${wrapperTag}`)
|
s.appendRight(startingIndex + loc[0].end, `<div nuxt-slot-fallback-start="${slotName}"/>${wrapperTag}`)
|
||||||
s.appendLeft(loc[1].start, '</div><div nuxt-slot-fallback-end/>')
|
s.appendLeft(startingIndex + loc[1].start, '</div><div nuxt-slot-fallback-end/>')
|
||||||
} else if (children.length === 1) {
|
} else if (children.length === 1) {
|
||||||
if (vfor && children[0].type === ELEMENT_NODE) {
|
if (vfor && children[0].type === ELEMENT_NODE) {
|
||||||
const { loc, name, attributes, isSelfClosingTag } = children[0]
|
const { loc, name, attributes, isSelfClosingTag } = children[0]
|
||||||
const attrs = Object.entries(attributes).map(([attr, val]) => `${attr}="${val}"`).join(' ')
|
const attrs = Object.entries(attributes).map(([attr, val]) => `${attr}="${val}"`).join(' ')
|
||||||
s.overwrite(loc[0].start, loc[0].end, `<${name} v-for="${vfor[0]} in ${vfor[1]}" ${attrs} ${isSelfClosingTag ? '/' : ''}>`)
|
s.overwrite(startingIndex + loc[0].start, startingIndex + loc[0].end, `<${name} v-for="${vfor[0]} in ${vfor[1]}" ${attrs} ${isSelfClosingTag ? '/' : ''}>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.appendRight(loc[0].end, `<div nuxt-slot-fallback-start="${slotName}"/>`)
|
s.appendRight(startingIndex + loc[0].end, `<div nuxt-slot-fallback-start="${slotName}"/>`)
|
||||||
s.appendLeft(loc[1].start, '<div nuxt-slot-fallback-end/>')
|
s.appendLeft(startingIndex + loc[1].start, '<div nuxt-slot-fallback-end/>')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
server-only component
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { appendResponseHeader } from 'h3'
|
import { appendResponseHeader } from 'h3'
|
||||||
|
|
||||||
appendResponseHeader(useRequestEvent(), 'x-nitro-prerender', '/some/url/from/server-only/component')
|
appendResponseHeader(useRequestEvent(), 'x-nitro-prerender', '/some/url/from/server-only/component')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
server-only component
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--server-only: 'server-only';
|
--server-only: 'server-only';
|
||||||
|
Loading…
Reference in New Issue
Block a user