feat(compiler-core): more hoisting optimizations (#276)

This commit is contained in:
HcySunYang
2019-10-15 23:41:24 +08:00
committed by Evan You
parent 9a37c4b2c3
commit 68a3879b88
11 changed files with 373 additions and 15 deletions

View File

@@ -2,6 +2,7 @@ import {
RootNode,
NodeTypes,
TemplateChildNode,
SimpleExpressionNode,
ElementTypes,
ElementCodegenNode,
PlainElementNode,
@@ -11,7 +12,7 @@ import {
} from '../ast'
import { TransformContext } from '../transform'
import { APPLY_DIRECTIVES } from '../runtimeHelpers'
import { PatchFlags } from '@vue/shared'
import { PatchFlags, isString, isSymbol } from '@vue/shared'
import { isSlotOutlet, findProp } from '../utils'
function hasDynamicKey(node: ElementNode) {
@@ -107,7 +108,7 @@ function getPatchFlag(node: PlainElementNode): number | undefined {
}
function isStaticNode(
node: TemplateChildNode,
node: TemplateChildNode | SimpleExpressionNode,
resultCache: Map<TemplateChildNode, boolean>
): boolean {
switch (node.type) {
@@ -119,7 +120,7 @@ function isStaticNode(
return resultCache.get(node) as boolean
}
const flag = getPatchFlag(node)
if (!flag) {
if (!flag || flag === PatchFlags.TEXT) {
// element self is static. check its children.
for (let i = 0; i < node.children.length; i++) {
if (!isStaticNode(node.children[i], resultCache)) {
@@ -137,9 +138,17 @@ function isStaticNode(
return true
case NodeTypes.IF:
case NodeTypes.FOR:
case NodeTypes.INTERPOLATION:
case NodeTypes.COMPOUND_EXPRESSION:
return false
case NodeTypes.INTERPOLATION:
return isStaticNode(node.content, resultCache)
case NodeTypes.SIMPLE_EXPRESSION:
return node.isConstant
case NodeTypes.COMPOUND_EXPRESSION:
return node.children.every(child => {
return (
isString(child) || isSymbol(child) || isStaticNode(child, resultCache)
)
})
default:
if (__DEV__) {
const exhaustiveCheck: never = node

View File

@@ -190,7 +190,12 @@ export function buildProps(
const analyzePatchFlag = ({ key, value }: Property) => {
if (key.type === NodeTypes.SIMPLE_EXPRESSION && key.isStatic) {
if (value.type !== NodeTypes.SIMPLE_EXPRESSION || !value.isStatic) {
if (
value.type !== NodeTypes.SIMPLE_EXPRESSION ||
// E.g: <p :foo="1 + 2" />.
// Do not add prop `foo` to `dynamicPropNames`.
(!value.isStatic && !value.isConstant)
) {
const name = key.content
if (name === 'ref') {
hasRef = true

View File

@@ -61,6 +61,7 @@ export const transformExpression: NodeTransform = (node, context) => {
interface PrefixMeta {
prefix?: string
isConstant: boolean
start: number
end: number
scopeIds?: Set<string>
@@ -108,6 +109,7 @@ export function processExpression(
const ids: (Identifier & PrefixMeta)[] = []
const knownIds = Object.create(context.identifiers)
let isConstant = true
// walk the AST and look for identifiers that need to be prefixed with `_ctx.`.
walkJS(ast, {
enter(node: Node & PrefixMeta, parent) {
@@ -120,8 +122,15 @@ export function processExpression(
node.prefix = `${node.name}: `
}
node.name = `_ctx.${node.name}`
node.isConstant = false
isConstant = false
ids.push(node)
} else if (!isStaticPropertyKey(node, parent)) {
// This means this identifier is pointing to a scope variable (a v-for alias, or a v-slot prop)
// which is also dynamic and cannot be hoisted.
node.isConstant = !(
knownIds[node.name] && shouldPrefix(node, parent)
)
// also generate sub-expressions for other identifiers for better
// source map support. (except for property keys which are static)
ids.push(node)
@@ -190,11 +199,16 @@ export function processExpression(
}
const source = rawExp.slice(start, end)
children.push(
createSimpleExpression(id.name, false, {
source,
start: advancePositionWithClone(node.loc.start, source, start),
end: advancePositionWithClone(node.loc.start, source, end)
})
createSimpleExpression(
id.name,
false,
{
source,
start: advancePositionWithClone(node.loc.start, source, start),
end: advancePositionWithClone(node.loc.start, source, end)
},
id.isConstant /* isConstant */
)
)
if (i === ids.length - 1 && end < rawExp.length) {
children.push(rawExp.slice(end))
@@ -206,6 +220,7 @@ export function processExpression(
ret = createCompoundExpression(children, node.loc)
} else {
ret = node
ret.isConstant = isConstant
}
ret.identifiers = Object.keys(knownIds)
return ret