wip: further optimize bindings
This commit is contained in:
@@ -61,8 +61,16 @@ export type HoistTransform = (
|
||||
parent: ParentNode
|
||||
) => void
|
||||
|
||||
export const enum BindingTypes {
|
||||
DATA = 'data',
|
||||
PROPS = 'props',
|
||||
SETUP = 'setup',
|
||||
CONST = 'const',
|
||||
OPTIONS = 'options'
|
||||
}
|
||||
|
||||
export interface BindingMetadata {
|
||||
[key: string]: 'data' | 'props' | 'setup' | 'options' | 'setup-raw'
|
||||
[key: string]: BindingTypes
|
||||
}
|
||||
|
||||
interface SharedTransformCodegenOptions {
|
||||
|
||||
@@ -207,11 +207,11 @@ export function getStaticType(
|
||||
case NodeTypes.TEXT_CALL:
|
||||
return getStaticType(node.content, resultCache)
|
||||
case NodeTypes.SIMPLE_EXPRESSION:
|
||||
return node.isConstant
|
||||
? node.isRuntimeConstant
|
||||
? StaticType.HAS_RUNTIME_CONSTANT
|
||||
: StaticType.FULL_STATIC
|
||||
: StaticType.NOT_STATIC
|
||||
return node.isRuntimeConstant
|
||||
? StaticType.HAS_RUNTIME_CONSTANT
|
||||
: node.isConstant
|
||||
? StaticType.FULL_STATIC
|
||||
: StaticType.NOT_STATIC
|
||||
case NodeTypes.COMPOUND_EXPRESSION:
|
||||
let returnType = StaticType.FULL_STATIC
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
|
||||
@@ -54,7 +54,7 @@ import {
|
||||
} from '../utils'
|
||||
import { buildSlots } from './vSlot'
|
||||
import { getStaticType } from './hoistStatic'
|
||||
import { BindingMetadata } from '../options'
|
||||
import { BindingTypes } from '../options'
|
||||
|
||||
// some directive transforms (e.g. v-model) may return a symbol for runtime
|
||||
// import, which should be used instead of a resolveDirective call.
|
||||
@@ -253,7 +253,7 @@ export function resolveComponentType(
|
||||
// 3. user component (from setup bindings)
|
||||
const bindings = context.bindingMetadata
|
||||
if (bindings !== EMPTY_OBJ) {
|
||||
const checkType = (type: BindingMetadata[string]) => {
|
||||
const checkType = (type: BindingTypes) => {
|
||||
let resolvedTag = tag
|
||||
if (
|
||||
bindings[resolvedTag] === type ||
|
||||
@@ -263,17 +263,17 @@ export function resolveComponentType(
|
||||
return resolvedTag
|
||||
}
|
||||
}
|
||||
const tagFromSetup = checkType('setup')
|
||||
const tagFromSetup = checkType(BindingTypes.SETUP)
|
||||
if (tagFromSetup) {
|
||||
return context.inline
|
||||
? // setup scope bindings may be refs so they need to be unrefed
|
||||
`${context.helperString(UNREF)}(${tagFromSetup})`
|
||||
: `$setup[${JSON.stringify(tagFromSetup)}]`
|
||||
}
|
||||
const tagFromImport = checkType('setup-raw')
|
||||
if (tagFromImport) {
|
||||
// raw setup bindings (e.g. imports) can be used as-is
|
||||
return tagFromImport
|
||||
const tagFromConst = checkType(BindingTypes.CONST)
|
||||
if (tagFromConst) {
|
||||
// constant setup bindings (e.g. imports) can be used as-is
|
||||
return tagFromConst
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import { validateBrowserExpression } from '../validateExpression'
|
||||
import { parse } from '@babel/parser'
|
||||
import { walk } from 'estree-walker'
|
||||
import { UNREF } from '../runtimeHelpers'
|
||||
import { BindingTypes } from '../options'
|
||||
|
||||
const isLiteralWhitelisted = /*#__PURE__*/ makeMap('true,false,null,this')
|
||||
|
||||
@@ -99,18 +100,26 @@ export function processExpression(
|
||||
}
|
||||
|
||||
const { inline, bindingMetadata } = context
|
||||
|
||||
// const bindings exposed from setup - we know they never change
|
||||
if (inline && bindingMetadata[node.content] === BindingTypes.CONST) {
|
||||
node.isRuntimeConstant = true
|
||||
return node
|
||||
}
|
||||
|
||||
const prefix = (raw: string) => {
|
||||
const type = hasOwn(bindingMetadata, raw) && bindingMetadata[raw]
|
||||
if (type === BindingTypes.CONST) {
|
||||
return raw
|
||||
}
|
||||
if (inline) {
|
||||
// setup inline mode
|
||||
if (type === 'setup') {
|
||||
if (type === BindingTypes.SETUP) {
|
||||
return `${context.helperString(UNREF)}(${raw})`
|
||||
} else if (type === 'props') {
|
||||
} else if (type === BindingTypes.PROPS) {
|
||||
// use __props which is generated by compileScript so in ts mode
|
||||
// it gets correct type
|
||||
return `__props.${raw}`
|
||||
} else if (type === 'setup-raw') {
|
||||
return raw
|
||||
}
|
||||
}
|
||||
// fallback to normal
|
||||
|
||||
@@ -70,7 +70,7 @@ export const transformOn: DirectiveTransform = (
|
||||
if (exp && !exp.content.trim()) {
|
||||
exp = undefined
|
||||
}
|
||||
let isCacheable: boolean = context.cacheHandlers && !exp
|
||||
let shouldCache: boolean = context.cacheHandlers && !exp
|
||||
if (exp) {
|
||||
const isMemberExp = isMemberExpression(exp.content)
|
||||
const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content))
|
||||
@@ -83,8 +83,11 @@ export const transformOn: DirectiveTransform = (
|
||||
isInlineStatement && context.removeIdentifiers(`$event`)
|
||||
// with scope analysis, the function is hoistable if it has no reference
|
||||
// to scope variables.
|
||||
isCacheable =
|
||||
shouldCache =
|
||||
context.cacheHandlers &&
|
||||
// runtime constants don't need to be cached
|
||||
// (this is analyzed by compileScript in SFC <script setup>)
|
||||
!(exp.type === NodeTypes.SIMPLE_EXPRESSION && exp.isRuntimeConstant) &&
|
||||
// #1541 bail if this is a member exp handler passed to a component -
|
||||
// we need to use the original function to preserve arity,
|
||||
// e.g. <transition> relies on checking cb.length to determine
|
||||
@@ -98,7 +101,7 @@ export const transformOn: DirectiveTransform = (
|
||||
// to a function, turn it into invocation (and wrap in an arrow function
|
||||
// below) so that it always accesses the latest value when called - thus
|
||||
// avoiding the need to be patched.
|
||||
if (isCacheable && isMemberExp) {
|
||||
if (shouldCache && isMemberExp) {
|
||||
if (exp.type === NodeTypes.SIMPLE_EXPRESSION) {
|
||||
exp.content += `(...args)`
|
||||
} else {
|
||||
@@ -116,7 +119,7 @@ export const transformOn: DirectiveTransform = (
|
||||
)
|
||||
}
|
||||
|
||||
if (isInlineStatement || (isCacheable && isMemberExp)) {
|
||||
if (isInlineStatement || (shouldCache && isMemberExp)) {
|
||||
// wrap inline statement in a function expression
|
||||
exp = createCompoundExpression([
|
||||
`${isInlineStatement ? `$event` : `(...args)`} => ${
|
||||
@@ -142,7 +145,7 @@ export const transformOn: DirectiveTransform = (
|
||||
ret = augmentor(ret)
|
||||
}
|
||||
|
||||
if (isCacheable) {
|
||||
if (shouldCache) {
|
||||
// cache handlers so that it's always the same handler being passed down.
|
||||
// this avoids unnecessary re-renders when users use inline handlers on
|
||||
// components.
|
||||
|
||||
Reference in New Issue
Block a user