wip(ssr): basic components
This commit is contained in:
@@ -79,8 +79,8 @@ return function render() {
|
||||
const _component_Foo = _resolveComponent(\\"Foo\\")
|
||||
const _component_bar_baz = _resolveComponent(\\"bar-baz\\")
|
||||
const _component_barbaz = _resolveComponent(\\"barbaz\\")
|
||||
const _directive_my_dir = _resolveDirective(\\"my_dir\\")
|
||||
|
||||
const _directive_my_dir = _resolveDirective(\\"my_dir\\")
|
||||
|
||||
return null
|
||||
}
|
||||
}"
|
||||
|
||||
@@ -25,7 +25,7 @@ const withId = withScopeId(\\"test\\")
|
||||
export const render = withId(function render() {
|
||||
const _ctx = this
|
||||
const _component_Child = resolveComponent(\\"Child\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Child, null, {
|
||||
default: withId(() => [
|
||||
createVNode(\\"div\\")
|
||||
@@ -42,7 +42,7 @@ const withId = withScopeId(\\"test\\")
|
||||
export const render = withId(function render() {
|
||||
const _ctx = this
|
||||
const _component_Child = resolveComponent(\\"Child\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Child, null, createSlots({ _compiled: true }, [
|
||||
(_ctx.ok)
|
||||
? {
|
||||
@@ -71,7 +71,7 @@ const withId = withScopeId(\\"test\\")
|
||||
export const render = withId(function render() {
|
||||
const _ctx = this
|
||||
const _component_Child = resolveComponent(\\"Child\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Child, null, {
|
||||
foo: withId(({ msg }) => [
|
||||
createTextVNode(toDisplayString(msg), 1 /* TEXT */)
|
||||
|
||||
@@ -103,7 +103,7 @@ return function render() {
|
||||
const { createVNode: _createVNode, withDirectives: _withDirectives, resolveDirective: _resolveDirective, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
const _directive_foo = _resolveDirective(\\"foo\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_withDirectives(_createVNode(\\"div\\", _hoisted_1, null, 32 /* NEED_PATCH */), [
|
||||
[_directive_foo]
|
||||
@@ -141,7 +141,7 @@ return function render() {
|
||||
const { resolveComponent: _resolveComponent, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_createVNode(\\"div\\", _hoisted_1, [
|
||||
_createVNode(_component_Comp)
|
||||
@@ -249,7 +249,7 @@ return function render() {
|
||||
const { toDisplayString: _toDisplayString, resolveComponent: _resolveComponent, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, {
|
||||
default: ({ foo }) => [_toDisplayString(_ctx.foo)],
|
||||
_compiled: true
|
||||
@@ -284,7 +284,7 @@ return function render() {
|
||||
const { resolveComponent: _resolveComponent, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_createVNode(_component_Comp)
|
||||
]))
|
||||
|
||||
@@ -140,7 +140,7 @@ return function render() {
|
||||
const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode, withDirectives: _withDirectives, resolveDirective: _resolveDirective } = _Vue
|
||||
|
||||
const _directive_foo = _resolveDirective(\\"foo\\")
|
||||
|
||||
|
||||
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(list, (i) => {
|
||||
return (_openBlock(), _withDirectives(_createBlock(\\"div\\", null, null, 32 /* NEED_PATCH */), [
|
||||
[_directive_foo]
|
||||
|
||||
@@ -27,7 +27,7 @@ return function render() {
|
||||
const _cache = $cache
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_cache[1] || (
|
||||
_setBlockTracking(-1),
|
||||
|
||||
@@ -6,7 +6,7 @@ exports[`compiler: transform component slots dynamically named slots 1`] = `
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
const _component_Comp = resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Comp, null, {
|
||||
[_ctx.one]: ({ foo }) => [toDisplayString(foo), toDisplayString(_ctx.bar)],
|
||||
[_ctx.two]: ({ bar }) => [toDisplayString(_ctx.foo), toDisplayString(bar)],
|
||||
@@ -21,7 +21,7 @@ exports[`compiler: transform component slots implicit default slot 1`] = `
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
const _component_Comp = resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Comp, null, {
|
||||
default: () => [
|
||||
createVNode(\\"div\\")
|
||||
@@ -37,7 +37,7 @@ exports[`compiler: transform component slots named slot with v-for w/ prefixIden
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
const _component_Comp = resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Comp, null, createSlots({ _compiled: true }, [
|
||||
renderList(_ctx.list, (name) => {
|
||||
return {
|
||||
@@ -55,7 +55,7 @@ exports[`compiler: transform component slots named slot with v-if + prefixIdenti
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
const _component_Comp = resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Comp, null, createSlots({ _compiled: true }, [
|
||||
(_ctx.ok)
|
||||
? {
|
||||
@@ -75,7 +75,7 @@ return function render() {
|
||||
const { resolveComponent: _resolveComponent, createSlots: _createSlots, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, _createSlots({ _compiled: true }, [
|
||||
ok
|
||||
? {
|
||||
@@ -104,7 +104,7 @@ return function render() {
|
||||
const { resolveComponent: _resolveComponent, createSlots: _createSlots, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, _createSlots({ _compiled: true }, [
|
||||
ok
|
||||
? {
|
||||
@@ -123,7 +123,7 @@ exports[`compiler: transform component slots named slots 1`] = `
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
const _component_Comp = resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Comp, null, {
|
||||
one: ({ foo }) => [toDisplayString(foo), toDisplayString(_ctx.bar)],
|
||||
two: ({ bar }) => [toDisplayString(_ctx.foo), toDisplayString(bar)],
|
||||
@@ -140,7 +140,7 @@ return function render() {
|
||||
const { createVNode: _createVNode, resolveComponent: _resolveComponent, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, {
|
||||
one: () => [\\"foo\\"],
|
||||
default: () => [
|
||||
@@ -160,7 +160,7 @@ return function render() {
|
||||
const _ctx = this
|
||||
const _component_Inner = resolveComponent(\\"Inner\\")
|
||||
const _component_Comp = resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Comp, null, {
|
||||
default: ({ foo }) => [
|
||||
createVNode(_component_Inner, null, {
|
||||
@@ -183,7 +183,7 @@ exports[`compiler: transform component slots on-component default slot 1`] = `
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
const _component_Comp = resolveComponent(\\"Comp\\")
|
||||
|
||||
|
||||
return (openBlock(), createBlock(_component_Comp, null, {
|
||||
default: ({ foo }) => [toDisplayString(foo), toDisplayString(_ctx.bar)],
|
||||
_compiled: true
|
||||
|
||||
@@ -353,17 +353,21 @@ function genModulePreamble(
|
||||
function genAssets(
|
||||
assets: string[],
|
||||
type: 'component' | 'directive',
|
||||
context: CodegenContext
|
||||
{ helper, push, newline }: CodegenContext
|
||||
) {
|
||||
const resolver = context.helper(
|
||||
const resolver = helper(
|
||||
type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE
|
||||
)
|
||||
for (let i = 0; i < assets.length; i++) {
|
||||
const id = assets[i]
|
||||
context.push(
|
||||
push(
|
||||
`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`
|
||||
)
|
||||
context.newline()
|
||||
if (i < assets.length - 1) {
|
||||
newline()
|
||||
} else {
|
||||
push(`\n`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export { transformOn } from './transforms/vOn'
|
||||
export { transformBind } from './transforms/vBind'
|
||||
|
||||
// exported for compiler-ssr
|
||||
export { MERGE_PROPS } from './runtimeHelpers'
|
||||
export * from './runtimeHelpers'
|
||||
export { processIf } from './transforms/vIf'
|
||||
export { processFor, createForLoopParams } from './transforms/vFor'
|
||||
export {
|
||||
@@ -42,7 +42,7 @@ export {
|
||||
processExpression
|
||||
} from './transforms/transformExpression'
|
||||
export { trackVForSlotScopes, trackSlotScopes } from './transforms/vSlot'
|
||||
export { buildProps } from './transforms/transformElement'
|
||||
export { resolveComponentType, buildProps } from './transforms/transformElement'
|
||||
export { processSlotOutlet } from './transforms/transformSlotOutlet'
|
||||
|
||||
// utility, but need to rewrite typing to avoid dts relying on @vue/shared
|
||||
|
||||
@@ -465,7 +465,8 @@ function parseTag(
|
||||
} else if (
|
||||
isCoreComponent(tag) ||
|
||||
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
||||
/^[A-Z]/.test(tag)
|
||||
/^[A-Z]/.test(tag) ||
|
||||
tag === 'component'
|
||||
) {
|
||||
tagType = ElementTypes.COMPONENT
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
createSimpleExpression,
|
||||
createObjectExpression,
|
||||
Property,
|
||||
createSequenceExpression
|
||||
createSequenceExpression,
|
||||
ComponentNode
|
||||
} from '../ast'
|
||||
import { PatchFlags, PatchFlagNames, isSymbol } from '@vue/shared'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
@@ -35,7 +36,8 @@ import {
|
||||
getInnerRange,
|
||||
toValidAssetId,
|
||||
findProp,
|
||||
isCoreComponent
|
||||
isCoreComponent,
|
||||
isBindKey
|
||||
} from '../utils'
|
||||
import { buildSlots } from './vSlot'
|
||||
import { isStaticNode } from './hoistStatic'
|
||||
@@ -58,69 +60,30 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
// perform the work on exit, after all child expressions have been
|
||||
// processed and merged.
|
||||
return function postTransformElement() {
|
||||
const { tag, tagType, props } = node
|
||||
const builtInComponentSymbol =
|
||||
isCoreComponent(tag) || context.isBuiltInComponent(tag)
|
||||
const isComponent = tagType === ElementTypes.COMPONENT
|
||||
const { tag, props } = node
|
||||
const isComponent = node.tagType === ElementTypes.COMPONENT
|
||||
|
||||
// <svg> and <foreignObject> must be forced into blocks so that block
|
||||
// updates inside get proper isSVG flag at runtime. (#639, #643)
|
||||
// This is technically web-specific, but splitting the logic out of core
|
||||
// leads to too much unnecessary complexity.
|
||||
const shouldUseBlock =
|
||||
!isComponent && (tag === 'svg' || tag === 'foreignObject')
|
||||
|
||||
const nodeType = isComponent
|
||||
? resolveComponentType(node as ComponentNode, context)
|
||||
: `"${tag}"`
|
||||
|
||||
const args: CallExpression['arguments'] = [nodeType]
|
||||
|
||||
let hasProps = props.length > 0
|
||||
let patchFlag: number = 0
|
||||
let runtimeDirectives: DirectiveNode[] | undefined
|
||||
let dynamicPropNames: string[] | undefined
|
||||
let dynamicComponent: string | CallExpression | undefined
|
||||
let shouldUseBlock = false
|
||||
|
||||
// handle dynamic component
|
||||
const isProp = tag === 'component' && findProp(node, 'is')
|
||||
if (isProp) {
|
||||
// static <component is="foo" />
|
||||
if (isProp.type === NodeTypes.ATTRIBUTE) {
|
||||
const tag = isProp.value && isProp.value.content
|
||||
if (tag) {
|
||||
context.helper(RESOLVE_COMPONENT)
|
||||
context.components.add(tag)
|
||||
dynamicComponent = toValidAssetId(tag, `component`)
|
||||
}
|
||||
}
|
||||
// dynamic <component :is="asdf" />
|
||||
else if (isProp.exp) {
|
||||
dynamicComponent = createCallExpression(
|
||||
context.helper(RESOLVE_DYNAMIC_COMPONENT),
|
||||
// _ctx.$ exposes the owner instance of current render function
|
||||
[isProp.exp, context.prefixIdentifiers ? `_ctx.$` : `$`]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let nodeType
|
||||
if (dynamicComponent) {
|
||||
nodeType = dynamicComponent
|
||||
} else if (builtInComponentSymbol) {
|
||||
nodeType = context.helper(builtInComponentSymbol)
|
||||
} else if (isComponent) {
|
||||
// user component w/ resolve
|
||||
context.helper(RESOLVE_COMPONENT)
|
||||
context.components.add(tag)
|
||||
nodeType = toValidAssetId(tag, `component`)
|
||||
} else {
|
||||
// plain element
|
||||
nodeType = `"${tag}"`
|
||||
// <svg> and <foreignObject> must be forced into blocks so that block
|
||||
// updates inside get proper isSVG flag at runtime. (#639, #643)
|
||||
// This is technically web-specific, but splitting the logic out of core
|
||||
// leads to too much unnecessary complexity.
|
||||
shouldUseBlock = tag === 'svg' || tag === 'foreignObject'
|
||||
}
|
||||
|
||||
const args: CallExpression['arguments'] = [nodeType]
|
||||
// props
|
||||
if (hasProps) {
|
||||
const propsBuildResult = buildProps(
|
||||
node,
|
||||
context,
|
||||
// skip reserved "is" prop <component is>
|
||||
isProp ? node.props.filter(p => p !== isProp) : node.props
|
||||
)
|
||||
const propsBuildResult = buildProps(node, context)
|
||||
patchFlag = propsBuildResult.patchFlag
|
||||
dynamicPropNames = propsBuildResult.dynamicPropNames
|
||||
runtimeDirectives = propsBuildResult.directives
|
||||
@@ -130,6 +93,7 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
args.push(propsBuildResult.props)
|
||||
}
|
||||
}
|
||||
|
||||
// children
|
||||
const hasChildren = node.children.length > 0
|
||||
if (hasChildren) {
|
||||
@@ -140,11 +104,7 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
// Portal is not a real component has dedicated handling in the renderer
|
||||
// KeepAlive should not track its own deps so that it can be used inside
|
||||
// Transition
|
||||
if (
|
||||
isComponent &&
|
||||
builtInComponentSymbol !== PORTAL &&
|
||||
builtInComponentSymbol !== KEEP_ALIVE
|
||||
) {
|
||||
if (isComponent && nodeType !== PORTAL && nodeType !== KEEP_ALIVE) {
|
||||
const { slots, hasDynamicSlots } = buildSlots(node, context)
|
||||
args.push(slots)
|
||||
if (hasDynamicSlots) {
|
||||
@@ -171,6 +131,7 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
args.push(node.children)
|
||||
}
|
||||
}
|
||||
|
||||
// patchFlag & dynamicPropNames
|
||||
if (patchFlag !== 0) {
|
||||
if (!hasChildren) {
|
||||
@@ -219,13 +180,45 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
}
|
||||
}
|
||||
|
||||
function stringifyDynamicPropNames(props: string[]): string {
|
||||
let propsNamesString = `[`
|
||||
for (let i = 0, l = props.length; i < l; i++) {
|
||||
propsNamesString += JSON.stringify(props[i])
|
||||
if (i < l - 1) propsNamesString += ', '
|
||||
export function resolveComponentType(
|
||||
node: ComponentNode,
|
||||
context: TransformContext
|
||||
) {
|
||||
const { tag } = node
|
||||
|
||||
// 1. dynamic component
|
||||
const isProp = node.tag === 'component' && findProp(node, 'is')
|
||||
if (isProp) {
|
||||
// static <component is="foo" />
|
||||
if (isProp.type === NodeTypes.ATTRIBUTE) {
|
||||
const isType = isProp.value && isProp.value.content
|
||||
if (isType) {
|
||||
context.helper(RESOLVE_COMPONENT)
|
||||
context.components.add(isType)
|
||||
return toValidAssetId(isType, `component`)
|
||||
}
|
||||
}
|
||||
// dynamic <component :is="asdf" />
|
||||
else if (isProp.exp) {
|
||||
return createCallExpression(
|
||||
context.helper(RESOLVE_DYNAMIC_COMPONENT),
|
||||
// _ctx.$ exposes the owner instance of current render function
|
||||
[isProp.exp, context.prefixIdentifiers ? `_ctx.$` : `$`]
|
||||
)
|
||||
}
|
||||
}
|
||||
return propsNamesString + `]`
|
||||
|
||||
// 2. built-in components (Portal, Transition, KeepAlive, Suspense...)
|
||||
const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag)
|
||||
if (builtIn) {
|
||||
context.helper(builtIn)
|
||||
return builtIn
|
||||
}
|
||||
|
||||
// 3. user component (resolve)
|
||||
context.helper(RESOLVE_COMPONENT)
|
||||
context.components.add(tag)
|
||||
return toValidAssetId(tag, `component`)
|
||||
}
|
||||
|
||||
export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode
|
||||
@@ -241,7 +234,7 @@ export function buildProps(
|
||||
patchFlag: number
|
||||
dynamicPropNames: string[]
|
||||
} {
|
||||
const elementLoc = node.loc
|
||||
const { tag, loc: elementLoc } = node
|
||||
const isComponent = node.tagType === ElementTypes.COMPONENT
|
||||
let properties: ObjectExpression['properties'] = []
|
||||
const mergeArgs: PropsExpression[] = []
|
||||
@@ -288,6 +281,10 @@ export function buildProps(
|
||||
if (name === 'ref') {
|
||||
hasRef = true
|
||||
}
|
||||
// skip :is on <component>
|
||||
if (name === 'is' && tag === 'component') {
|
||||
continue
|
||||
}
|
||||
properties.push(
|
||||
createObjectProperty(
|
||||
createSimpleExpression(
|
||||
@@ -305,6 +302,8 @@ export function buildProps(
|
||||
} else {
|
||||
// directives
|
||||
const { name, arg, exp, loc } = prop
|
||||
const isBind = name === 'bind'
|
||||
const isOn = name === 'on'
|
||||
|
||||
// skip v-slot - it is handled by its dedicated transform.
|
||||
if (name === 'slot') {
|
||||
@@ -315,17 +314,16 @@ export function buildProps(
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// skip v-once - it is handled by its dedicated transform.
|
||||
if (name === 'once') {
|
||||
continue
|
||||
}
|
||||
|
||||
const isBind = name === 'bind'
|
||||
const isOn = name === 'on'
|
||||
|
||||
// skip :is on <component>
|
||||
if (isBind && tag === 'component' && isBindKey(arg, 'is')) {
|
||||
continue
|
||||
}
|
||||
// skip v-on in SSR compilation
|
||||
if (ssr && isOn) {
|
||||
if (isOn && ssr) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -518,3 +516,12 @@ function buildDirectiveArgs(
|
||||
}
|
||||
return createArrayExpression(dirArgs, dir.loc)
|
||||
}
|
||||
|
||||
function stringifyDynamicPropNames(props: string[]): string {
|
||||
let propsNamesString = `[`
|
||||
for (let i = 0, l = props.length; i < l; i++) {
|
||||
propsNamesString += JSON.stringify(props[i])
|
||||
if (i < l - 1) propsNamesString += ', '
|
||||
}
|
||||
return propsNamesString + `]`
|
||||
}
|
||||
|
||||
@@ -44,10 +44,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
||||
const eventName = arg
|
||||
? arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic
|
||||
? `onUpdate:${arg.content}`
|
||||
: createCompoundExpression([
|
||||
'"onUpdate:" + ',
|
||||
...(arg.type === NodeTypes.SIMPLE_EXPRESSION ? [arg] : arg.children)
|
||||
])
|
||||
: createCompoundExpression(['"onUpdate:" + ', arg])
|
||||
: `onUpdate:modelValue`
|
||||
|
||||
const props = [
|
||||
|
||||
@@ -192,19 +192,21 @@ export function findProp(
|
||||
if (p.name === name && p.value) {
|
||||
return p
|
||||
}
|
||||
} else if (
|
||||
p.name === 'bind' &&
|
||||
p.arg &&
|
||||
p.arg.type === NodeTypes.SIMPLE_EXPRESSION &&
|
||||
p.arg.isStatic &&
|
||||
p.arg.content === name &&
|
||||
p.exp
|
||||
) {
|
||||
} else if (p.name === 'bind' && p.exp && isBindKey(p.arg, name)) {
|
||||
return p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isBindKey(arg: DirectiveNode['arg'], name: string): boolean {
|
||||
return !!(
|
||||
arg &&
|
||||
arg.type === NodeTypes.SIMPLE_EXPRESSION &&
|
||||
arg.isStatic &&
|
||||
arg.content === name
|
||||
)
|
||||
}
|
||||
|
||||
export function hasDynamicKeyVBind(node: ElementNode): boolean {
|
||||
return node.props.some(
|
||||
p =>
|
||||
|
||||
Reference in New Issue
Block a user