提交 cf5f6746 编写于 作者: fxy060608's avatar fxy060608

feat(uvue): 支持 v-once

上级 04806327
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`compiler: v-once transform as root node 1`] = `
"_cache[0] ?? run((): VNode | null => {
setBlockTracking(-1)
_cache[0] = createElementVNode("view", utsMapOf({ id: foo }), null, 8 /* PROPS */, ["id"])
setBlockTracking(1)
return _cache[0] as VNode | null
})"
`;
exports[`compiler: v-once transform on component 1`] = `
"createElementVNode("view", null, [
_cache[0] ?? run((): VNode | null => {
setBlockTracking(-1)
_cache[0] = createVNode(_component_Comp, utsMapOf({ id: foo }), null, 8 /* PROPS */, ["id"])
setBlockTracking(1)
return _cache[0] as VNode | null
})
])"
`;
exports[`compiler: v-once transform on nested plain element 1`] = `
"createElementVNode("view", null, [
_cache[0] ?? run((): VNode | null => {
setBlockTracking(-1)
_cache[0] = createElementVNode("view", utsMapOf({ id: foo }), null, 8 /* PROPS */, ["id"])
setBlockTracking(1)
return _cache[0] as VNode | null
})
])"
`;
exports[`compiler: v-once transform on slot outlet 1`] = `
"createElementVNode("view", null, [
_cache[0] ?? run((): VNode | null => {
setBlockTracking(-1)
_cache[0] = renderSlot($slots, "default")
setBlockTracking(1)
return _cache[0] as VNode | null
})
])"
`;
import { NodeTypes, SET_BLOCK_TRACKING, baseParse } from '@vue/compiler-core'
import { getBaseTransformPreset } from '../../../src/plugins/android/uvue/compiler/index'
import { transform } from '../../../src/plugins/android/uvue/compiler/transform'
import { CompilerOptions } from '../../../src/plugins/android/uvue/compiler/options'
import { generate } from '../../../src/plugins/android/uvue/compiler/codegen'
import { RENDER_SLOT } from '../../../src/plugins/android/uvue/compiler/runtimeHelpers'
function transformWithOnce(template: string, options: CompilerOptions = {}) {
const ast = baseParse(template)
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset()
transform(ast, {
nodeTransforms,
directiveTransforms,
...options,
})
return ast
}
describe('compiler: v-once transform', () => {
test('as root node', () => {
const root = transformWithOnce(`<view :id="foo" v-once />`)
expect(root.cached).toBe(1)
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect(root.codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"view"`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
test('on nested plain element', () => {
const root = transformWithOnce(`<view><view :id="foo" v-once /></view>`)
expect(root.cached).toBe(1)
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"view"`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
test('on component', () => {
const root = transformWithOnce(`<view><Comp :id="foo" v-once /></view>`)
expect(root.cached).toBe(1)
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `_component_Comp`,
},
})
expect(generate(root).code).toMatchSnapshot()
})
test('on slot outlet', () => {
const root = transformWithOnce(`<view><slot v-once /></view>`)
expect(root.cached).toBe(1)
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 0,
value: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT,
},
})
expect(generate(root).code).toMatchSnapshot()
})
// v-once inside v-once should not be cached
test('inside v-once', () => {
const root = transformWithOnce(`<view v-once><view v-once/></view>`)
expect(root.cached).not.toBe(2)
expect(root.cached).toBe(1)
})
// cached nodes should be ignored by hoistStatic transform
// test('with hoistStatic: true', () => {
// const root = transformWithOnce(`<view><view v-once /></view>`, {
// hoistStatic: true,
// })
// expect(root.cached).toBe(1)
// expect(root.helpers).toContain(SET_BLOCK_TRACKING)
// expect(root.hoists.length).toBe(0)
// expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
// type: NodeTypes.JS_CACHE_EXPRESSION,
// index: 0,
// value: {
// type: NodeTypes.VNODE_CALL,
// tag: `"view"`,
// },
// })
// expect(generate(root).code).toMatchSnapshot()
// })
test('with v-if/else', () => {
const root = transformWithOnce(`<view v-if="BOOLEAN" v-once /><p v-else/>`)
expect(root.cached).toBe(1)
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect(root.children[0]).toMatchObject({
type: NodeTypes.IF,
// should cache the entire v-if/else-if/else expression, not just a single branch
codegenNode: {
type: NodeTypes.JS_CACHE_EXPRESSION,
value: {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
consequent: {
type: NodeTypes.VNODE_CALL,
tag: `"view"`,
},
alternate: {
type: NodeTypes.VNODE_CALL,
tag: `"p"`,
},
},
},
})
})
test('with v-for', () => {
const root = transformWithOnce(`<view v-for="i in list" v-once />`)
expect(root.cached).toBe(1)
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect(root.children[0]).toMatchObject({
type: NodeTypes.FOR,
// should cache the entire v-for expression, not just a single branch
codegenNode: {
type: NodeTypes.JS_CACHE_EXPRESSION,
},
})
})
})
...@@ -198,7 +198,7 @@ const UTS_COMPONENT_ELEMENT_IMPORTS = `/*UTS-COMPONENTS-IMPORTS*/` ...@@ -198,7 +198,7 @@ const UTS_COMPONENT_ELEMENT_IMPORTS = `/*UTS-COMPONENTS-IMPORTS*/`
export function generate( export function generate(
ast: RootNode, ast: RootNode,
options: CodegenOptions options: CodegenOptions = {}
): CodegenResult { ): CodegenResult {
const context = createCodegenContext(ast, options) const context = createCodegenContext(ast, options)
const { mode, deindent, indent, push, newline } = context const { mode, deindent, indent, push, newline } = context
...@@ -822,21 +822,20 @@ function genConditionalExpression( ...@@ -822,21 +822,20 @@ function genConditionalExpression(
function genCacheExpression(node: CacheExpression, context: CodegenContext) { function genCacheExpression(node: CacheExpression, context: CodegenContext) {
const { push, helper, indent, deindent, newline } = context const { push, helper, indent, deindent, newline } = context
push(`_cache[${node.index}] || (`) push(`_cache[${node.index}] ?? run((): VNode | null => {`)
if (node.isVNode) { if (node.isVNode) {
indent() indent()
push(`${helper(SET_BLOCK_TRACKING)}(-1),`) push(`${helper(SET_BLOCK_TRACKING)}(-1)`)
newline() newline()
} }
push(`_cache[${node.index}] = `) push(`_cache[${node.index}] = `)
genNode(node.value, context) genNode(node.value, context)
if (node.isVNode) { if (node.isVNode) {
push(`,`)
newline() newline()
push(`${helper(SET_BLOCK_TRACKING)}(1),`) push(`${helper(SET_BLOCK_TRACKING)}(1)`)
newline() newline()
push(`_cache[${node.index}]`) push(`return _cache[${node.index}] as VNode | null`)
deindent() deindent()
} }
push(`)`) push(`})`)
} }
...@@ -32,6 +32,7 @@ import { transformElements } from './transforms/transformElements' ...@@ -32,6 +32,7 @@ import { transformElements } from './transforms/transformElements'
import { transformStyle } from './transforms/transformStyle' import { transformStyle } from './transforms/transformStyle'
import { transformVHtml } from './transforms/vHtml' import { transformVHtml } from './transforms/vHtml'
import { transformMemo } from './transforms/vMemo' import { transformMemo } from './transforms/vMemo'
import { transformOnce } from './transforms/vOnce'
export type TransformPreset = [ export type TransformPreset = [
NodeTransform[], NodeTransform[],
...@@ -43,6 +44,7 @@ export function getBaseTransformPreset( ...@@ -43,6 +44,7 @@ export function getBaseTransformPreset(
): TransformPreset { ): TransformPreset {
return [ return [
[ [
transformOnce,
transformIf, transformIf,
transformMemo, transformMemo,
transformFor, transformFor,
......
...@@ -270,10 +270,18 @@ export function transform(root: RootNode, options: TransformOptions) { ...@@ -270,10 +270,18 @@ export function transform(root: RootNode, options: TransformOptions) {
const context = createTransformContext(root, options) const context = createTransformContext(root, options)
traverseNode(root, context) traverseNode(root, context)
createRootCodegen(root, context) createRootCodegen(root, context)
// finalize meta information
root.helpers = new Set([...context.helpers.keys()])
root.components = [...context.components] root.components = [...context.components]
// @ts-ignore root.directives = [...context.directives]
root.elements = Array.from(context.elements)
root.imports = context.imports root.imports = context.imports
// root.hoists = context.hoists
root.temps = context.temps
root.cached = context.cached
// @ts-expect-error
root.elements = Array.from(context.elements)
} }
export function isSingleElementRoot( export function isSingleElementRoot(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册