diff --git a/src/context.ts b/src/context.ts index 0949cc4..1194347 100644 --- a/src/context.ts +++ b/src/context.ts @@ -1,6 +1,11 @@ import type { Node } from '@babel/types' import { isMp } from '@uni-helper/uni-env' -import type { AttributeNode, DirectiveNode, ElementNode, SimpleExpressionNode } from '@vue/compiler-core' +import type { + AttributeNode, + DirectiveNode, + ElementNode, + SimpleExpressionNode, +} from '@vue/compiler-core' import { babelParse, walkAST } from 'ast-kit' import MagicString from 'magic-string' import { kebabCase } from 'scule' @@ -71,7 +76,9 @@ export class Context { // layout name is empty if (!pageLayoutName) return - pageLayout = this.layouts.find(l => l.name === (pageLayoutName as string)) + pageLayout = this.layouts.find( + l => l.name === (pageLayoutName as string), + ) // can not find layout if (!pageLayout) return @@ -100,18 +107,58 @@ export class Context { }) } + // 检查是否有 page-meta 组件 + let pageMetaNodes: ElementNode[] = [] + if (sfc.template?.ast) { + pageMetaNodes = sfc.template.ast.children.filter( + v => + v.type === 1 + && (kebabCase(v.tag) === 'page-meta' || v.tag === 'page-meta'), + ) as ElementNode[] + } + if (disabled) { // find dynamic layout - const uniLayoutNode = sfc.template?.ast.children.find(v => v.type === 1 && kebabCase(v.tag) === 'uni-layout') as ElementNode + const uniLayoutNode = sfc.template?.ast!.children.find( + v => v.type === 1 && kebabCase(v.tag) === 'uni-layout', + ) as ElementNode // not found if (!uniLayoutNode) return - ms.overwrite(uniLayoutNode.loc.start.offset, uniLayoutNode.loc.end.offset, this.generateDynamicLayout(uniLayoutNode)) + ms.overwrite( + uniLayoutNode.loc.start.offset, + uniLayoutNode.loc.end.offset, + this.generateDynamicLayout(uniLayoutNode), + ) } else { - if (sfc.template?.loc.start.offset && sfc.template?.loc.end.offset) - ms.overwrite(sfc.template?.loc.start.offset, sfc.template?.loc.end.offset, `\n${sfc.template.content}\n`) + if (sfc.template?.loc.start.offset && sfc.template?.loc.end.offset) { + // 提取 page-meta 组件内容 + const pageMetaContent = pageMetaNodes + .map(node => node.loc.source) + .join('\n') + + // 从原内容中移除 page-meta 组件 + let contentWithoutPageMeta = sfc.template.content + for (const node of pageMetaNodes) { + contentWithoutPageMeta = contentWithoutPageMeta.replace( + node.loc.source, + '', + ) + } + + // 在布局外部添加 page-meta + ms.overwrite( + sfc.template?.loc.start.offset, + sfc.template?.loc.end.offset, + `\n${pageMetaContent}${contentWithoutPageMeta}\n`, + ) + } } if (ms.hasChanged()) { @@ -155,42 +202,70 @@ export default { v => v.type === 6 && v.name === 'name' && v.value?.content, ) as AttributeNode const dynamicLayoutNameBind = node.props.find( - v => v.type === 7 && v.name === 'bind' && v.arg?.type === 4 && v.arg?.content === 'name' && v.exp?.type === 4 && v.exp.content, + v => + v.type === 7 + && v.name === 'bind' + && v.arg?.type === 4 + && v.arg?.content === 'name' + && v.exp?.type === 4 + && v.exp.content, ) as DirectiveNode const slotsSource = node.children.map(v => v.loc.source).join('\n') - const nodeProps = node.props.filter(prop => !(prop === dynamicLayoutNameBind || prop === staticLayoutNameBind)).map(v => v.loc.source) + const nodeProps = node.props + .filter( + prop => + !(prop === dynamicLayoutNameBind || prop === staticLayoutNameBind), + ) + .map(v => v.loc.source) - if (!(staticLayoutNameBind || dynamicLayoutNameBind)) - console.warn('[vite-plugin-uni-layouts] Dynamic layout not found name bind') + if (!(staticLayoutNameBind || dynamicLayoutNameBind)) { + console.warn( + '[vite-plugin-uni-layouts] Dynamic layout not found name bind', + ) + } if (isMp) { const props: string[] = [...nodeProps] if (staticLayoutNameBind) { const layout = staticLayoutNameBind.value?.content - return `${slotsSource}` + return `${slotsSource}` } const bind = (dynamicLayoutNameBind.exp as SimpleExpressionNode).content const defaultSlot = node.children.filter((v) => { if (v.type === 1 && v.tagType === 3) { - const slot = v.props.find(v => v.type === 7 && v.name === 'slot' && v.arg?.type === 4) as any + const slot = v.props.find( + v => v.type === 7 && v.name === 'slot' && v.arg?.type === 4, + ) as any if (slot) return slot.arg.content === 'default' } return v }) const defaultSlotSource = defaultSlot.map(v => v.loc.source).join('\n') - const layouts = this.layouts.map((layout, index) => `${slotsSource}`) + const layouts = this.layouts.map( + (layout, index) => `${slotsSource}`, + ) layouts.push(``) return layouts.join('\n') } else { const props: string[] = [...nodeProps] - if (staticLayoutNameBind) - props.push(`is="layout-${staticLayoutNameBind.value?.content}-uni"`) - else - props.push(`:is="\`layout-\${${(dynamicLayoutNameBind.exp as SimpleExpressionNode).content}}-uni\`"`) + if (staticLayoutNameBind) { props.push(`is="layout-${staticLayoutNameBind.value?.content}-uni"`) } + else { + props.push( + `:is="\`layout-\${${ + (dynamicLayoutNameBind.exp as SimpleExpressionNode).content + }}-uni\`"`, + ) + } return `${slotsSource}` } }