refactor(compiler): use shorter helpers for text and comment nodes

This commit is contained in:
Evan You 2019-10-24 17:55:00 -04:00
parent eb20730a67
commit 1c0a2c6d41
19 changed files with 126 additions and 108 deletions

View File

@ -90,7 +90,7 @@ exports[`compiler: codegen comment 1`] = `
" "
return function render() { return function render() {
with (this) { with (this) {
return _createVNode(_Comment, null, \\"foo\\") return _createCommentVNode(\\"foo\\")
} }
}" }"
`; `;

View File

@ -5,13 +5,13 @@ exports[`compiler: integration tests function mode 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { toString: _toString, openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Comment: _Comment, Fragment: _Fragment, renderList: _renderList, Text: _Text } = _Vue const { toString: _toString, openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment, renderList: _renderList, createTextVNode: _createTextVNode } = _Vue
return (_openBlock(), _createBlock(\\"div\\", { return (_openBlock(), _createBlock(\\"div\\", {
id: \\"foo\\", id: \\"foo\\",
class: bar.baz class: bar.baz
}, [ }, [
_createVNode(_Text, null, _toString(world.burn()) + \\" \\", 1 /* TEXT */), _createTextVNode(_toString(world.burn()) + \\" \\", 1 /* TEXT */),
(_openBlock(), ok (_openBlock(), ok
? _createBlock(\\"div\\", { key: 0 }, \\"yes\\") ? _createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: _createBlock(_Fragment, { key: 1 }, [\\"no\\"])), : _createBlock(_Fragment, { key: 1 }, [\\"no\\"])),
@ -26,7 +26,7 @@ return function render() {
`; `;
exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = ` exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = `
"const { toString, openBlock, createVNode, createBlock, Comment, Fragment, renderList, Text } = Vue "const { toString, openBlock, createVNode, createBlock, createCommentVNode, Fragment, renderList, createTextVNode } = Vue
return function render() { return function render() {
const _ctx = this const _ctx = this
@ -34,7 +34,7 @@ return function render() {
id: \\"foo\\", id: \\"foo\\",
class: _ctx.bar.baz class: _ctx.bar.baz
}, [ }, [
createVNode(Text, null, toString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */), createTextVNode(toString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */),
(openBlock(), (_ctx.ok) (openBlock(), (_ctx.ok)
? createBlock(\\"div\\", { key: 0 }, \\"yes\\") ? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: createBlock(Fragment, { key: 1 }, [\\"no\\"])), : createBlock(Fragment, { key: 1 }, [\\"no\\"])),
@ -48,7 +48,7 @@ return function render() {
`; `;
exports[`compiler: integration tests module mode 1`] = ` exports[`compiler: integration tests module mode 1`] = `
"import { toString, openBlock, createVNode, createBlock, Comment, Fragment, renderList, Text } from \\"vue\\" "import { toString, openBlock, createVNode, createBlock, createCommentVNode, Fragment, renderList, createTextVNode } from \\"vue\\"
export default function render() { export default function render() {
const _ctx = this const _ctx = this
@ -56,7 +56,7 @@ export default function render() {
id: \\"foo\\", id: \\"foo\\",
class: _ctx.bar.baz class: _ctx.bar.baz
}, [ }, [
createVNode(Text, null, toString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */), createTextVNode(toString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */),
(openBlock(), (_ctx.ok) (openBlock(), (_ctx.ok)
? createBlock(\\"div\\", { key: 0 }, \\"yes\\") ? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
: createBlock(Fragment, { key: 1 }, [\\"no\\"])), : createBlock(Fragment, { key: 1 }, [\\"no\\"])),

View File

@ -18,11 +18,11 @@ import {
} from '../src' } from '../src'
import { import {
CREATE_VNODE, CREATE_VNODE,
COMMENT,
TO_STRING, TO_STRING,
RESOLVE_DIRECTIVE, RESOLVE_DIRECTIVE,
helperNameMap, helperNameMap,
RESOLVE_COMPONENT RESOLVE_COMPONENT,
CREATE_COMMENT
} from '../src/runtimeHelpers' } from '../src/runtimeHelpers'
import { createElementWithCodegen } from './testUtils' import { createElementWithCodegen } from './testUtils'
import { PatchFlags } from '@vue/shared' import { PatchFlags } from '@vue/shared'
@ -149,7 +149,6 @@ describe('compiler: codegen', () => {
codegenNode: { codegenNode: {
type: NodeTypes.TEXT, type: NodeTypes.TEXT,
content: 'hello', content: 'hello',
isEmpty: false,
loc: locStub loc: locStub
} }
}) })
@ -178,11 +177,7 @@ describe('compiler: codegen', () => {
} }
}) })
) )
expect(code).toMatch( expect(code).toMatch(`return _${helperNameMap[CREATE_COMMENT]}("foo")`)
`return _${helperNameMap[CREATE_VNODE]}(_${
helperNameMap[COMMENT]
}, null, "foo")`
)
expect(code).toMatchSnapshot() expect(code).toMatchSnapshot()
}) })

View File

@ -1612,6 +1612,14 @@ foo
expect(ast.children.every(c => c.type === NodeTypes.ELEMENT)).toBe(true) expect(ast.children.every(c => c.type === NodeTypes.ELEMENT)).toBe(true)
}) })
it('should remove whitespaces adjacent to comments', () => {
const ast = parse(`<div/> \n <!--foo--> <div/>`)
expect(ast.children.length).toBe(3)
expect(ast.children[0].type).toBe(NodeTypes.ELEMENT)
expect(ast.children[1].type).toBe(NodeTypes.COMMENT)
expect(ast.children[2].type).toBe(NodeTypes.ELEMENT)
})
it('should remove whitespaces w/ newline between comments and elements', () => { it('should remove whitespaces w/ newline between comments and elements', () => {
const ast = parse(`<div/> \n <!--foo--> \n <div/>`) const ast = parse(`<div/> \n <!--foo--> \n <div/>`)
expect(ast.children.length).toBe(3) expect(ast.children.length).toBe(3)

View File

@ -9,13 +9,12 @@ import {
import { ErrorCodes, createCompilerError } from '../src/errors' import { ErrorCodes, createCompilerError } from '../src/errors'
import { import {
TO_STRING, TO_STRING,
CREATE_VNODE,
COMMENT,
OPEN_BLOCK, OPEN_BLOCK,
CREATE_BLOCK, CREATE_BLOCK,
FRAGMENT, FRAGMENT,
RENDER_SLOT, RENDER_SLOT,
WITH_DIRECTIVES WITH_DIRECTIVES,
CREATE_COMMENT
} from '../src/runtimeHelpers' } from '../src/runtimeHelpers'
import { transformIf } from '../src/transforms/vIf' import { transformIf } from '../src/transforms/vIf'
import { transformFor } from '../src/transforms/vFor' import { transformFor } from '../src/transforms/vFor'
@ -232,8 +231,7 @@ describe('compiler: transform', () => {
test('should inject createVNode and Comment for comments', () => { test('should inject createVNode and Comment for comments', () => {
const ast = parse(`<!--foo-->`) const ast = parse(`<!--foo-->`)
transform(ast, {}) transform(ast, {})
expect(ast.helpers).toContain(CREATE_VNODE) expect(ast.helpers).toContain(CREATE_COMMENT)
expect(ast.helpers).toContain(COMMENT)
}) })
describe('root codegenNode', () => { describe('root codegenNode', () => {

View File

@ -40,15 +40,15 @@ return function render() {
exports[`compiler: hoistStatic transform hoist nested static tree with comments 1`] = ` exports[`compiler: hoistStatic transform hoist nested static tree with comments 1`] = `
"const _Vue = Vue "const _Vue = Vue
const _createVNode = Vue.createVNode const _createVNode = Vue.createVNode
const _Comment = Vue.Comment const _createCommentVNode = Vue.createCommentVNode
const _hoisted_1 = _createVNode(\\"div\\", null, [ const _hoisted_1 = _createVNode(\\"div\\", null, [
_createVNode(_Comment, null, \\"comment\\") _createCommentVNode(\\"comment\\")
]) ])
return function render() { return function render() {
with (this) { with (this) {
const { createVNode: _createVNode, Comment: _Comment, createBlock: _createBlock, openBlock: _openBlock } = _Vue const { createCommentVNode: _createCommentVNode, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
return (_openBlock(), _createBlock(\\"div\\", null, [ return (_openBlock(), _createBlock(\\"div\\", null, [
_hoisted_1 _hoisted_1
@ -372,7 +372,7 @@ return function render() {
exports[`compiler: hoistStatic transform should hoist v-if props/children if static 1`] = ` exports[`compiler: hoistStatic transform should hoist v-if props/children if static 1`] = `
"const _Vue = Vue "const _Vue = Vue
const _createVNode = Vue.createVNode const _createVNode = Vue.createVNode
const _Comment = Vue.Comment const _createCommentVNode = Vue.createCommentVNode
const _hoisted_1 = { const _hoisted_1 = {
key: 0, key: 0,
@ -382,14 +382,14 @@ const _hoisted_2 = _createVNode(\\"span\\")
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Comment: _Comment } = _Vue const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), _createBlock(\\"div\\", null, [ return (_openBlock(), _createBlock(\\"div\\", null, [
(_openBlock(), ok (_openBlock(), ok
? _createBlock(\\"div\\", _hoisted_1, [ ? _createBlock(\\"div\\", _hoisted_1, [
_hoisted_2 _hoisted_2
]) ])
: _createBlock(_Comment)) : _createCommentVNode())
])) ]))
} }
}" }"

View File

@ -17,11 +17,11 @@ exports[`compiler: transform text consecutive text between elements 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { createVNode: _createVNode, toString: _toString, Text: _Text, createBlock: _createBlock, Fragment: _Fragment, openBlock: _openBlock } = _Vue const { createVNode: _createVNode, toString: _toString, createTextVNode: _createTextVNode, createBlock: _createBlock, Fragment: _Fragment, openBlock: _openBlock } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, [ return (_openBlock(), _createBlock(_Fragment, null, [
_createVNode(\\"div\\"), _createVNode(\\"div\\"),
_createVNode(_Text, null, _toString(foo) + \\" bar \\" + _toString(baz), 1 /* TEXT */), _createTextVNode(_toString(foo) + \\" bar \\" + _toString(baz), 1 /* TEXT */),
_createVNode(\\"div\\") _createVNode(\\"div\\")
])) ]))
} }
@ -33,13 +33,13 @@ exports[`compiler: transform text consecutive text mixed with elements 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { createVNode: _createVNode, toString: _toString, Text: _Text, createBlock: _createBlock, Fragment: _Fragment, openBlock: _openBlock } = _Vue const { createVNode: _createVNode, toString: _toString, createTextVNode: _createTextVNode, createBlock: _createBlock, Fragment: _Fragment, openBlock: _openBlock } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, [ return (_openBlock(), _createBlock(_Fragment, null, [
_createVNode(\\"div\\"), _createVNode(\\"div\\"),
_createVNode(_Text, null, _toString(foo) + \\" bar \\" + _toString(baz), 1 /* TEXT */), _createTextVNode(_toString(foo) + \\" bar \\" + _toString(baz), 1 /* TEXT */),
_createVNode(\\"div\\"), _createVNode(\\"div\\"),
_createVNode(_Text, null, \\"hello\\"), _createTextVNode(\\"hello\\"),
_createVNode(\\"div\\") _createVNode(\\"div\\")
])) ]))
} }
@ -63,11 +63,11 @@ exports[`compiler: transform text text between elements (static) 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { createVNode: _createVNode, Text: _Text, createBlock: _createBlock, Fragment: _Fragment, openBlock: _openBlock } = _Vue const { createVNode: _createVNode, createTextVNode: _createTextVNode, createBlock: _createBlock, Fragment: _Fragment, openBlock: _openBlock } = _Vue
return (_openBlock(), _createBlock(_Fragment, null, [ return (_openBlock(), _createBlock(_Fragment, null, [
_createVNode(\\"div\\"), _createVNode(\\"div\\"),
_createVNode(_Text, null, \\"hello\\"), _createTextVNode(\\"hello\\"),
_createVNode(\\"div\\") _createVNode(\\"div\\")
])) ]))
} }

View File

@ -155,13 +155,13 @@ exports[`compiler: v-for codegen v-if + v-for 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, renderList: _renderList, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode, Comment: _Comment } = _Vue const { openBlock: _openBlock, renderList: _renderList, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => { ? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
return (_openBlock(), _createBlock(\\"div\\")) return (_openBlock(), _createBlock(\\"div\\"))
}), 128 /* UNKEYED_FRAGMENT */) }), 128 /* UNKEYED_FRAGMENT */)
: _createBlock(_Comment)) : _createCommentVNode())
} }
}" }"
`; `;

View File

@ -5,11 +5,11 @@ exports[`compiler: v-if codegen basic v-if 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Comment: _Comment } = _Vue const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _createBlock(\\"div\\", { key: 0 }) ? _createBlock(\\"div\\", { key: 0 })
: _createBlock(_Comment)) : _createCommentVNode())
} }
}" }"
`; `;
@ -19,7 +19,7 @@ exports[`compiler: v-if codegen template v-if 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, Comment: _Comment } = _Vue const { openBlock: _openBlock, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _createBlock(_Fragment, { key: 0 }, [ ? _createBlock(_Fragment, { key: 0 }, [
@ -27,7 +27,7 @@ return function render() {
\\"hello\\", \\"hello\\",
_createVNode(\\"p\\") _createVNode(\\"p\\")
]) ])
: _createBlock(_Comment)) : _createCommentVNode())
} }
}" }"
`; `;
@ -37,11 +37,11 @@ exports[`compiler: v-if codegen template v-if w/ single <slot/> child 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, renderSlot: _renderSlot, createBlock: _createBlock, Comment: _Comment } = _Vue const { openBlock: _openBlock, renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _renderSlot($slots, \\"default\\", { key: 0 }) ? _renderSlot($slots, \\"default\\", { key: 0 })
: _createBlock(_Comment)) : _createCommentVNode())
} }
}" }"
`; `;
@ -51,7 +51,7 @@ exports[`compiler: v-if codegen v-if + v-else 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Comment: _Comment } = _Vue const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _createBlock(\\"div\\", { key: 0 }) ? _createBlock(\\"div\\", { key: 0 })
@ -65,7 +65,7 @@ exports[`compiler: v-if codegen v-if + v-else-if + v-else 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Comment: _Comment, Fragment: _Fragment } = _Vue const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _createBlock(\\"div\\", { key: 0 }) ? _createBlock(\\"div\\", { key: 0 })
@ -81,13 +81,13 @@ exports[`compiler: v-if codegen v-if + v-else-if 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Comment: _Comment } = _Vue const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _createBlock(\\"div\\", { key: 0 }) ? _createBlock(\\"div\\", { key: 0 })
: orNot : orNot
? _createBlock(\\"p\\", { key: 1 }) ? _createBlock(\\"p\\", { key: 1 })
: _createBlock(_Comment)) : _createCommentVNode())
} }
}" }"
`; `;
@ -97,11 +97,11 @@ exports[`compiler: v-if codegen v-if on <slot/> 1`] = `
return function render() { return function render() {
with (this) { with (this) {
const { openBlock: _openBlock, renderSlot: _renderSlot, createBlock: _createBlock, Comment: _Comment } = _Vue const { openBlock: _openBlock, renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
return (_openBlock(), ok return (_openBlock(), ok
? _renderSlot($slots, \\"default\\", { key: 0 }) ? _renderSlot($slots, \\"default\\", { key: 0 })
: _createBlock(_Comment)) : _createCommentVNode())
} }
}" }"
`; `;

View File

@ -8,7 +8,7 @@ import {
import { transformText } from '../../src/transforms/transformText' import { transformText } from '../../src/transforms/transformText'
import { transformExpression } from '../../src/transforms/transformExpression' import { transformExpression } from '../../src/transforms/transformExpression'
import { transformElement } from '../../src/transforms/transformElement' import { transformElement } from '../../src/transforms/transformElement'
import { CREATE_VNODE, TEXT } from '../../src/runtimeHelpers' import { CREATE_TEXT } from '../../src/runtimeHelpers'
import { genFlagText } from '../testUtils' import { genFlagText } from '../testUtils'
import { PatchFlags } from '@vue/shared' import { PatchFlags } from '@vue/shared'
@ -62,10 +62,8 @@ describe('compiler: transform text', () => {
type: NodeTypes.TEXT_CALL, type: NodeTypes.TEXT_CALL,
codegenNode: { codegenNode: {
type: NodeTypes.JS_CALL_EXPRESSION, type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_VNODE, callee: CREATE_TEXT,
arguments: [ arguments: [
TEXT,
`null`,
{ {
type: NodeTypes.COMPOUND_EXPRESSION, type: NodeTypes.COMPOUND_EXPRESSION,
children: [ children: [
@ -93,10 +91,8 @@ describe('compiler: transform text', () => {
type: NodeTypes.TEXT_CALL, type: NodeTypes.TEXT_CALL,
codegenNode: { codegenNode: {
type: NodeTypes.JS_CALL_EXPRESSION, type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_VNODE, callee: CREATE_TEXT,
arguments: [ arguments: [
TEXT,
`null`,
{ {
type: NodeTypes.TEXT, type: NodeTypes.TEXT,
content: `hello` content: `hello`
@ -119,10 +115,8 @@ describe('compiler: transform text', () => {
type: NodeTypes.TEXT_CALL, type: NodeTypes.TEXT_CALL,
codegenNode: { codegenNode: {
type: NodeTypes.JS_CALL_EXPRESSION, type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_VNODE, callee: CREATE_TEXT,
arguments: [ arguments: [
TEXT,
`null`,
{ {
type: NodeTypes.COMPOUND_EXPRESSION, type: NodeTypes.COMPOUND_EXPRESSION,
children: [ children: [
@ -142,10 +136,8 @@ describe('compiler: transform text', () => {
type: NodeTypes.TEXT_CALL, type: NodeTypes.TEXT_CALL,
codegenNode: { codegenNode: {
type: NodeTypes.JS_CALL_EXPRESSION, type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_VNODE, callee: CREATE_TEXT,
arguments: [ arguments: [
TEXT,
`null`,
{ {
type: NodeTypes.TEXT, type: NodeTypes.TEXT,
content: `hello` content: `hello`

View File

@ -19,11 +19,11 @@ import { CompilerOptions, generate } from '../../src'
import { import {
OPEN_BLOCK, OPEN_BLOCK,
CREATE_BLOCK, CREATE_BLOCK,
COMMENT,
FRAGMENT, FRAGMENT,
MERGE_PROPS, MERGE_PROPS,
WITH_DIRECTIVES, WITH_DIRECTIVES,
RENDER_SLOT RENDER_SLOT,
CREATE_COMMENT
} from '../../src/runtimeHelpers' } from '../../src/runtimeHelpers'
import { createObjectMatcher } from '../testUtils' import { createObjectMatcher } from '../testUtils'
@ -265,7 +265,11 @@ describe('compiler: v-if', () => {
}) })
describe('codegen', () => { describe('codegen', () => {
function assertSharedCodegen(node: SequenceExpression, depth: number = 0) { function assertSharedCodegen(
node: SequenceExpression,
depth: number = 0,
hasElse: boolean = false
) {
expect(node).toMatchObject({ expect(node).toMatchObject({
type: NodeTypes.JS_SEQUENCE_EXPRESSION, type: NodeTypes.JS_SEQUENCE_EXPRESSION,
expressions: [ expressions: [
@ -287,7 +291,7 @@ describe('compiler: v-if', () => {
depth < 1 depth < 1
? { ? {
type: NodeTypes.JS_CALL_EXPRESSION, type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_BLOCK callee: hasElse ? CREATE_BLOCK : CREATE_COMMENT
} }
: { : {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION, type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
@ -300,7 +304,7 @@ describe('compiler: v-if', () => {
}, },
alternate: { alternate: {
type: NodeTypes.JS_CALL_EXPRESSION, type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_BLOCK callee: hasElse ? CREATE_BLOCK : CREATE_COMMENT
} }
} }
} }
@ -322,7 +326,10 @@ describe('compiler: v-if', () => {
]) ])
const branch2 = (codegenNode.expressions[1] as ConditionalExpression) const branch2 = (codegenNode.expressions[1] as ConditionalExpression)
.alternate as CallExpression .alternate as CallExpression
expect(branch2.arguments).toMatchObject([COMMENT]) expect(branch2).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_COMMENT
})
expect(generate(root).code).toMatchSnapshot() expect(generate(root).code).toMatchSnapshot()
}) })
@ -345,7 +352,10 @@ describe('compiler: v-if', () => {
]) ])
const branch2 = (codegenNode.expressions[1] as ConditionalExpression) const branch2 = (codegenNode.expressions[1] as ConditionalExpression)
.alternate as CallExpression .alternate as CallExpression
expect(branch2.arguments).toMatchObject([COMMENT]) expect(branch2).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_COMMENT
})
expect(generate(root).code).toMatchSnapshot() expect(generate(root).code).toMatchSnapshot()
}) })
@ -386,7 +396,7 @@ describe('compiler: v-if', () => {
root, root,
node: { codegenNode } node: { codegenNode }
} = parseWithIfTransform(`<div v-if="ok"/><p v-else/>`) } = parseWithIfTransform(`<div v-if="ok"/><p v-else/>`)
assertSharedCodegen(codegenNode) assertSharedCodegen(codegenNode, 0, true)
const branch1 = (codegenNode.expressions[1] as ConditionalExpression) const branch1 = (codegenNode.expressions[1] as ConditionalExpression)
.consequent as CallExpression .consequent as CallExpression
expect(branch1.arguments).toMatchObject([ expect(branch1.arguments).toMatchObject([
@ -430,7 +440,7 @@ describe('compiler: v-if', () => {
} = parseWithIfTransform( } = parseWithIfTransform(
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>` `<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`
) )
assertSharedCodegen(codegenNode, 1) assertSharedCodegen(codegenNode, 1, true)
const branch1 = (codegenNode.expressions[1] as ConditionalExpression) const branch1 = (codegenNode.expressions[1] as ConditionalExpression)
.consequent as CallExpression .consequent as CallExpression
expect(branch1.arguments).toMatchObject([ expect(branch1.arguments).toMatchObject([

View File

@ -29,13 +29,13 @@ import {
} from './utils' } from './utils'
import { isString, isArray, isSymbol } from '@vue/shared' import { isString, isArray, isSymbol } from '@vue/shared'
import { import {
helperNameMap,
TO_STRING, TO_STRING,
CREATE_VNODE, CREATE_VNODE,
COMMENT,
helperNameMap,
RESOLVE_COMPONENT, RESOLVE_COMPONENT,
RESOLVE_DIRECTIVE, RESOLVE_DIRECTIVE,
SET_BLOCK_TRACKING SET_BLOCK_TRACKING,
CREATE_COMMENT
} from './runtimeHelpers' } from './runtimeHelpers'
type CodegenNode = TemplateChildNode | JSChildNode type CodegenNode = TemplateChildNode | JSChildNode
@ -212,9 +212,17 @@ export function generate(
// has check cost, but hoists are lifted out of the function - we need // has check cost, but hoists are lifted out of the function - we need
// to provide the helper here. // to provide the helper here.
if (ast.hoists.length) { if (ast.hoists.length) {
push(`const _${helperNameMap[CREATE_VNODE]} = Vue.createVNode\n`) push(
if (ast.helpers.includes(COMMENT)) { `const _${helperNameMap[CREATE_VNODE]} = Vue.${
push(`const _${helperNameMap[COMMENT]} = Vue.Comment\n`) helperNameMap[CREATE_VNODE]
}\n`
)
if (ast.helpers.includes(CREATE_COMMENT)) {
push(
`const _${helperNameMap[CREATE_COMMENT]} = Vue.${
helperNameMap[CREATE_COMMENT]
}\n`
)
} }
} }
} }
@ -502,12 +510,7 @@ function genExpressionAsPropertyKey(
function genComment(node: CommentNode, context: CodegenContext) { function genComment(node: CommentNode, context: CodegenContext) {
if (__DEV__) { if (__DEV__) {
const { push, helper } = context const { push, helper } = context
push( push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node)
`${helper(CREATE_VNODE)}(${helper(COMMENT)}, null, ${JSON.stringify(
node.content
)})`,
node
)
} }
} }

View File

@ -218,15 +218,16 @@ function parseChildren(
const next = nodes[i + 1] const next = nodes[i + 1]
// If: // If:
// - the whitespace is the first or last node, or: // - the whitespace is the first or last node, or:
// - the whitespace contains newline AND is between two element or comments // - the whitespace is adjacent to a comment, or:
// - the whitespace is between two elements AND contains newline
// Then the whitespace is ignored. // Then the whitespace is ignored.
if ( if (
!prev || !prev ||
!next || !next ||
((prev.type === NodeTypes.ELEMENT || prev.type === NodeTypes.COMMENT ||
prev.type === NodeTypes.COMMENT) && next.type === NodeTypes.COMMENT ||
(next.type === NodeTypes.ELEMENT || (prev.type === NodeTypes.ELEMENT &&
next.type === NodeTypes.COMMENT) && next.type === NodeTypes.ELEMENT &&
/[\r\n]/.test(node.content)) /[\r\n]/.test(node.content))
) { ) {
removedWhitespace = true removedWhitespace = true

View File

@ -1,11 +1,11 @@
export const FRAGMENT = Symbol(__DEV__ ? `Fragment` : ``) export const FRAGMENT = Symbol(__DEV__ ? `Fragment` : ``)
export const PORTAL = Symbol(__DEV__ ? `Portal` : ``) export const PORTAL = Symbol(__DEV__ ? `Portal` : ``)
export const COMMENT = Symbol(__DEV__ ? `Comment` : ``)
export const TEXT = Symbol(__DEV__ ? `Text` : ``)
export const SUSPENSE = Symbol(__DEV__ ? `Suspense` : ``) export const SUSPENSE = Symbol(__DEV__ ? `Suspense` : ``)
export const OPEN_BLOCK = Symbol(__DEV__ ? `openBlock` : ``) export const OPEN_BLOCK = Symbol(__DEV__ ? `openBlock` : ``)
export const CREATE_BLOCK = Symbol(__DEV__ ? `createBlock` : ``) export const CREATE_BLOCK = Symbol(__DEV__ ? `createBlock` : ``)
export const CREATE_VNODE = Symbol(__DEV__ ? `createVNode` : ``) export const CREATE_VNODE = Symbol(__DEV__ ? `createVNode` : ``)
export const CREATE_COMMENT = Symbol(__DEV__ ? `createCommentVNode` : ``)
export const CREATE_TEXT = Symbol(__DEV__ ? `createTextVNode` : ``)
export const RESOLVE_COMPONENT = Symbol(__DEV__ ? `resolveComponent` : ``) export const RESOLVE_COMPONENT = Symbol(__DEV__ ? `resolveComponent` : ``)
export const RESOLVE_DYNAMIC_COMPONENT = Symbol( export const RESOLVE_DYNAMIC_COMPONENT = Symbol(
__DEV__ ? `resolveDynamicComponent` : `` __DEV__ ? `resolveDynamicComponent` : ``
@ -27,12 +27,12 @@ export const SET_BLOCK_TRACKING = Symbol(__DEV__ ? `setBlockTracking` : ``)
export const helperNameMap: any = { export const helperNameMap: any = {
[FRAGMENT]: `Fragment`, [FRAGMENT]: `Fragment`,
[PORTAL]: `Portal`, [PORTAL]: `Portal`,
[COMMENT]: `Comment`,
[TEXT]: `Text`,
[SUSPENSE]: `Suspense`, [SUSPENSE]: `Suspense`,
[OPEN_BLOCK]: `openBlock`, [OPEN_BLOCK]: `openBlock`,
[CREATE_BLOCK]: `createBlock`, [CREATE_BLOCK]: `createBlock`,
[CREATE_VNODE]: `createVNode`, [CREATE_VNODE]: `createVNode`,
[CREATE_COMMENT]: `createCommentVNode`,
[CREATE_TEXT]: `createTextVNode`,
[RESOLVE_COMPONENT]: `resolveComponent`, [RESOLVE_COMPONENT]: `resolveComponent`,
[RESOLVE_DYNAMIC_COMPONENT]: `resolveDynamicComponent`, [RESOLVE_DYNAMIC_COMPONENT]: `resolveDynamicComponent`,
[RESOLVE_DIRECTIVE]: `resolveDirective`, [RESOLVE_DIRECTIVE]: `resolveDirective`,

View File

@ -21,12 +21,11 @@ import { isString, isArray } from '@vue/shared'
import { CompilerError, defaultOnError } from './errors' import { CompilerError, defaultOnError } from './errors'
import { import {
TO_STRING, TO_STRING,
COMMENT,
CREATE_VNODE,
FRAGMENT, FRAGMENT,
helperNameMap, helperNameMap,
WITH_DIRECTIVES, WITH_DIRECTIVES,
CREATE_BLOCK CREATE_BLOCK,
CREATE_COMMENT
} from './runtimeHelpers' } from './runtimeHelpers'
import { isVSlot, createBlockExpression } from './utils' import { isVSlot, createBlockExpression } from './utils'
import { hoistStatic, isSingleElementRoot } from './transforms/hoistStatic' import { hoistStatic, isSingleElementRoot } from './transforms/hoistStatic'
@ -346,8 +345,7 @@ export function traverseNode(
case NodeTypes.COMMENT: case NodeTypes.COMMENT:
// inject import for the Comment symbol, which is needed for creating // inject import for the Comment symbol, which is needed for creating
// comment nodes with `createVNode` // comment nodes with `createVNode`
context.helper(CREATE_VNODE) context.helper(CREATE_COMMENT)
context.helper(COMMENT)
break break
case NodeTypes.INTERPOLATION: case NodeTypes.INTERPOLATION:
// no need to traverse, but we need to inject toString helper // no need to traverse, but we need to inject toString helper

View File

@ -5,9 +5,10 @@ import {
TextNode, TextNode,
InterpolationNode, InterpolationNode,
CompoundExpressionNode, CompoundExpressionNode,
createCallExpression createCallExpression,
CallExpression
} from '../ast' } from '../ast'
import { TEXT, CREATE_VNODE } from '../runtimeHelpers' import { CREATE_TEXT } from '../runtimeHelpers'
import { PatchFlags, PatchFlagNames } from '@vue/shared' import { PatchFlags, PatchFlagNames } from '@vue/shared'
const isText = ( const isText = (
@ -54,11 +55,17 @@ export const transformText: NodeTransform = (node, context) => {
if (hasText && children.length > 1) { if (hasText && children.length > 1) {
// when an element has mixed text/element children, convert text nodes // when an element has mixed text/element children, convert text nodes
// into createVNode(Text) calls. // into createTextVNode(text) calls.
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
const child = children[i] const child = children[i]
if (isText(child) || child.type === NodeTypes.COMPOUND_EXPRESSION) { if (isText(child) || child.type === NodeTypes.COMPOUND_EXPRESSION) {
const callArgs = [context.helper(TEXT), `null`, child] const callArgs: CallExpression['arguments'] = []
// createTextVNode defaults to single whitespace, so if it is a
// single space the code could be an empty call to save bytes.
if (child.type !== NodeTypes.TEXT || child.content !== ' ') {
callArgs.push(child)
}
// mark dynamic text with flag so it gets patched inside a block
if (child.type !== NodeTypes.TEXT) { if (child.type !== NodeTypes.TEXT) {
callArgs.push( callArgs.push(
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */` `${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
@ -69,7 +76,7 @@ export const transformText: NodeTransform = (node, context) => {
content: child, content: child,
loc: child.loc, loc: child.loc,
codegenNode: createCallExpression( codegenNode: createCallExpression(
context.helper(CREATE_VNODE), context.helper(CREATE_TEXT),
callArgs callArgs
) )
} }

View File

@ -30,10 +30,10 @@ import { processExpression } from './transformExpression'
import { import {
OPEN_BLOCK, OPEN_BLOCK,
CREATE_BLOCK, CREATE_BLOCK,
COMMENT,
FRAGMENT, FRAGMENT,
WITH_DIRECTIVES, WITH_DIRECTIVES,
CREATE_VNODE CREATE_VNODE,
CREATE_COMMENT
} from '../runtimeHelpers' } from '../runtimeHelpers'
import { injectProp } from '../utils' import { injectProp } from '../utils'
@ -152,9 +152,7 @@ function createCodegenNodeForBranch(
return createConditionalExpression( return createConditionalExpression(
branch.condition, branch.condition,
createChildrenCodegenNode(branch, index, context), createChildrenCodegenNode(branch, index, context),
createCallExpression(context.helper(CREATE_BLOCK), [ createCallExpression(context.helper(CREATE_COMMENT))
context.helper(COMMENT)
])
) as IfConditionalExpression ) as IfConditionalExpression
} else { } else {
return createChildrenCodegenNode(branch, index, context) as BlockCodegenNode return createChildrenCodegenNode(branch, index, context) as BlockCodegenNode

View File

@ -49,7 +49,7 @@ export { toString } from './helpers/toString'
export { toHandlers } from './helpers/toHandlers' export { toHandlers } from './helpers/toHandlers'
export { renderSlot } from './helpers/renderSlot' export { renderSlot } from './helpers/renderSlot'
export { createSlots } from './helpers/createSlots' export { createSlots } from './helpers/createSlots'
export { setBlockTracking } from './vnode' export { setBlockTracking, createTextVNode } from './vnode'
export { capitalize, camelize } from '@vue/shared' export { capitalize, camelize } from '@vue/shared'
// Internal, for integration with runtime compiler // Internal, for integration with runtime compiler

View File

@ -19,10 +19,10 @@ import { AppContext } from './apiApp'
import { SuspenseBoundary } from './suspense' import { SuspenseBoundary } from './suspense'
export const Fragment = __DEV__ ? Symbol('Fragment') : Symbol() export const Fragment = __DEV__ ? Symbol('Fragment') : Symbol()
export const Text = __DEV__ ? Symbol('Text') : Symbol()
export const Comment = __DEV__ ? Symbol('Comment') : Symbol()
export const Portal = __DEV__ ? Symbol('Portal') : Symbol() export const Portal = __DEV__ ? Symbol('Portal') : Symbol()
export const Suspense = __DEV__ ? Symbol('Suspense') : Symbol() export const Suspense = __DEV__ ? Symbol('Suspense') : Symbol()
export const Text = __DEV__ ? Symbol('Text') : Symbol()
export const Comment = __DEV__ ? Symbol('Comment') : Symbol()
export type VNodeTypes = export type VNodeTypes =
| string | string
@ -254,6 +254,14 @@ export function cloneVNode(vnode: VNode): VNode {
} }
} }
export function createTextVNode(text: string = ' ', flag: number = 0): VNode {
return createVNode(Text, null, text, flag)
}
export function createCommentVNode(text: string = ''): VNode {
return createVNode(Comment, null, text)
}
export function normalizeVNode(child: VNodeChild): VNode { export function normalizeVNode(child: VNodeChild): VNode {
if (child == null) { if (child == null) {
// empty placeholder // empty placeholder