mirror of https://github.com/vuejs/core.git
fix(compiler-core): change node hoisting to caching per instance (#11067)
close #5256 close #9219 close #10959
This commit is contained in:
parent
f8eba75d0a
commit
cd0ea0d479
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
exports[`compiler: parse > Edge Cases > invalid html 1`] = `
|
exports[`compiler: parse > Edge Cases > invalid html 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -86,7 +86,7 @@ exports[`compiler: parse > Edge Cases > invalid html 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Edge Cases > self closing multiple tag 1`] = `
|
exports[`compiler: parse > Edge Cases > self closing multiple tag 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -280,7 +280,7 @@ exports[`compiler: parse > Edge Cases > self closing multiple tag 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Edge Cases > valid html 1`] = `
|
exports[`compiler: parse > Edge Cases > valid html 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -498,7 +498,7 @@ exports[`compiler: parse > Edge Cases > valid html 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[cdata]]></template> 1`] = `
|
exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[cdata]]></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -550,7 +550,7 @@ exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><![CDATA[c
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><svg><![CDATA[cdata]]></svg></template> 1`] = `
|
exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><svg><![CDATA[cdata]]></svg></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -643,7 +643,7 @@ exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > <template><svg><![CD
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" id=""></div></template> 1`] = `
|
exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" id=""></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -813,7 +813,7 @@ exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > <template><div id="" i
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template>< 1`] = `
|
exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template>< 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -883,7 +883,7 @@ exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template>< 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template></ 1`] = `
|
exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template></ 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -953,7 +953,7 @@ exports[`compiler: parse > Errors > EOF_BEFORE_TAG_NAME > <template></ 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -1028,7 +1028,7 @@ exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[ 1`]
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[cdata 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[cdata 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -1121,7 +1121,7 @@ exports[`compiler: parse > Errors > EOF_IN_CDATA > <template><svg><![CDATA[cdata
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!-- 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!-- 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1173,7 +1173,7 @@ exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!-- 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!--comment 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!--comment 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -1243,7 +1243,7 @@ exports[`compiler: parse > Errors > EOF_IN_COMMENT > <template><!--comment 1`] =
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <div></div 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <div></div 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1295,7 +1295,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <div></div 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1347,7 +1347,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1399,7 +1399,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1451,7 +1451,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id = 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id = 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1503,7 +1503,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id = 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1555,7 +1555,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1607,7 +1607,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc" 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc" 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1659,7 +1659,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc" 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc"/ 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc"/ 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -1729,7 +1729,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id="abc"/ 1`] =
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1781,7 +1781,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc' 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc' 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -1833,7 +1833,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc' 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc'/ 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc'/ 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -1903,7 +1903,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id='abc'/ 1`] =
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id=abc / 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id=abc / 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -1973,7 +1973,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id=abc / 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id=abc 1`] = `
|
exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id=abc 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -2025,7 +2025,7 @@ exports[`compiler: parse > Errors > EOF_IN_TAG > <template><div id=abc 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id= /></div></template> 1`] = `
|
exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id= /></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -2148,7 +2148,7 @@ exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id=
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id= ></div></template> 1`] = `
|
exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id= ></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -2271,7 +2271,7 @@ exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id=
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id=></div></template> 1`] = `
|
exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id=></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -2394,7 +2394,7 @@ exports[`compiler: parse > Errors > MISSING_ATTRIBUTE_VALUE > <template><div id=
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > MISSING_END_TAG_NAME > <template></></template> 1`] = `
|
exports[`compiler: parse > Errors > MISSING_END_TAG_NAME > <template></></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -2446,7 +2446,7 @@ exports[`compiler: parse > Errors > MISSING_END_TAG_NAME > <template></></templa
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <template><div a"bc=''></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <template><div a"bc=''></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -2569,7 +2569,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <te
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <template><div a'bc=''></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <template><div a'bc=''></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -2692,7 +2692,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <te
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <template><div a<bc=''></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <template><div a<bc=''></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -2815,7 +2815,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME > <te
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar"></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar"></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -2938,7 +2938,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_V
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar'></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar'></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3061,7 +3061,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_V
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar<div></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar<div></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3184,7 +3184,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_V
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar=baz></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar=baz></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3307,7 +3307,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_V
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar\`></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE > <template><div foo=bar\`></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3430,7 +3430,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_V
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME > <template><div =></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME > <template><div =></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3537,7 +3537,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME > <template><div =foo=bar></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME > <template><div =foo=bar></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3660,7 +3660,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME > <template><?xml?></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME > <template><?xml?></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -3712,7 +3712,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > UNEXPECTED_SOLIDUS_IN_TAG > <template><div a/b></div></template> 1`] = `
|
exports[`compiler: parse > Errors > UNEXPECTED_SOLIDUS_IN_TAG > <template><div a/b></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3850,7 +3850,7 @@ exports[`compiler: parse > Errors > UNEXPECTED_SOLIDUS_IN_TAG > <template><div a
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <svg><![CDATA[</div>]]></svg> 1`] = `
|
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <svg><![CDATA[</div>]]></svg> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3920,7 +3920,7 @@ exports[`compiler: parse > Errors > X_INVALID_END_TAG > <svg><![CDATA[</div>]]><
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <svg><!--</div>--></svg> 1`] = `
|
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <svg><!--</div>--></svg> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -3990,7 +3990,7 @@ exports[`compiler: parse > Errors > X_INVALID_END_TAG > <svg><!--</div>--></svg>
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template></div></div></template> 1`] = `
|
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template></div></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -4042,7 +4042,7 @@ exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template></div></div></
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template></div></template> 1`] = `
|
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template></div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -4094,7 +4094,7 @@ exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template></div></templa
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template>{{'</div>'}}</template> 1`] = `
|
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template>{{'</div>'}}</template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -4182,7 +4182,7 @@ exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template>{{'</div>'}}</
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template>a </ b</template> 1`] = `
|
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template>a </ b</template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -4252,7 +4252,7 @@ exports[`compiler: parse > Errors > X_INVALID_END_TAG > <template>a </ b</templa
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <textarea></div></textarea> 1`] = `
|
exports[`compiler: parse > Errors > X_INVALID_END_TAG > <textarea></div></textarea> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -4322,7 +4322,7 @@ exports[`compiler: parse > Errors > X_INVALID_END_TAG > <textarea></div></textar
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END > <div v-foo:[sef fsef] /> 1`] = `
|
exports[`compiler: parse > Errors > X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END > <div v-foo:[sef fsef] /> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [],
|
"children": [],
|
||||||
|
@ -4446,7 +4446,7 @@ exports[`compiler: parse > Errors > X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END > <
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_MISSING_END_TAG > <template><div> 1`] = `
|
exports[`compiler: parse > Errors > X_MISSING_END_TAG > <template><div> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -4521,7 +4521,7 @@ exports[`compiler: parse > Errors > X_MISSING_END_TAG > <template><div> 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_MISSING_END_TAG > <template><div></template> 1`] = `
|
exports[`compiler: parse > Errors > X_MISSING_END_TAG > <template><div></template> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -4596,7 +4596,7 @@ exports[`compiler: parse > Errors > X_MISSING_END_TAG > <template><div></templat
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > <div>{{ foo</div> 1`] = `
|
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > <div>{{ foo</div> 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"children": [
|
"children": [
|
||||||
|
@ -4666,7 +4666,7 @@ exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > <div>{{ foo</d
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{ 1`] = `
|
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{ 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"content": "{{",
|
"content": "{{",
|
||||||
|
@ -4713,7 +4713,7 @@ exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{ 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{ foo 1`] = `
|
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{ foo 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"content": "{{ foo",
|
"content": "{{ foo",
|
||||||
|
@ -4760,7 +4760,7 @@ exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{ foo 1`] = `
|
||||||
|
|
||||||
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{}} 1`] = `
|
exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{}} 1`] = `
|
||||||
{
|
{
|
||||||
"cached": 0,
|
"cached": [],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"content": {
|
"content": {
|
||||||
|
|
|
@ -1,21 +1,5 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`scopeId compiler support > should push scopeId for hoisted nodes 1`] = `
|
|
||||||
"import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, createTextVNode as _createTextVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue"
|
|
||||||
|
|
||||||
const _withScopeId = n => (_pushScopeId("test"),n=n(),_popScopeId(),n)
|
|
||||||
const _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "hello", -1 /* HOISTED */))
|
|
||||||
const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "world", -1 /* HOISTED */))
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, [
|
|
||||||
_hoisted_1,
|
|
||||||
_createTextVNode(_toDisplayString(_ctx.foo), 1 /* TEXT */),
|
|
||||||
_hoisted_2
|
|
||||||
]))
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`scopeId compiler support > should wrap default slot 1`] = `
|
exports[`scopeId compiler support > should wrap default slot 1`] = `
|
||||||
"import { createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from "vue"
|
"import { createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, withCtx as _withCtx, openBlock as _openBlock, createBlock as _createBlock } from "vue"
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ function createRoot(options: Partial<RootNode> = {}): RootNode {
|
||||||
directives: [],
|
directives: [],
|
||||||
imports: [],
|
imports: [],
|
||||||
hoists: [],
|
hoists: [],
|
||||||
cached: 0,
|
cached: [],
|
||||||
temps: 0,
|
temps: 0,
|
||||||
codegenNode: createSimpleExpression(`null`, false),
|
codegenNode: createSimpleExpression(`null`, false),
|
||||||
loc: locStub,
|
loc: locStub,
|
||||||
|
@ -422,7 +422,7 @@ describe('compiler: codegen', () => {
|
||||||
test('CacheExpression', () => {
|
test('CacheExpression', () => {
|
||||||
const { code } = generate(
|
const { code } = generate(
|
||||||
createRoot({
|
createRoot({
|
||||||
cached: 1,
|
cached: [],
|
||||||
codegenNode: createCacheExpression(
|
codegenNode: createCacheExpression(
|
||||||
1,
|
1,
|
||||||
createSimpleExpression(`foo`, false),
|
createSimpleExpression(`foo`, false),
|
||||||
|
@ -440,7 +440,7 @@ describe('compiler: codegen', () => {
|
||||||
test('CacheExpression w/ isVNode: true', () => {
|
test('CacheExpression w/ isVNode: true', () => {
|
||||||
const { code } = generate(
|
const { code } = generate(
|
||||||
createRoot({
|
createRoot({
|
||||||
cached: 1,
|
cached: [],
|
||||||
codegenNode: createCacheExpression(
|
codegenNode: createCacheExpression(
|
||||||
1,
|
1,
|
||||||
createSimpleExpression(`foo`, false),
|
createSimpleExpression(`foo`, false),
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import { baseCompile } from '../src/compile'
|
import { baseCompile } from '../src/compile'
|
||||||
import { POP_SCOPE_ID, PUSH_SCOPE_ID } from '../src/runtimeHelpers'
|
|
||||||
import { PatchFlags } from '@vue/shared'
|
|
||||||
import { genFlagText } from './testUtils'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure all slot functions are wrapped with _withCtx
|
* Ensure all slot functions are wrapped with _withCtx
|
||||||
|
@ -57,28 +54,4 @@ describe('scopeId compiler support', () => {
|
||||||
expect(code).toMatch(/name: i,\s+fn: _withCtx\(/)
|
expect(code).toMatch(/name: i,\s+fn: _withCtx\(/)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should push scopeId for hoisted nodes', () => {
|
|
||||||
const { ast, code } = baseCompile(
|
|
||||||
`<div><div>hello</div>{{ foo }}<div>world</div></div>`,
|
|
||||||
{
|
|
||||||
mode: 'module',
|
|
||||||
scopeId: 'test',
|
|
||||||
hoistStatic: true,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
expect(ast.helpers).toContain(PUSH_SCOPE_ID)
|
|
||||||
expect(ast.helpers).toContain(POP_SCOPE_ID)
|
|
||||||
expect(ast.hoists.length).toBe(2)
|
|
||||||
;[
|
|
||||||
`const _withScopeId = n => (_pushScopeId("test"),n=n(),_popScopeId(),n)`,
|
|
||||||
`const _hoisted_1 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "hello", ${genFlagText(
|
|
||||||
PatchFlags.HOISTED,
|
|
||||||
)}))`,
|
|
||||||
`const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("div", null, "world", ${genFlagText(
|
|
||||||
PatchFlags.HOISTED,
|
|
||||||
)}))`,
|
|
||||||
].forEach(c => expect(code).toMatch(c))
|
|
||||||
expect(code).toMatchSnapshot()
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,103 +1,87 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist element with static key 1`] = `
|
exports[`compiler: cacheStatic transform > cache element with static key 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", { key: "foo" }, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("div", { key: "foo" }, null, -1 /* CACHED */)
|
||||||
|
])))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist nested static tree 1`] = `
|
exports[`compiler: cacheStatic transform > cache nested children array 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("p", null, [
|
|
||||||
/*#__PURE__*/_createElementVNode("span"),
|
|
||||||
/*#__PURE__*/_createElementVNode("span")
|
|
||||||
], -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("p", null, [
|
||||||
|
_createElementVNode("span"),
|
||||||
|
_createElementVNode("span")
|
||||||
|
], -1 /* CACHED */),
|
||||||
|
_createElementVNode("p", null, [
|
||||||
|
_createElementVNode("span"),
|
||||||
|
_createElementVNode("span")
|
||||||
|
], -1 /* CACHED */)
|
||||||
|
])))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist nested static tree with comments 1`] = `
|
exports[`compiler: cacheStatic transform > cache nested static tree with comments 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, [
|
|
||||||
/*#__PURE__*/_createCommentVNode("comment")
|
|
||||||
], -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("div", null, [
|
||||||
|
_createCommentVNode("comment")
|
||||||
|
], -1 /* CACHED */)
|
||||||
|
])))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist siblings with common non-hoistable parent 1`] = `
|
exports[`compiler: cacheStatic transform > cache siblings including text with common non-hoistable parent 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */)
|
return function render(_ctx, _cache) {
|
||||||
const _hoisted_2 = /*#__PURE__*/_createElementVNode("div", null, null, -1 /* HOISTED */)
|
with (_ctx) {
|
||||||
const _hoisted_3 = [
|
const { createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
_hoisted_1,
|
|
||||||
_hoisted_2
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
]
|
_createElementVNode("span", null, null, -1 /* CACHED */),
|
||||||
|
_createTextVNode("foo"),
|
||||||
|
_createElementVNode("div", null, null, -1 /* CACHED */)
|
||||||
|
])))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: cacheStatic transform > cache single children array 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_3))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("span", { class: "inline" }, "hello", -1 /* CACHED */)
|
||||||
|
])))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist simple element 1`] = `
|
exports[`compiler: cacheStatic transform > hoist static props for elements with directives 1`] = `
|
||||||
"const _Vue = Vue
|
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", { class: "inline" }, "hello", -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
|
||||||
with (_ctx) {
|
|
||||||
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist static props for elements with directives 1`] = `
|
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
const { createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
@ -118,7 +102,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist static props for elements with dynamic text children 1`] = `
|
exports[`compiler: cacheStatic transform > hoist static props for elements with dynamic text children 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
const { createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
@ -135,7 +119,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > hoist static props for elements with unhoistable children 1`] = `
|
exports[`compiler: cacheStatic transform > hoist static props for elements with unhoistable children 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createVNode: _createVNode, createElementVNode: _createElementVNode } = _Vue
|
const { createVNode: _createVNode, createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
@ -156,7 +140,53 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > hoist class with static object value 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > cache nested static tree with static interpolation 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
|
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("span", null, "foo " + _toDisplayString(1) + " " + _toDisplayString(true), -1 /* CACHED */)
|
||||||
|
])))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > cache nested static tree with static prop value 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||||
|
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("span", { foo: 0 }, _toDisplayString(1), -1 /* CACHED */)
|
||||||
|
])))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > clone hoisted array children in v-for + HMR mode 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, [
|
||||||
|
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(1, (i) => {
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("span", { class: "hi" }, null, -1 /* CACHED */)
|
||||||
|
]))]))
|
||||||
|
}), 256 /* UNKEYED_FRAGMENT */))
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > hoist class with static object value 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
const { createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
@ -175,50 +205,8 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > hoist nested static tree with static interpolation 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > should NOT cache SVG with directives 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", null, "foo " + /*#__PURE__*/_toDisplayString(1) + " " + /*#__PURE__*/_toDisplayString(true), -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
|
||||||
with (_ctx) {
|
|
||||||
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > hoist nested static tree with static prop value 1`] = `
|
|
||||||
"const _Vue = Vue
|
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", { foo: 0 }, /*#__PURE__*/_toDisplayString(1), -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
|
||||||
with (_ctx) {
|
|
||||||
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist SVG with directives 1`] = `
|
|
||||||
"const _Vue = Vue
|
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
|
@ -227,7 +215,9 @@ return function render(_ctx, _cache) {
|
||||||
const _directive_foo = _resolveDirective("foo")
|
const _directive_foo = _resolveDirective("foo")
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, [
|
return (_openBlock(), _createElementBlock("div", null, [
|
||||||
_withDirectives((_openBlock(), _createElementBlock("svg", null, _hoisted_2)), [
|
_withDirectives((_openBlock(), _createElementBlock("svg", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* CACHED */)
|
||||||
|
]))), [
|
||||||
[_directive_foo]
|
[_directive_foo]
|
||||||
])
|
])
|
||||||
]))
|
]))
|
||||||
|
@ -235,7 +225,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist elements with cached handlers + other bindings 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > should NOT cache elements with cached handlers + other bindings 1`] = `
|
||||||
"import { normalizeClass as _normalizeClass, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
"import { normalizeClass as _normalizeClass, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
|
@ -250,7 +240,7 @@ export function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist elements with cached handlers 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > should NOT cache elements with cached handlers 1`] = `
|
||||||
"import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
"import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
|
@ -264,7 +254,7 @@ export function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist expressions that refer scope variables (2) 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > should NOT cache expressions that refer scope variables (2) 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
|
@ -282,7 +272,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist expressions that refer scope variables (v-slot) 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > should NOT cache expressions that refer scope variables (v-slot) 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
|
@ -301,7 +291,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist expressions that refer scope variables 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > should NOT cache expressions that refer scope variables 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
|
@ -319,7 +309,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > prefixIdentifiers > should NOT hoist keyed template v-for with plain element child 1`] = `
|
exports[`compiler: cacheStatic transform > prefixIdentifiers > should NOT cache keyed template v-for with plain element child 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
|
@ -335,7 +325,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > should NOT hoist components 1`] = `
|
exports[`compiler: cacheStatic transform > should NOT cache components 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
|
@ -351,7 +341,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > should NOT hoist element with dynamic key 1`] = `
|
exports[`compiler: cacheStatic transform > should NOT cache element with dynamic key 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
|
@ -365,7 +355,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > should NOT hoist element with dynamic props (but hoist the props list) 1`] = `
|
exports[`compiler: cacheStatic transform > should NOT cache element with dynamic props (but hoist the props list) 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
const { createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
@ -382,7 +372,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > should NOT hoist element with dynamic ref 1`] = `
|
exports[`compiler: cacheStatic transform > should NOT cache element with dynamic ref 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
|
@ -396,42 +386,7 @@ return function render(_ctx, _cache) {
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > should NOT hoist root node 1`] = `
|
exports[`compiler: cacheStatic transform > should cache v-if props/children if static 1`] = `
|
||||||
"const _Vue = Vue
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
|
||||||
with (_ctx) {
|
|
||||||
const { openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div"))
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > should hoist v-for children if static 1`] = `
|
|
||||||
"const _Vue = Vue
|
|
||||||
const { createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
const _hoisted_1 = { id: "foo" }
|
|
||||||
const _hoisted_2 = /*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_3 = [
|
|
||||||
_hoisted_2
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
|
||||||
with (_ctx) {
|
|
||||||
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode } = _Vue
|
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, [
|
|
||||||
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => {
|
|
||||||
return (_openBlock(), _createElementBlock("div", _hoisted_1, _hoisted_3))
|
|
||||||
}), 256 /* UNKEYED_FRAGMENT */))
|
|
||||||
]))
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`compiler: hoistStatic transform > should hoist v-if props/children if static 1`] = `
|
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue
|
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue
|
||||||
|
|
||||||
|
@ -439,10 +394,6 @@ const _hoisted_1 = {
|
||||||
key: 0,
|
key: 0,
|
||||||
id: "foo"
|
id: "foo"
|
||||||
}
|
}
|
||||||
const _hoisted_2 = /*#__PURE__*/_createElementVNode("span", null, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_3 = [
|
|
||||||
_hoisted_2
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
with (_ctx) {
|
with (_ctx) {
|
||||||
|
@ -450,9 +401,32 @@ return function render(_ctx, _cache) {
|
||||||
|
|
||||||
return (_openBlock(), _createElementBlock("div", null, [
|
return (_openBlock(), _createElementBlock("div", null, [
|
||||||
ok
|
ok
|
||||||
? (_openBlock(), _createElementBlock("div", _hoisted_1, _hoisted_3))
|
? (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("span", null, null, -1 /* CACHED */)
|
||||||
|
])))
|
||||||
: _createCommentVNode("v-if", true)
|
: _createCommentVNode("v-if", true)
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: cacheStatic transform > should hoist v-for children if static 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
const { createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
const _hoisted_1 = { id: "foo" }
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
with (_ctx) {
|
||||||
|
const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, createElementVNode: _createElementVNode } = _Vue
|
||||||
|
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, [
|
||||||
|
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => {
|
||||||
|
return (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("span", null, null, -1 /* CACHED */)
|
||||||
|
])))
|
||||||
|
}), 256 /* UNKEYED_FRAGMENT */))
|
||||||
|
]))
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
|
@ -25,18 +25,33 @@ import { createObjectMatcher, genFlagText } from '../testUtils'
|
||||||
import { transformText } from '../../src/transforms/transformText'
|
import { transformText } from '../../src/transforms/transformText'
|
||||||
import { PatchFlags } from '@vue/shared'
|
import { PatchFlags } from '@vue/shared'
|
||||||
|
|
||||||
const hoistedChildrenArrayMatcher = (startIndex = 1, length = 1) => ({
|
const cachedChildrenArrayMatcher = (
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
tags: string[],
|
||||||
elements: new Array(length).fill(0).map((_, i) => ({
|
needArraySpread = false,
|
||||||
type: NodeTypes.ELEMENT,
|
) => ({
|
||||||
codegenNode: {
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
needArraySpread,
|
||||||
content: `_hoisted_${startIndex + i}`,
|
value: {
|
||||||
},
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
})),
|
elements: tags.map(tag => {
|
||||||
|
if (tag === '') {
|
||||||
|
return {
|
||||||
|
type: NodeTypes.TEXT_CALL,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
type: NodeTypes.ELEMENT,
|
||||||
|
codegenNode: {
|
||||||
|
type: NodeTypes.VNODE_CALL,
|
||||||
|
tag: JSON.stringify(tag),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
function transformWithHoist(template: string, options: CompilerOptions = {}) {
|
function transformWithCache(template: string, options: CompilerOptions = {}) {
|
||||||
const ast = parse(template)
|
const ast = parse(template)
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
hoistStatic: true,
|
hoistStatic: true,
|
||||||
|
@ -60,101 +75,253 @@ function transformWithHoist(template: string, options: CompilerOptions = {}) {
|
||||||
return ast
|
return ast
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('compiler: hoistStatic transform', () => {
|
describe('compiler: cacheStatic transform', () => {
|
||||||
test('should NOT hoist root node', () => {
|
test('should NOT cache root node', () => {
|
||||||
// if the whole tree is static, the root still needs to be a block
|
// if the whole tree is static, the root still needs to be a block
|
||||||
// so that it's patched in optimized mode to skip children
|
// so that it's patched in optimized mode to skip children
|
||||||
const root = transformWithHoist(`<div/>`)
|
const root = transformWithCache(`<div/>`)
|
||||||
expect(root.hoists.length).toBe(0)
|
|
||||||
expect(root.codegenNode).toMatchObject({
|
expect(root.codegenNode).toMatchObject({
|
||||||
|
type: NodeTypes.VNODE_CALL,
|
||||||
tag: `"div"`,
|
tag: `"div"`,
|
||||||
})
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(root.cached.length).toBe(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist simple element', () => {
|
test('cache root node children', () => {
|
||||||
const root = transformWithHoist(
|
// we don't have access to the root codegenNode during the transform
|
||||||
|
// so we only cache each child individually
|
||||||
|
const root = transformWithCache(
|
||||||
|
`<span class="inline">hello</span><span class="inline">hello</span>`,
|
||||||
|
)
|
||||||
|
expect(root.codegenNode).toMatchObject({
|
||||||
|
type: NodeTypes.VNODE_CALL,
|
||||||
|
children: [
|
||||||
|
{ codegenNode: { type: NodeTypes.JS_CACHE_EXPRESSION } },
|
||||||
|
{ codegenNode: { type: NodeTypes.JS_CACHE_EXPRESSION } },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
expect(root.cached.length).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('cache single children array', () => {
|
||||||
|
const root = transformWithCache(
|
||||||
`<div><span class="inline">hello</span></div>`,
|
`<div><span class="inline">hello</span></div>`,
|
||||||
)
|
)
|
||||||
expect(root.hoists).toMatchObject([
|
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"span"`,
|
|
||||||
props: createObjectMatcher({ class: 'inline' }),
|
|
||||||
children: {
|
|
||||||
type: NodeTypes.TEXT,
|
|
||||||
content: `hello`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(),
|
|
||||||
])
|
|
||||||
expect(root.codegenNode).toMatchObject({
|
expect(root.codegenNode).toMatchObject({
|
||||||
tag: `"div"`,
|
tag: `"div"`,
|
||||||
props: undefined,
|
props: undefined,
|
||||||
children: { content: `_hoisted_2` },
|
children: cachedChildrenArrayMatcher(['span']),
|
||||||
})
|
})
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist nested static tree', () => {
|
test('cache nested children array', () => {
|
||||||
const root = transformWithHoist(`<div><p><span/><span/></p></div>`)
|
const root = transformWithCache(
|
||||||
expect(root.hoists).toMatchObject([
|
`<div><p><span/><span/></p><p><span/><span/></p></div>`,
|
||||||
{
|
)
|
||||||
type: NodeTypes.VNODE_CALL,
|
expect((root.codegenNode as VNodeCall).children).toMatchObject(
|
||||||
tag: `"p"`,
|
cachedChildrenArrayMatcher(['p', 'p']),
|
||||||
props: undefined,
|
)
|
||||||
children: [
|
expect(root.cached.length).toBe(1)
|
||||||
{ type: NodeTypes.ELEMENT, tag: `span` },
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
{ type: NodeTypes.ELEMENT, tag: `span` },
|
})
|
||||||
],
|
|
||||||
},
|
test('cache nested static tree with comments', () => {
|
||||||
hoistedChildrenArrayMatcher(),
|
const root = transformWithCache(`<div><div><!--comment--></div></div>`)
|
||||||
])
|
expect((root.codegenNode as VNodeCall).children).toMatchObject(
|
||||||
|
cachedChildrenArrayMatcher(['div']),
|
||||||
|
)
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('cache siblings including text with common non-hoistable parent', () => {
|
||||||
|
const root = transformWithCache(`<div><span/>foo<div/></div>`)
|
||||||
|
expect((root.codegenNode as VNodeCall).children).toMatchObject(
|
||||||
|
cachedChildrenArrayMatcher(['span', '', 'div']),
|
||||||
|
)
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('cache inside default slot', () => {
|
||||||
|
const root = transformWithCache(`<Foo>{{x}}<span/></Foo>`)
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
||||||
content: '_hoisted_2',
|
properties: [
|
||||||
|
{
|
||||||
|
key: { content: 'default' },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
returns: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.TEXT_CALL,
|
||||||
|
},
|
||||||
|
// first slot child cached
|
||||||
|
{
|
||||||
|
type: NodeTypes.ELEMENT,
|
||||||
|
codegenNode: {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* _ slot flag */
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist nested static tree with comments', () => {
|
test('cache default slot as a whole', () => {
|
||||||
const root = transformWithHoist(`<div><div><!--comment--></div></div>`)
|
const root = transformWithCache(`<Foo><span/><span/></Foo>`)
|
||||||
expect(root.hoists).toMatchObject([
|
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"div"`,
|
|
||||||
props: undefined,
|
|
||||||
children: [{ type: NodeTypes.COMMENT, content: `comment` }],
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(),
|
|
||||||
])
|
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
||||||
content: `_hoisted_2`,
|
properties: [
|
||||||
|
{
|
||||||
|
key: { content: 'default' },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
returns: {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
|
elements: [
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* _ slot flag */
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist siblings with common non-hoistable parent', () => {
|
test('cache inside named slot', () => {
|
||||||
const root = transformWithHoist(`<div><span/><div/></div>`)
|
const root = transformWithCache(
|
||||||
expect(root.hoists).toMatchObject([
|
`<Foo><template #foo>{{x}}<span/></template></Foo>`,
|
||||||
{
|
)
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"span"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"div"`,
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(1, 2),
|
|
||||||
])
|
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
||||||
content: '_hoisted_3',
|
properties: [
|
||||||
|
{
|
||||||
|
key: { content: 'foo' },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
returns: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.TEXT_CALL,
|
||||||
|
},
|
||||||
|
// first slot child cached
|
||||||
|
{
|
||||||
|
type: NodeTypes.ELEMENT,
|
||||||
|
codegenNode: {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* _ slot flag */
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist components', () => {
|
test('cache named slot as a whole', () => {
|
||||||
const root = transformWithHoist(`<div><Comp/></div>`)
|
const root = transformWithCache(
|
||||||
expect(root.hoists.length).toBe(0)
|
`<Foo><template #foo><span/><span/></template></Foo>`,
|
||||||
|
)
|
||||||
|
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: { content: 'foo' },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
returns: {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
|
elements: [
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* _ slot flag */
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('cache dynamically named slot as a whole', () => {
|
||||||
|
const root = transformWithCache(
|
||||||
|
`<Foo><template #[foo]><span/><span/></template></Foo>`,
|
||||||
|
)
|
||||||
|
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: { content: 'foo', isStatic: false },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
returns: {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
|
elements: [
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* _ slot flag */
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('cache dynamically named (expression) slot as a whole', () => {
|
||||||
|
const root = transformWithCache(
|
||||||
|
`<Foo><template #[foo+1]><span/><span/></template></Foo>`,
|
||||||
|
{ prefixIdentifiers: true },
|
||||||
|
)
|
||||||
|
expect((root.codegenNode as VNodeCall).children).toMatchObject({
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: { type: NodeTypes.COMPOUND_EXPRESSION },
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
|
returns: {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
|
elements: [
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
{ type: NodeTypes.ELEMENT },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* _ slot flag */
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should NOT cache components', () => {
|
||||||
|
const root = transformWithCache(`<div><Comp/></div>`)
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
||||||
{
|
{
|
||||||
type: NodeTypes.ELEMENT,
|
type: NodeTypes.ELEMENT,
|
||||||
|
@ -164,11 +331,12 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist element with dynamic props (but hoist the props list)', () => {
|
test('should NOT cache element with dynamic props (but hoist the props list)', () => {
|
||||||
const root = transformWithHoist(`<div><div :id="foo"/></div>`)
|
const root = transformWithCache(`<div><div :id="foo"/></div>`)
|
||||||
expect(root.hoists.length).toBe(1)
|
expect(root.hoists.length).toBe(1)
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
||||||
{
|
{
|
||||||
|
@ -189,31 +357,23 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist element with static key', () => {
|
test('cache element with static key', () => {
|
||||||
const root = transformWithHoist(`<div><div key="foo"/></div>`)
|
const root = transformWithCache(`<div><div key="foo"/></div>`)
|
||||||
expect(root.hoists.length).toBe(2)
|
|
||||||
expect(root.hoists).toMatchObject([
|
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"div"`,
|
|
||||||
props: createObjectMatcher({ key: 'foo' }),
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(),
|
|
||||||
])
|
|
||||||
expect(root.codegenNode).toMatchObject({
|
expect(root.codegenNode).toMatchObject({
|
||||||
tag: `"div"`,
|
tag: `"div"`,
|
||||||
props: undefined,
|
props: undefined,
|
||||||
children: { content: `_hoisted_2` },
|
children: cachedChildrenArrayMatcher(['div']),
|
||||||
})
|
})
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist element with dynamic key', () => {
|
test('should NOT cache element with dynamic key', () => {
|
||||||
const root = transformWithHoist(`<div><div :key="foo"/></div>`)
|
const root = transformWithCache(`<div><div :key="foo"/></div>`)
|
||||||
expect(root.hoists.length).toBe(0)
|
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
||||||
{
|
{
|
||||||
type: NodeTypes.ELEMENT,
|
type: NodeTypes.ELEMENT,
|
||||||
|
@ -226,12 +386,12 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist element with dynamic ref', () => {
|
test('should NOT cache element with dynamic ref', () => {
|
||||||
const root = transformWithHoist(`<div><div :ref="foo"/></div>`)
|
const root = transformWithCache(`<div><div :ref="foo"/></div>`)
|
||||||
expect(root.hoists.length).toBe(0)
|
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
||||||
{
|
{
|
||||||
type: NodeTypes.ELEMENT,
|
type: NodeTypes.ELEMENT,
|
||||||
|
@ -246,11 +406,12 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist static props for elements with directives', () => {
|
test('hoist static props for elements with directives', () => {
|
||||||
const root = transformWithHoist(`<div><div id="foo" v-foo/></div>`)
|
const root = transformWithCache(`<div><div id="foo" v-foo/></div>`)
|
||||||
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'foo' })])
|
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'foo' })])
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
||||||
{
|
{
|
||||||
|
@ -270,11 +431,12 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist static props for elements with dynamic text children', () => {
|
test('hoist static props for elements with dynamic text children', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><div id="foo">{{ hello }}</div></div>`,
|
`<div><div id="foo">{{ hello }}</div></div>`,
|
||||||
)
|
)
|
||||||
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'foo' })])
|
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'foo' })])
|
||||||
|
@ -290,11 +452,12 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist static props for elements with unhoistable children', () => {
|
test('hoist static props for elements with unhoistable children', () => {
|
||||||
const root = transformWithHoist(`<div><div id="foo"><Comp/></div></div>`)
|
const root = transformWithCache(`<div><div id="foo"><Comp/></div></div>`)
|
||||||
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'foo' })])
|
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'foo' })])
|
||||||
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
||||||
{
|
{
|
||||||
|
@ -307,11 +470,12 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should hoist v-if props/children if static', () => {
|
test('should cache v-if props/children if static', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><div v-if="ok" id="foo"><span/></div></div>`,
|
`<div><div v-if="ok" id="foo"><span/></div></div>`,
|
||||||
)
|
)
|
||||||
expect(root.hoists).toMatchObject([
|
expect(root.hoists).toMatchObject([
|
||||||
|
@ -319,40 +483,31 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
key: `[0]`, // key injected by v-if branch
|
key: `[0]`, // key injected by v-if branch
|
||||||
id: 'foo',
|
id: 'foo',
|
||||||
}),
|
}),
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"span"`,
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(2),
|
|
||||||
])
|
])
|
||||||
expect(
|
expect(
|
||||||
((root.children[0] as ElementNode).children[0] as IfNode).codegenNode,
|
((root.children[0] as ElementNode).children[0] as IfNode).codegenNode,
|
||||||
).toMatchObject({
|
).toMatchObject({
|
||||||
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
|
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
|
||||||
consequent: {
|
consequent: {
|
||||||
// blocks should NOT be hoisted
|
// blocks should NOT be cached
|
||||||
type: NodeTypes.VNODE_CALL,
|
type: NodeTypes.VNODE_CALL,
|
||||||
tag: `"div"`,
|
tag: `"div"`,
|
||||||
props: { content: `_hoisted_1` },
|
props: { content: `_hoisted_1` },
|
||||||
children: { content: `_hoisted_3` },
|
children: cachedChildrenArrayMatcher(['span']),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should hoist v-for children if static', () => {
|
test('should hoist v-for children if static', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><div v-for="i in list" id="foo"><span/></div></div>`,
|
`<div><div v-for="i in list" id="foo"><span/></div></div>`,
|
||||||
)
|
)
|
||||||
expect(root.hoists).toMatchObject([
|
expect(root.hoists).toMatchObject([
|
||||||
createObjectMatcher({
|
createObjectMatcher({
|
||||||
id: 'foo',
|
id: 'foo',
|
||||||
}),
|
}),
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"span"`,
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(2),
|
|
||||||
])
|
])
|
||||||
const forBlockCodegen = (
|
const forBlockCodegen = (
|
||||||
(root.children[0] as ElementNode).children[0] as ForNode
|
(root.children[0] as ElementNode).children[0] as ForNode
|
||||||
|
@ -372,78 +527,47 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
type: NodeTypes.VNODE_CALL,
|
type: NodeTypes.VNODE_CALL,
|
||||||
tag: `"div"`,
|
tag: `"div"`,
|
||||||
props: { content: `_hoisted_1` },
|
props: { content: `_hoisted_1` },
|
||||||
children: { content: `_hoisted_3` },
|
children: cachedChildrenArrayMatcher(['span']),
|
||||||
})
|
})
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('prefixIdentifiers', () => {
|
describe('prefixIdentifiers', () => {
|
||||||
test('hoist nested static tree with static interpolation', () => {
|
test('cache nested static tree with static interpolation', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><span>foo {{ 1 }} {{ true }}</span></div>`,
|
`<div><span>foo {{ 1 }} {{ true }}</span></div>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
expect(root.hoists).toMatchObject([
|
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"span"`,
|
|
||||||
props: undefined,
|
|
||||||
children: {
|
|
||||||
type: NodeTypes.COMPOUND_EXPRESSION,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(),
|
|
||||||
])
|
|
||||||
expect(root.codegenNode).toMatchObject({
|
expect(root.codegenNode).toMatchObject({
|
||||||
tag: `"div"`,
|
tag: `"div"`,
|
||||||
props: undefined,
|
props: undefined,
|
||||||
children: {
|
children: cachedChildrenArrayMatcher(['span']),
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
|
||||||
content: `_hoisted_2`,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist nested static tree with static prop value', () => {
|
test('cache nested static tree with static prop value', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><span :foo="0">{{ 1 }}</span></div>`,
|
`<div><span :foo="0">{{ 1 }}</span></div>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(root.hoists).toMatchObject([
|
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
tag: `"span"`,
|
|
||||||
props: createObjectMatcher({ foo: `[0]` }),
|
|
||||||
children: {
|
|
||||||
type: NodeTypes.INTERPOLATION,
|
|
||||||
content: {
|
|
||||||
content: `1`,
|
|
||||||
isStatic: false,
|
|
||||||
constType: ConstantTypes.CAN_STRINGIFY,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hoistedChildrenArrayMatcher(),
|
|
||||||
])
|
|
||||||
expect(root.codegenNode).toMatchObject({
|
expect(root.codegenNode).toMatchObject({
|
||||||
tag: `"div"`,
|
tag: `"div"`,
|
||||||
props: undefined,
|
props: undefined,
|
||||||
children: {
|
children: cachedChildrenArrayMatcher(['span']),
|
||||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
|
||||||
content: `_hoisted_2`,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('hoist class with static object value', () => {
|
test('hoist class with static object value', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><span :class="{ foo: true }">{{ bar }}</span></div>`,
|
`<div><span :class="{ foo: true }">{{ bar }}</span></div>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
|
@ -504,44 +628,44 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist expressions that refer scope variables', () => {
|
test('should NOT cache expressions that refer scope variables', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><p v-for="o in list"><span>{{ o }}</span></p></div>`,
|
`<div><p v-for="o in list"><span>{{ o }}</span></p></div>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(root.hoists.length).toBe(0)
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist expressions that refer scope variables (2)', () => {
|
test('should NOT cache expressions that refer scope variables (2)', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><p v-for="o in list"><span>{{ o + 'foo' }}</span></p></div>`,
|
`<div><p v-for="o in list"><span>{{ o + 'foo' }}</span></p></div>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(root.hoists.length).toBe(0)
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist expressions that refer scope variables (v-slot)', () => {
|
test('should NOT cache expressions that refer scope variables (v-slot)', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<Comp v-slot="{ foo }">{{ foo }}</Comp>`,
|
`<Comp v-slot="{ foo }">{{ foo }}</Comp>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(root.hoists.length).toBe(0)
|
expect(root.cached.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist elements with cached handlers', () => {
|
test('should NOT cache elements with cached handlers', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><div><div @click="foo"/></div></div>`,
|
`<div><div><div @click="foo"/></div></div>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
|
@ -549,7 +673,7 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.hoists.length).toBe(0)
|
expect(root.hoists.length).toBe(0)
|
||||||
expect(
|
expect(
|
||||||
generate(root, {
|
generate(root, {
|
||||||
|
@ -559,8 +683,8 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
).toMatchSnapshot()
|
).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist elements with cached handlers + other bindings', () => {
|
test('should NOT cache elements with cached handlers + other bindings', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><div><div :class="{}" @click="foo"/></div></div>`,
|
`<div><div><div :class="{}" @click="foo"/></div></div>`,
|
||||||
{
|
{
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
|
@ -568,7 +692,7 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.hoists.length).toBe(0)
|
expect(root.hoists.length).toBe(0)
|
||||||
expect(
|
expect(
|
||||||
generate(root, {
|
generate(root, {
|
||||||
|
@ -578,32 +702,66 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
).toMatchSnapshot()
|
).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist keyed template v-for with plain element child', () => {
|
test('should NOT cache keyed template v-for with plain element child', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><template v-for="item in items" :key="item"><span/></template></div>`,
|
`<div><template v-for="item in items" :key="item"><span/></template></div>`,
|
||||||
)
|
)
|
||||||
expect(root.hoists.length).toBe(0)
|
expect(root.hoists.length).toBe(0)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should NOT hoist SVG with directives', () => {
|
test('should NOT cache SVG with directives', () => {
|
||||||
const root = transformWithHoist(
|
const root = transformWithCache(
|
||||||
`<div><svg v-foo><path d="M2,3H5.5L12"/></svg></div>`,
|
`<div><svg v-foo><path d="M2,3H5.5L12"/></svg></div>`,
|
||||||
)
|
)
|
||||||
expect(root.hoists.length).toBe(2)
|
expect(root.cached.length).toBe(1)
|
||||||
|
expect(root.codegenNode).toMatchObject({
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
tag: 'svg',
|
||||||
|
// only cache the children, not the svg tag itself
|
||||||
|
codegenNode: {
|
||||||
|
children: {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('clone hoisted array children in HMR mode', () => {
|
test('clone hoisted array children in v-for + HMR mode', () => {
|
||||||
const root = transformWithHoist(`<div><span class="hi"></span></div>`, {
|
const root = transformWithCache(
|
||||||
hmr: true,
|
`<div><div v-for="i in 1"><span class="hi"></span></div></div>`,
|
||||||
})
|
{
|
||||||
expect(root.hoists.length).toBe(2)
|
hmr: true,
|
||||||
expect(root.codegenNode).toMatchObject({
|
|
||||||
children: {
|
|
||||||
content: '[..._hoisted_2]',
|
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
expect(root.cached.length).toBe(1)
|
||||||
|
const forBlockCodegen = (
|
||||||
|
(root.children[0] as ElementNode).children[0] as ForNode
|
||||||
|
).codegenNode
|
||||||
|
expect(forBlockCodegen).toMatchObject({
|
||||||
|
type: NodeTypes.VNODE_CALL,
|
||||||
|
tag: FRAGMENT,
|
||||||
|
props: undefined,
|
||||||
|
children: {
|
||||||
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
|
callee: RENDER_LIST,
|
||||||
|
},
|
||||||
|
patchFlag: genFlagText(PatchFlags.UNKEYED_FRAGMENT),
|
||||||
})
|
})
|
||||||
|
const innerBlockCodegen = forBlockCodegen!.children.arguments[1]
|
||||||
|
expect(innerBlockCodegen.returns).toMatchObject({
|
||||||
|
type: NodeTypes.VNODE_CALL,
|
||||||
|
tag: `"div"`,
|
||||||
|
children: cachedChildrenArrayMatcher(
|
||||||
|
['span'],
|
||||||
|
true /* needArraySpread */,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
|
@ -399,7 +399,7 @@ describe('compiler: transform v-model', () => {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const codegen = (root.children[0] as PlainElementNode)
|
const codegen = (root.children[0] as PlainElementNode)
|
||||||
.codegenNode as VNodeCall
|
.codegenNode as VNodeCall
|
||||||
// should not list cached prop in dynamicProps
|
// should not list cached prop in dynamicProps
|
||||||
|
@ -417,7 +417,7 @@ describe('compiler: transform v-model', () => {
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
expect(root.cached).toBe(0)
|
expect(root.cached.length).toBe(0)
|
||||||
const codegen = (
|
const codegen = (
|
||||||
(root.children[0] as ForNode).children[0] as PlainElementNode
|
(root.children[0] as ForNode).children[0] as PlainElementNode
|
||||||
).codegenNode as VNodeCall
|
).codegenNode as VNodeCall
|
||||||
|
@ -433,7 +433,7 @@ describe('compiler: transform v-model', () => {
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).not.toBe(2)
|
expect(root.cached).not.toBe(2)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should mark update handler dynamic if it refers slot scope variables', () => {
|
test('should mark update handler dynamic if it refers slot scope variables', () => {
|
||||||
|
|
|
@ -504,7 +504,7 @@ describe('compiler: transform v-on', () => {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
@ -525,7 +525,7 @@ describe('compiler: transform v-on', () => {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
@ -550,7 +550,7 @@ describe('compiler: transform v-on', () => {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
@ -587,7 +587,7 @@ describe('compiler: transform v-on', () => {
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
isNativeTag: tag => tag === 'div',
|
isNativeTag: tag => tag === 'div',
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(0)
|
expect(root.cached.length).toBe(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should not be cached inside v-once', () => {
|
test('should not be cached inside v-once', () => {
|
||||||
|
@ -599,7 +599,7 @@ describe('compiler: transform v-on', () => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
expect(root.cached).not.toBe(2)
|
expect(root.cached).not.toBe(2)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('inline function expression handler', () => {
|
test('inline function expression handler', () => {
|
||||||
|
@ -607,7 +607,7 @@ describe('compiler: transform v-on', () => {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
@ -631,7 +631,7 @@ describe('compiler: transform v-on', () => {
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
@ -656,7 +656,7 @@ describe('compiler: transform v-on', () => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
@ -688,7 +688,7 @@ describe('compiler: transform v-on', () => {
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
@ -713,8 +713,8 @@ describe('compiler: transform v-on', () => {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
const vnodeCall = node.codegenNode as VNodeCall
|
const vnodeCall = node.codegenNode as VNodeCall
|
||||||
// should not treat cached handler as dynamicProp, so no flags
|
// should not treat cached handler as dynamicProp, so no flags
|
||||||
expect(vnodeCall.patchFlag).toBeUndefined()
|
expect(vnodeCall.patchFlag).toBeUndefined()
|
||||||
|
|
|
@ -22,7 +22,7 @@ function transformWithOnce(template: string, options: CompilerOptions = {}) {
|
||||||
describe('compiler: v-once transform', () => {
|
describe('compiler: v-once transform', () => {
|
||||||
test('as root node', () => {
|
test('as root node', () => {
|
||||||
const root = transformWithOnce(`<div :id="foo" v-once />`)
|
const root = transformWithOnce(`<div :id="foo" v-once />`)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||||
expect(root.codegenNode).toMatchObject({
|
expect(root.codegenNode).toMatchObject({
|
||||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
@ -37,7 +37,7 @@ describe('compiler: v-once transform', () => {
|
||||||
|
|
||||||
test('on nested plain element', () => {
|
test('on nested plain element', () => {
|
||||||
const root = transformWithOnce(`<div><div :id="foo" v-once /></div>`)
|
const root = transformWithOnce(`<div><div :id="foo" v-once /></div>`)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
@ -52,7 +52,7 @@ describe('compiler: v-once transform', () => {
|
||||||
|
|
||||||
test('on component', () => {
|
test('on component', () => {
|
||||||
const root = transformWithOnce(`<div><Comp :id="foo" v-once /></div>`)
|
const root = transformWithOnce(`<div><Comp :id="foo" v-once /></div>`)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
@ -67,7 +67,7 @@ describe('compiler: v-once transform', () => {
|
||||||
|
|
||||||
test('on slot outlet', () => {
|
test('on slot outlet', () => {
|
||||||
const root = transformWithOnce(`<div><slot v-once /></div>`)
|
const root = transformWithOnce(`<div><slot v-once /></div>`)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
@ -84,7 +84,7 @@ describe('compiler: v-once transform', () => {
|
||||||
test('inside v-once', () => {
|
test('inside v-once', () => {
|
||||||
const root = transformWithOnce(`<div v-once><div v-once/></div>`)
|
const root = transformWithOnce(`<div v-once><div v-once/></div>`)
|
||||||
expect(root.cached).not.toBe(2)
|
expect(root.cached).not.toBe(2)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
// cached nodes should be ignored by hoistStatic transform
|
// cached nodes should be ignored by hoistStatic transform
|
||||||
|
@ -92,7 +92,7 @@ describe('compiler: v-once transform', () => {
|
||||||
const root = transformWithOnce(`<div><div v-once /></div>`, {
|
const root = transformWithOnce(`<div><div v-once /></div>`, {
|
||||||
hoistStatic: true,
|
hoistStatic: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||||
expect(root.hoists.length).toBe(0)
|
expect(root.hoists.length).toBe(0)
|
||||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||||
|
@ -108,7 +108,7 @@ describe('compiler: v-once transform', () => {
|
||||||
|
|
||||||
test('with v-if/else', () => {
|
test('with v-if/else', () => {
|
||||||
const root = transformWithOnce(`<div v-if="BOOLEAN" v-once /><p v-else/>`)
|
const root = transformWithOnce(`<div v-if="BOOLEAN" v-once /><p v-else/>`)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||||
expect(root.children[0]).toMatchObject({
|
expect(root.children[0]).toMatchObject({
|
||||||
type: NodeTypes.IF,
|
type: NodeTypes.IF,
|
||||||
|
@ -132,7 +132,7 @@ describe('compiler: v-once transform', () => {
|
||||||
|
|
||||||
test('with v-for', () => {
|
test('with v-for', () => {
|
||||||
const root = transformWithOnce(`<div v-for="i in list" v-once />`)
|
const root = transformWithOnce(`<div v-for="i in list" v-once />`)
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||||
expect(root.children[0]).toMatchObject({
|
expect(root.children[0]).toMatchObject({
|
||||||
type: NodeTypes.FOR,
|
type: NodeTypes.FOR,
|
||||||
|
|
|
@ -110,7 +110,7 @@ export interface RootNode extends Node {
|
||||||
directives: string[]
|
directives: string[]
|
||||||
hoists: (JSChildNode | null)[]
|
hoists: (JSChildNode | null)[]
|
||||||
imports: ImportItem[]
|
imports: ImportItem[]
|
||||||
cached: number
|
cached: (CacheExpression | null)[]
|
||||||
temps: number
|
temps: number
|
||||||
ssrHelpers?: symbol[]
|
ssrHelpers?: symbol[]
|
||||||
codegenNode?: TemplateChildNode | JSChildNode | BlockStatement
|
codegenNode?: TemplateChildNode | JSChildNode | BlockStatement
|
||||||
|
@ -218,7 +218,7 @@ export interface DirectiveNode extends Node {
|
||||||
export enum ConstantTypes {
|
export enum ConstantTypes {
|
||||||
NOT_CONSTANT = 0,
|
NOT_CONSTANT = 0,
|
||||||
CAN_SKIP_PATCH,
|
CAN_SKIP_PATCH,
|
||||||
CAN_HOIST,
|
CAN_CACHE,
|
||||||
CAN_STRINGIFY,
|
CAN_STRINGIFY,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +330,7 @@ export interface VNodeCall extends Node {
|
||||||
| SlotsExpression // component slots
|
| SlotsExpression // component slots
|
||||||
| ForRenderListExpression // v-for fragment call
|
| ForRenderListExpression // v-for fragment call
|
||||||
| SimpleExpressionNode // hoisted
|
| SimpleExpressionNode // hoisted
|
||||||
|
| CacheExpression // cached
|
||||||
| undefined
|
| undefined
|
||||||
patchFlag: string | undefined
|
patchFlag: string | undefined
|
||||||
dynamicProps: string | SimpleExpressionNode | undefined
|
dynamicProps: string | SimpleExpressionNode | undefined
|
||||||
|
@ -416,7 +417,8 @@ export interface CacheExpression extends Node {
|
||||||
type: NodeTypes.JS_CACHE_EXPRESSION
|
type: NodeTypes.JS_CACHE_EXPRESSION
|
||||||
index: number
|
index: number
|
||||||
value: JSChildNode
|
value: JSChildNode
|
||||||
isVNode: boolean
|
needPauseTracking: boolean
|
||||||
|
needArraySpread: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MemoExpression extends CallExpression {
|
export interface MemoExpression extends CallExpression {
|
||||||
|
@ -511,7 +513,7 @@ export interface SlotsObjectProperty extends Property {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SlotFunctionExpression extends FunctionExpression {
|
export interface SlotFunctionExpression extends FunctionExpression {
|
||||||
returns: TemplateChildNode[]
|
returns: TemplateChildNode[] | CacheExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
// createSlots({ ... }, [
|
// createSlots({ ... }, [
|
||||||
|
@ -598,7 +600,7 @@ export function createRoot(
|
||||||
directives: [],
|
directives: [],
|
||||||
hoists: [],
|
hoists: [],
|
||||||
imports: [],
|
imports: [],
|
||||||
cached: 0,
|
cached: [],
|
||||||
temps: 0,
|
temps: 0,
|
||||||
codegenNode: undefined,
|
codegenNode: undefined,
|
||||||
loc: locStub,
|
loc: locStub,
|
||||||
|
@ -771,13 +773,14 @@ export function createConditionalExpression(
|
||||||
export function createCacheExpression(
|
export function createCacheExpression(
|
||||||
index: number,
|
index: number,
|
||||||
value: JSChildNode,
|
value: JSChildNode,
|
||||||
isVNode: boolean = false,
|
needPauseTracking: boolean = false,
|
||||||
): CacheExpression {
|
): CacheExpression {
|
||||||
return {
|
return {
|
||||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
index,
|
index,
|
||||||
value,
|
value,
|
||||||
isVNode,
|
needPauseTracking: needPauseTracking,
|
||||||
|
needArraySpread: false,
|
||||||
loc: locStub,
|
loc: locStub,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,6 @@ import {
|
||||||
CREATE_TEXT,
|
CREATE_TEXT,
|
||||||
CREATE_VNODE,
|
CREATE_VNODE,
|
||||||
OPEN_BLOCK,
|
OPEN_BLOCK,
|
||||||
POP_SCOPE_ID,
|
|
||||||
PUSH_SCOPE_ID,
|
|
||||||
RESOLVE_COMPONENT,
|
RESOLVE_COMPONENT,
|
||||||
RESOLVE_DIRECTIVE,
|
RESOLVE_DIRECTIVE,
|
||||||
RESOLVE_FILTER,
|
RESOLVE_FILTER,
|
||||||
|
@ -473,11 +471,6 @@ function genModulePreamble(
|
||||||
ssrRuntimeModuleName,
|
ssrRuntimeModuleName,
|
||||||
} = context
|
} = context
|
||||||
|
|
||||||
if (genScopeId && ast.hoists.length) {
|
|
||||||
ast.helpers.add(PUSH_SCOPE_ID)
|
|
||||||
ast.helpers.add(POP_SCOPE_ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate import statements for helpers
|
// generate import statements for helpers
|
||||||
if (ast.helpers.size) {
|
if (ast.helpers.size) {
|
||||||
const helpers = Array.from(ast.helpers)
|
const helpers = Array.from(ast.helpers)
|
||||||
|
@ -566,33 +559,14 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
context.pure = true
|
context.pure = true
|
||||||
const { push, newline, helper, scopeId, mode } = context
|
const { push, newline } = context
|
||||||
const genScopeId = !__BROWSER__ && scopeId != null && mode !== 'function'
|
|
||||||
newline()
|
newline()
|
||||||
|
|
||||||
// generate inlined withScopeId helper
|
|
||||||
if (genScopeId) {
|
|
||||||
push(
|
|
||||||
`const _withScopeId = n => (${helper(
|
|
||||||
PUSH_SCOPE_ID,
|
|
||||||
)}("${scopeId}"),n=n(),${helper(POP_SCOPE_ID)}(),n)`,
|
|
||||||
)
|
|
||||||
newline()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < hoists.length; i++) {
|
for (let i = 0; i < hoists.length; i++) {
|
||||||
const exp = hoists[i]
|
const exp = hoists[i]
|
||||||
if (exp) {
|
if (exp) {
|
||||||
const needScopeIdWrapper = genScopeId && exp.type === NodeTypes.VNODE_CALL
|
push(`const _hoisted_${i + 1} = `)
|
||||||
push(
|
|
||||||
`const _hoisted_${i + 1} = ${
|
|
||||||
needScopeIdWrapper ? `${PURE_ANNOTATION} _withScopeId(() => ` : ``
|
|
||||||
}`,
|
|
||||||
)
|
|
||||||
genNode(exp, context)
|
genNode(exp, context)
|
||||||
if (needScopeIdWrapper) {
|
|
||||||
push(`)`)
|
|
||||||
}
|
|
||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1007,15 +981,19 @@ 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
|
||||||
|
const { needPauseTracking, needArraySpread } = node
|
||||||
|
if (needArraySpread) {
|
||||||
|
push(`[...(`)
|
||||||
|
}
|
||||||
push(`_cache[${node.index}] || (`)
|
push(`_cache[${node.index}] || (`)
|
||||||
if (node.isVNode) {
|
if (needPauseTracking) {
|
||||||
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 (needPauseTracking) {
|
||||||
push(`,`)
|
push(`,`)
|
||||||
newline()
|
newline()
|
||||||
push(`${helper(SET_BLOCK_TRACKING)}(1),`)
|
push(`${helper(SET_BLOCK_TRACKING)}(1),`)
|
||||||
|
@ -1024,6 +1002,9 @@ function genCacheExpression(node: CacheExpression, context: CodegenContext) {
|
||||||
deindent()
|
deindent()
|
||||||
}
|
}
|
||||||
push(`)`)
|
push(`)`)
|
||||||
|
if (needArraySpread) {
|
||||||
|
push(`)]`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function genTemplateLiteral(node: TemplateLiteral, context: CodegenContext) {
|
function genTemplateLiteral(node: TemplateLiteral, context: CodegenContext) {
|
||||||
|
|
|
@ -67,7 +67,7 @@ export {
|
||||||
type PropsExpression,
|
type PropsExpression,
|
||||||
} from './transforms/transformElement'
|
} from './transforms/transformElement'
|
||||||
export { processSlotOutlet } from './transforms/transformSlotOutlet'
|
export { processSlotOutlet } from './transforms/transformSlotOutlet'
|
||||||
export { getConstantType } from './transforms/hoistStatic'
|
export { getConstantType } from './transforms/cacheStatic'
|
||||||
export { generateCodeFrame } from '@vue/shared'
|
export { generateCodeFrame } from '@vue/shared'
|
||||||
|
|
||||||
// v2 compat only
|
// v2 compat only
|
||||||
|
|
|
@ -250,7 +250,7 @@ export interface TransformOptions
|
||||||
*/
|
*/
|
||||||
prefixIdentifiers?: boolean
|
prefixIdentifiers?: boolean
|
||||||
/**
|
/**
|
||||||
* Hoist static VNodes and props objects to `_hoisted_x` constants
|
* Cache static VNodes and props objects to `_hoisted_x` constants
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
hoistStatic?: boolean
|
hoistStatic?: boolean
|
||||||
|
|
|
@ -32,7 +32,14 @@ export const CAMELIZE = Symbol(__DEV__ ? `camelize` : ``)
|
||||||
export const CAPITALIZE = Symbol(__DEV__ ? `capitalize` : ``)
|
export const CAPITALIZE = Symbol(__DEV__ ? `capitalize` : ``)
|
||||||
export const TO_HANDLER_KEY = Symbol(__DEV__ ? `toHandlerKey` : ``)
|
export const TO_HANDLER_KEY = Symbol(__DEV__ ? `toHandlerKey` : ``)
|
||||||
export const SET_BLOCK_TRACKING = Symbol(__DEV__ ? `setBlockTracking` : ``)
|
export const SET_BLOCK_TRACKING = Symbol(__DEV__ ? `setBlockTracking` : ``)
|
||||||
|
/**
|
||||||
|
* @deprecated no longer needed in 3.5+ because we no longer hoist element nodes
|
||||||
|
* but kept for backwards compat
|
||||||
|
*/
|
||||||
export const PUSH_SCOPE_ID = Symbol(__DEV__ ? `pushScopeId` : ``)
|
export const PUSH_SCOPE_ID = Symbol(__DEV__ ? `pushScopeId` : ``)
|
||||||
|
/**
|
||||||
|
* @deprecated kept for backwards compat
|
||||||
|
*/
|
||||||
export const POP_SCOPE_ID = Symbol(__DEV__ ? `popScopeId` : ``)
|
export const POP_SCOPE_ID = Symbol(__DEV__ ? `popScopeId` : ``)
|
||||||
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
|
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
|
||||||
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
|
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
|
||||||
|
|
|
@ -38,7 +38,7 @@ import {
|
||||||
helperNameMap,
|
helperNameMap,
|
||||||
} from './runtimeHelpers'
|
} from './runtimeHelpers'
|
||||||
import { isVSlot } from './utils'
|
import { isVSlot } from './utils'
|
||||||
import { hoistStatic, isSingleElementRoot } from './transforms/hoistStatic'
|
import { cacheStatic, isSingleElementRoot } from './transforms/cacheStatic'
|
||||||
import type { CompilerCompatOptions } from './compat/compatConfig'
|
import type { CompilerCompatOptions } from './compat/compatConfig'
|
||||||
|
|
||||||
// There are two types of transforms:
|
// There are two types of transforms:
|
||||||
|
@ -93,7 +93,7 @@ export interface TransformContext
|
||||||
hoists: (JSChildNode | null)[]
|
hoists: (JSChildNode | null)[]
|
||||||
imports: ImportItem[]
|
imports: ImportItem[]
|
||||||
temps: number
|
temps: number
|
||||||
cached: number
|
cached: (CacheExpression | null)[]
|
||||||
identifiers: { [name: string]: number | undefined }
|
identifiers: { [name: string]: number | undefined }
|
||||||
scopes: {
|
scopes: {
|
||||||
vFor: number
|
vFor: number
|
||||||
|
@ -117,7 +117,7 @@ export interface TransformContext
|
||||||
addIdentifiers(exp: ExpressionNode | string): void
|
addIdentifiers(exp: ExpressionNode | string): void
|
||||||
removeIdentifiers(exp: ExpressionNode | string): void
|
removeIdentifiers(exp: ExpressionNode | string): void
|
||||||
hoist(exp: string | JSChildNode | ArrayExpression): SimpleExpressionNode
|
hoist(exp: string | JSChildNode | ArrayExpression): SimpleExpressionNode
|
||||||
cache<T extends JSChildNode>(exp: T, isVNode?: boolean): CacheExpression | T
|
cache(exp: JSChildNode, isVNode?: boolean): CacheExpression
|
||||||
constantCache: WeakMap<TemplateChildNode, ConstantTypes>
|
constantCache: WeakMap<TemplateChildNode, ConstantTypes>
|
||||||
|
|
||||||
// 2.x Compat only
|
// 2.x Compat only
|
||||||
|
@ -185,9 +185,9 @@ export function createTransformContext(
|
||||||
directives: new Set(),
|
directives: new Set(),
|
||||||
hoists: [],
|
hoists: [],
|
||||||
imports: [],
|
imports: [],
|
||||||
|
cached: [],
|
||||||
constantCache: new WeakMap(),
|
constantCache: new WeakMap(),
|
||||||
temps: 0,
|
temps: 0,
|
||||||
cached: 0,
|
|
||||||
identifiers: Object.create(null),
|
identifiers: Object.create(null),
|
||||||
scopes: {
|
scopes: {
|
||||||
vFor: 0,
|
vFor: 0,
|
||||||
|
@ -291,13 +291,19 @@ export function createTransformContext(
|
||||||
`_hoisted_${context.hoists.length}`,
|
`_hoisted_${context.hoists.length}`,
|
||||||
false,
|
false,
|
||||||
exp.loc,
|
exp.loc,
|
||||||
ConstantTypes.CAN_HOIST,
|
ConstantTypes.CAN_CACHE,
|
||||||
)
|
)
|
||||||
identifier.hoisted = exp
|
identifier.hoisted = exp
|
||||||
return identifier
|
return identifier
|
||||||
},
|
},
|
||||||
cache(exp, isVNode = false) {
|
cache(exp, isVNode = false) {
|
||||||
return createCacheExpression(context.cached++, exp, isVNode)
|
const cacheExp = createCacheExpression(
|
||||||
|
context.cached.length,
|
||||||
|
exp,
|
||||||
|
isVNode,
|
||||||
|
)
|
||||||
|
context.cached.push(cacheExp)
|
||||||
|
return cacheExp
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +330,7 @@ export function transform(root: RootNode, options: TransformOptions) {
|
||||||
const context = createTransformContext(root, options)
|
const context = createTransformContext(root, options)
|
||||||
traverseNode(root, context)
|
traverseNode(root, context)
|
||||||
if (options.hoistStatic) {
|
if (options.hoistStatic) {
|
||||||
hoistStatic(root, context)
|
cacheStatic(root, context)
|
||||||
}
|
}
|
||||||
if (!options.ssr) {
|
if (!options.ssr) {
|
||||||
createRootCodegen(root, context)
|
createRootCodegen(root, context)
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
import {
|
import {
|
||||||
|
type CacheExpression,
|
||||||
type CallExpression,
|
type CallExpression,
|
||||||
type ComponentNode,
|
type ComponentNode,
|
||||||
ConstantTypes,
|
ConstantTypes,
|
||||||
ElementTypes,
|
ElementTypes,
|
||||||
|
type ExpressionNode,
|
||||||
type JSChildNode,
|
type JSChildNode,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
type ParentNode,
|
type ParentNode,
|
||||||
type PlainElementNode,
|
type PlainElementNode,
|
||||||
type RootNode,
|
type RootNode,
|
||||||
type SimpleExpressionNode,
|
type SimpleExpressionNode,
|
||||||
|
type SlotFunctionExpression,
|
||||||
type TemplateChildNode,
|
type TemplateChildNode,
|
||||||
type TemplateNode,
|
type TemplateNode,
|
||||||
|
type TextCallNode,
|
||||||
type VNodeCall,
|
type VNodeCall,
|
||||||
createArrayExpression,
|
createArrayExpression,
|
||||||
getVNodeBlockHelper,
|
getVNodeBlockHelper,
|
||||||
|
@ -18,7 +22,7 @@ import {
|
||||||
} from '../ast'
|
} from '../ast'
|
||||||
import type { TransformContext } from '../transform'
|
import type { TransformContext } from '../transform'
|
||||||
import { PatchFlags, isArray, isString, isSymbol } from '@vue/shared'
|
import { PatchFlags, isArray, isString, isSymbol } from '@vue/shared'
|
||||||
import { isSlotOutlet } from '../utils'
|
import { findDir, isSlotOutlet } from '../utils'
|
||||||
import {
|
import {
|
||||||
GUARD_REACTIVE_PROPS,
|
GUARD_REACTIVE_PROPS,
|
||||||
NORMALIZE_CLASS,
|
NORMALIZE_CLASS,
|
||||||
|
@ -27,9 +31,10 @@ import {
|
||||||
OPEN_BLOCK,
|
OPEN_BLOCK,
|
||||||
} from '../runtimeHelpers'
|
} from '../runtimeHelpers'
|
||||||
|
|
||||||
export function hoistStatic(root: RootNode, context: TransformContext) {
|
export function cacheStatic(root: RootNode, context: TransformContext) {
|
||||||
walk(
|
walk(
|
||||||
root,
|
root,
|
||||||
|
undefined,
|
||||||
context,
|
context,
|
||||||
// Root node is unfortunately non-hoistable due to potential parent
|
// Root node is unfortunately non-hoistable due to potential parent
|
||||||
// fallthrough attributes.
|
// fallthrough attributes.
|
||||||
|
@ -51,16 +56,16 @@ export function isSingleElementRoot(
|
||||||
|
|
||||||
function walk(
|
function walk(
|
||||||
node: ParentNode,
|
node: ParentNode,
|
||||||
|
parent: ParentNode | undefined,
|
||||||
context: TransformContext,
|
context: TransformContext,
|
||||||
doNotHoistNode: boolean = false,
|
doNotHoistNode: boolean = false,
|
||||||
|
inFor = false,
|
||||||
) {
|
) {
|
||||||
const { children } = node
|
const { children } = node
|
||||||
const originalCount = children.length
|
const toCache: (PlainElementNode | TextCallNode)[] = []
|
||||||
let hoistedCount = 0
|
|
||||||
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
const child = children[i]
|
const child = children[i]
|
||||||
// only plain elements & text calls are eligible for hoisting.
|
// only plain elements & text calls are eligible for caching.
|
||||||
if (
|
if (
|
||||||
child.type === NodeTypes.ELEMENT &&
|
child.type === NodeTypes.ELEMENT &&
|
||||||
child.tagType === ElementTypes.ELEMENT
|
child.tagType === ElementTypes.ELEMENT
|
||||||
|
@ -69,11 +74,10 @@ function walk(
|
||||||
? ConstantTypes.NOT_CONSTANT
|
? ConstantTypes.NOT_CONSTANT
|
||||||
: getConstantType(child, context)
|
: getConstantType(child, context)
|
||||||
if (constantType > ConstantTypes.NOT_CONSTANT) {
|
if (constantType > ConstantTypes.NOT_CONSTANT) {
|
||||||
if (constantType >= ConstantTypes.CAN_HOIST) {
|
if (constantType >= ConstantTypes.CAN_CACHE) {
|
||||||
;(child.codegenNode as VNodeCall).patchFlag =
|
;(child.codegenNode as VNodeCall).patchFlag =
|
||||||
PatchFlags.HOISTED + (__DEV__ ? ` /* HOISTED */` : ``)
|
PatchFlags.CACHED + (__DEV__ ? ` /* CACHED */` : ``)
|
||||||
child.codegenNode = context.hoist(child.codegenNode!)
|
toCache.push(child)
|
||||||
hoistedCount++
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,7 +91,7 @@ function walk(
|
||||||
flag === PatchFlags.NEED_PATCH ||
|
flag === PatchFlags.NEED_PATCH ||
|
||||||
flag === PatchFlags.TEXT) &&
|
flag === PatchFlags.TEXT) &&
|
||||||
getGeneratedPropsConstantType(child, context) >=
|
getGeneratedPropsConstantType(child, context) >=
|
||||||
ConstantTypes.CAN_HOIST
|
ConstantTypes.CAN_CACHE
|
||||||
) {
|
) {
|
||||||
const props = getNodeProps(child)
|
const props = getNodeProps(child)
|
||||||
if (props) {
|
if (props) {
|
||||||
|
@ -99,6 +103,14 @@ function walk(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (child.type === NodeTypes.TEXT_CALL) {
|
||||||
|
const constantType = doNotHoistNode
|
||||||
|
? ConstantTypes.NOT_CONSTANT
|
||||||
|
: getConstantType(child, context)
|
||||||
|
if (constantType >= ConstantTypes.CAN_CACHE) {
|
||||||
|
toCache.push(child)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// walk further
|
// walk further
|
||||||
|
@ -107,54 +119,122 @@ function walk(
|
||||||
if (isComponent) {
|
if (isComponent) {
|
||||||
context.scopes.vSlot++
|
context.scopes.vSlot++
|
||||||
}
|
}
|
||||||
walk(child, context)
|
walk(child, node, context, false, inFor)
|
||||||
if (isComponent) {
|
if (isComponent) {
|
||||||
context.scopes.vSlot--
|
context.scopes.vSlot--
|
||||||
}
|
}
|
||||||
} else if (child.type === NodeTypes.FOR) {
|
} else if (child.type === NodeTypes.FOR) {
|
||||||
// Do not hoist v-for single child because it has to be a block
|
// Do not hoist v-for single child because it has to be a block
|
||||||
walk(child, context, child.children.length === 1)
|
walk(child, node, context, child.children.length === 1, true)
|
||||||
} else if (child.type === NodeTypes.IF) {
|
} else if (child.type === NodeTypes.IF) {
|
||||||
for (let i = 0; i < child.branches.length; i++) {
|
for (let i = 0; i < child.branches.length; i++) {
|
||||||
// Do not hoist v-if single child because it has to be a block
|
// Do not hoist v-if single child because it has to be a block
|
||||||
walk(
|
walk(
|
||||||
child.branches[i],
|
child.branches[i],
|
||||||
|
node,
|
||||||
context,
|
context,
|
||||||
child.branches[i].children.length === 1,
|
child.branches[i].children.length === 1,
|
||||||
|
inFor,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hoistedCount && context.transformHoist) {
|
let cachedAsArray = false
|
||||||
context.transformHoist(children, context, node)
|
if (toCache.length === children.length && node.type === NodeTypes.ELEMENT) {
|
||||||
|
if (
|
||||||
|
node.tagType === ElementTypes.ELEMENT &&
|
||||||
|
node.codegenNode &&
|
||||||
|
node.codegenNode.type === NodeTypes.VNODE_CALL &&
|
||||||
|
isArray(node.codegenNode.children)
|
||||||
|
) {
|
||||||
|
// all children were hoisted - the entire children array is cacheable.
|
||||||
|
node.codegenNode.children = getCacheExpression(
|
||||||
|
createArrayExpression(node.codegenNode.children),
|
||||||
|
)
|
||||||
|
cachedAsArray = true
|
||||||
|
} else if (
|
||||||
|
node.tagType === ElementTypes.COMPONENT &&
|
||||||
|
node.codegenNode &&
|
||||||
|
node.codegenNode.type === NodeTypes.VNODE_CALL &&
|
||||||
|
node.codegenNode.children &&
|
||||||
|
!isArray(node.codegenNode.children) &&
|
||||||
|
node.codegenNode.children.type === NodeTypes.JS_OBJECT_EXPRESSION
|
||||||
|
) {
|
||||||
|
// default slot
|
||||||
|
const slot = getSlotNode(node.codegenNode, 'default')
|
||||||
|
if (slot) {
|
||||||
|
slot.returns = getCacheExpression(
|
||||||
|
createArrayExpression(slot.returns as TemplateChildNode[]),
|
||||||
|
)
|
||||||
|
cachedAsArray = true
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
node.tagType === ElementTypes.TEMPLATE &&
|
||||||
|
parent &&
|
||||||
|
parent.type === NodeTypes.ELEMENT &&
|
||||||
|
parent.tagType === ElementTypes.COMPONENT &&
|
||||||
|
parent.codegenNode &&
|
||||||
|
parent.codegenNode.type === NodeTypes.VNODE_CALL &&
|
||||||
|
parent.codegenNode.children &&
|
||||||
|
!isArray(parent.codegenNode.children) &&
|
||||||
|
parent.codegenNode.children.type === NodeTypes.JS_OBJECT_EXPRESSION
|
||||||
|
) {
|
||||||
|
// named <template> slot
|
||||||
|
const slotName = findDir(node, 'slot', true)
|
||||||
|
const slot =
|
||||||
|
slotName &&
|
||||||
|
slotName.arg &&
|
||||||
|
getSlotNode(parent.codegenNode, slotName.arg)
|
||||||
|
if (slot) {
|
||||||
|
slot.returns = getCacheExpression(
|
||||||
|
createArrayExpression(slot.returns as TemplateChildNode[]),
|
||||||
|
)
|
||||||
|
cachedAsArray = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// all children were hoisted - the entire children array is hoistable.
|
if (!cachedAsArray) {
|
||||||
if (
|
for (const child of toCache) {
|
||||||
hoistedCount &&
|
child.codegenNode = context.cache(child.codegenNode!)
|
||||||
hoistedCount === originalCount &&
|
|
||||||
node.type === NodeTypes.ELEMENT &&
|
|
||||||
node.tagType === ElementTypes.ELEMENT &&
|
|
||||||
node.codegenNode &&
|
|
||||||
node.codegenNode.type === NodeTypes.VNODE_CALL &&
|
|
||||||
isArray(node.codegenNode.children)
|
|
||||||
) {
|
|
||||||
const hoisted = context.hoist(
|
|
||||||
createArrayExpression(node.codegenNode.children),
|
|
||||||
)
|
|
||||||
// #6978, #7138, #7114
|
|
||||||
// a hoisted children array inside v-for can caused HMR errors since
|
|
||||||
// it might be mutated when mounting the v-for list
|
|
||||||
if (context.hmr) {
|
|
||||||
hoisted.content = `[...${hoisted.content}]`
|
|
||||||
}
|
}
|
||||||
node.codegenNode.children = hoisted
|
}
|
||||||
|
|
||||||
|
function getCacheExpression(value: JSChildNode): CacheExpression {
|
||||||
|
const exp = context.cache(value)
|
||||||
|
// #6978, #7138, #7114
|
||||||
|
// a cached children array inside v-for can caused HMR errors since
|
||||||
|
// it might be mutated when mounting the first item
|
||||||
|
if (inFor && context.hmr) {
|
||||||
|
exp.needArraySpread = true
|
||||||
|
}
|
||||||
|
return exp
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSlotNode(
|
||||||
|
node: VNodeCall,
|
||||||
|
name: string | ExpressionNode,
|
||||||
|
): SlotFunctionExpression | undefined {
|
||||||
|
if (
|
||||||
|
node.children &&
|
||||||
|
!isArray(node.children) &&
|
||||||
|
node.children.type === NodeTypes.JS_OBJECT_EXPRESSION
|
||||||
|
) {
|
||||||
|
const slot = node.children.properties.find(
|
||||||
|
p => p.key === name || (p.key as SimpleExpressionNode).content === name,
|
||||||
|
)
|
||||||
|
return slot && slot.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toCache.length && context.transformHoist) {
|
||||||
|
context.transformHoist(children, context, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConstantType(
|
export function getConstantType(
|
||||||
node: TemplateChildNode | SimpleExpressionNode,
|
node: TemplateChildNode | SimpleExpressionNode | CacheExpression,
|
||||||
context: TransformContext,
|
context: TransformContext,
|
||||||
): ConstantTypes {
|
): ConstantTypes {
|
||||||
const { constantCache } = context
|
const { constantCache } = context
|
||||||
|
@ -284,6 +364,8 @@ export function getConstantType(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return returnType
|
return returnType
|
||||||
|
case NodeTypes.JS_CACHE_EXPRESSION:
|
||||||
|
return ConstantTypes.CAN_CACHE
|
||||||
default:
|
default:
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
const exhaustiveCheck: never = node
|
const exhaustiveCheck: never = node
|
|
@ -57,7 +57,7 @@ import {
|
||||||
toValidAssetId,
|
toValidAssetId,
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import { buildSlots } from './vSlot'
|
import { buildSlots } from './vSlot'
|
||||||
import { getConstantType } from './hoistStatic'
|
import { getConstantType } from './cacheStatic'
|
||||||
import { BindingTypes } from '../options'
|
import { BindingTypes } from '../options'
|
||||||
import {
|
import {
|
||||||
CompilerDeprecationTypes,
|
CompilerDeprecationTypes,
|
||||||
|
|
|
@ -250,7 +250,7 @@ export function processExpression(
|
||||||
if (isLiteral) {
|
if (isLiteral) {
|
||||||
node.constType = ConstantTypes.CAN_STRINGIFY
|
node.constType = ConstantTypes.CAN_STRINGIFY
|
||||||
} else {
|
} else {
|
||||||
node.constType = ConstantTypes.CAN_HOIST
|
node.constType = ConstantTypes.CAN_CACHE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return node
|
return node
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
import { isText } from '../utils'
|
import { isText } from '../utils'
|
||||||
import { CREATE_TEXT } from '../runtimeHelpers'
|
import { CREATE_TEXT } from '../runtimeHelpers'
|
||||||
import { PatchFlagNames, PatchFlags } from '@vue/shared'
|
import { PatchFlagNames, PatchFlags } from '@vue/shared'
|
||||||
import { getConstantType } from './hoistStatic'
|
import { getConstantType } from './cacheStatic'
|
||||||
|
|
||||||
// Merge adjacent text nodes and expressions into a single expression
|
// Merge adjacent text nodes and expressions into a single expression
|
||||||
// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.
|
// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.
|
||||||
|
|
|
@ -224,8 +224,10 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||||
renderExp.arguments.push(
|
renderExp.arguments.push(
|
||||||
loop as ForIteratorExpression,
|
loop as ForIteratorExpression,
|
||||||
createSimpleExpression(`_cache`),
|
createSimpleExpression(`_cache`),
|
||||||
createSimpleExpression(String(context.cached++)),
|
createSimpleExpression(String(context.cached.length)),
|
||||||
)
|
)
|
||||||
|
// increment cache count
|
||||||
|
context.cached.push(null)
|
||||||
} else {
|
} else {
|
||||||
renderExp.arguments.push(
|
renderExp.arguments.push(
|
||||||
createFunctionExpression(
|
createFunctionExpression(
|
||||||
|
|
|
@ -248,7 +248,7 @@ function createChildrenCodegenNode(
|
||||||
`${keyIndex}`,
|
`${keyIndex}`,
|
||||||
false,
|
false,
|
||||||
locStub,
|
locStub,
|
||||||
ConstantTypes.CAN_HOIST,
|
ConstantTypes.CAN_CACHE,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
const { children } = branch
|
const { children } = branch
|
||||||
|
|
|
@ -33,8 +33,10 @@ export const transformMemo: NodeTransform = (node, context) => {
|
||||||
dir.exp!,
|
dir.exp!,
|
||||||
createFunctionExpression(undefined, codegenNode),
|
createFunctionExpression(undefined, codegenNode),
|
||||||
`_cache`,
|
`_cache`,
|
||||||
String(context.cached++),
|
String(context.cached.length),
|
||||||
]) as MemoExpression
|
]) as MemoExpression
|
||||||
|
// increment cache count
|
||||||
|
context.cached.push(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
||||||
`{ ${modifiers} }`,
|
`{ ${modifiers} }`,
|
||||||
false,
|
false,
|
||||||
dir.loc,
|
dir.loc,
|
||||||
ConstantTypes.CAN_HOIST,
|
ConstantTypes.CAN_CACHE,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {
|
import {
|
||||||
type BlockCodegenNode,
|
type BlockCodegenNode,
|
||||||
|
type CacheExpression,
|
||||||
type CallExpression,
|
type CallExpression,
|
||||||
type DirectiveNode,
|
type DirectiveNode,
|
||||||
type ElementNode,
|
type ElementNode,
|
||||||
|
@ -438,7 +439,12 @@ export function toValidAssetId(
|
||||||
|
|
||||||
// Check if a node contains expressions that reference current context scope ids
|
// Check if a node contains expressions that reference current context scope ids
|
||||||
export function hasScopeRef(
|
export function hasScopeRef(
|
||||||
node: TemplateChildNode | IfBranchNode | ExpressionNode | undefined,
|
node:
|
||||||
|
| TemplateChildNode
|
||||||
|
| IfBranchNode
|
||||||
|
| ExpressionNode
|
||||||
|
| CacheExpression
|
||||||
|
| undefined,
|
||||||
ids: TransformContext['identifiers'],
|
ids: TransformContext['identifiers'],
|
||||||
): boolean {
|
): boolean {
|
||||||
if (!node || Object.keys(ids).length === 0) {
|
if (!node || Object.keys(ids).length === 0) {
|
||||||
|
@ -481,6 +487,7 @@ export function hasScopeRef(
|
||||||
return hasScopeRef(node.content, ids)
|
return hasScopeRef(node.content, ids)
|
||||||
case NodeTypes.TEXT:
|
case NodeTypes.TEXT:
|
||||||
case NodeTypes.COMMENT:
|
case NodeTypes.COMMENT:
|
||||||
|
case NodeTypes.JS_CACHE_EXPRESSION:
|
||||||
return false
|
return false
|
||||||
default:
|
default:
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
|
|
|
@ -1,96 +1,128 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`stringify static html > escape 1`] = `
|
||||||
|
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<div><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span><span class=\\"foo>ar\\">1 + <</span><span>&</span></div>", 1)
|
||||||
|
])))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`stringify static html > serializing constant bindings 1`] = `
|
||||||
|
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<div style=\\"color:red;\\"><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span><span class=\\"foo bar\\">1 + false</span></div>", 1)
|
||||||
|
])))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > should bail for <option> elements with number values 1`] = `
|
exports[`stringify static html > should bail for <option> elements with number values 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("select", null, [
|
|
||||||
/*#__PURE__*/_createElementVNode("option", { value: 1 }),
|
|
||||||
/*#__PURE__*/_createElementVNode("option", { value: 1 }),
|
|
||||||
/*#__PURE__*/_createElementVNode("option", { value: 1 }),
|
|
||||||
/*#__PURE__*/_createElementVNode("option", { value: 1 }),
|
|
||||||
/*#__PURE__*/_createElementVNode("option", { value: 1 })
|
|
||||||
], -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("select", null, [
|
||||||
|
_createElementVNode("option", { value: 1 }),
|
||||||
|
_createElementVNode("option", { value: 1 }),
|
||||||
|
_createElementVNode("option", { value: 1 }),
|
||||||
|
_createElementVNode("option", { value: 1 }),
|
||||||
|
_createElementVNode("option", { value: 1 })
|
||||||
|
], -1 /* CACHED */)
|
||||||
|
])))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > should bail on bindings that are hoisted but not stringifiable 1`] = `
|
exports[`stringify static html > should bail on bindings that are cached but not stringifiable 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, [
|
|
||||||
/*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
|
|
||||||
/*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
|
|
||||||
/*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
|
|
||||||
/*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
|
|
||||||
/*#__PURE__*/_createElementVNode("span", { class: "foo" }, "foo"),
|
|
||||||
/*#__PURE__*/_createElementVNode("img", { src: _imports_0_ })
|
|
||||||
], -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createElementVNode("div", null, [
|
||||||
|
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||||
|
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||||
|
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||||
|
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||||
|
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||||
|
_createElementVNode("img", { src: _imports_0_ })
|
||||||
|
], -1 /* CACHED */)
|
||||||
|
])))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > should work for <option> elements with string values 1`] = `
|
exports[`stringify static html > should work for <option> elements with string values 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<select><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option></select>", 1)
|
return function render(_ctx, _cache) {
|
||||||
const _hoisted_2 = [
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
_hoisted_1
|
_createStaticVNode("<select><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option><option value=\\"1\\"></option></select>", 1)
|
||||||
]
|
])))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`stringify static html > should work for multiple adjacent nodes 1`] = `
|
||||||
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span>", 5)
|
||||||
|
])))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`stringify static html > should work on eligible content (elements > 20) 1`] = `
|
||||||
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></div>", 1)
|
||||||
|
])))
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`stringify static html > should work on eligible content (elements with binding > 5) 1`] = `
|
||||||
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
|
return function render(_ctx, _cache) {
|
||||||
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<div><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span><span class=\\"foo\\"></span></div>", 1)
|
||||||
|
])))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > should work with bindings that are non-static but stringifiable 1`] = `
|
exports[`stringify static html > should work with bindings that are non-static but stringifiable 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<div><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><img src=\\"" + _imports_0_ + "\\"></div>", 1)
|
|
||||||
const _hoisted_2 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_2))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<div><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><span class=\\"foo\\">foo</span><img src=\\"" + _imports_0_ + "\\"></div>", 1)
|
||||||
|
])))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > stringify v-html 1`] = `
|
exports[`stringify static html > stringify v-html 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<pre data-type=\\"js\\"><code><span>show-it </span></code></pre><div class><span class>1</span><span class>2</span></div>", 2)
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
return _hoisted_1
|
return _cache[0] || (_cache[0] = _createStaticVNode("<pre data-type=\\"js\\"><code><span>show-it </span></code></pre><div class><span class>1</span><span class>2</span></div>", 2))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > stringify v-text 1`] = `
|
exports[`stringify static html > stringify v-text 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<pre data-type=\\"js\\"><code><span>show-it </span></code></pre><div class><span class>1</span><span class>2</span></div>", 2)
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
return _hoisted_1
|
return _cache[0] || (_cache[0] = _createStaticVNode("<pre data-type=\\"js\\"><code><span>show-it </span></code></pre><div class><span class>1</span><span class>2</span></div>", 2))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`stringify static html > stringify v-text with escape 1`] = `
|
exports[`stringify static html > stringify v-text with escape 1`] = `
|
||||||
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue
|
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode } = Vue
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<pre data-type=\\"js\\"><code>text1</code></pre><div class><span class>1</span><span class>2</span></div>", 2)
|
|
||||||
|
|
||||||
return function render(_ctx, _cache) {
|
return function render(_ctx, _cache) {
|
||||||
return _hoisted_1
|
return _cache[0] || (_cache[0] = _createStaticVNode("<pre data-type=\\"js\\"><code>text1</code></pre><div class><span class>1</span><span class>2</span></div>", 2))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -23,134 +23,147 @@ describe('stringify static html', () => {
|
||||||
return code.repeat(n)
|
return code.repeat(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert cached node NOT stringified
|
||||||
|
*/
|
||||||
|
function cachedArrayBailedMatcher(n = 1) {
|
||||||
|
return {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
|
elements: new Array(n).fill(0).map(() => ({
|
||||||
|
// should remain VNODE_CALL instead of JS_CALL_EXPRESSION
|
||||||
|
codegenNode: { type: NodeTypes.VNODE_CALL },
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert cached node is stringified (no content check)
|
||||||
|
*/
|
||||||
|
function cachedArraySuccessMatcher(n = 1) {
|
||||||
|
return {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
|
elements: new Array(n).fill(0).map(() => ({
|
||||||
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
|
callee: CREATE_STATIC,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert cached node stringified with desired content and node count
|
||||||
|
*/
|
||||||
|
function cachedArrayStaticNodeMatcher(content: string, count: number) {
|
||||||
|
return {
|
||||||
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
|
value: {
|
||||||
|
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
|
callee: CREATE_STATIC,
|
||||||
|
arguments: [JSON.stringify(content), String(count)],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test('should bail on non-eligible static trees', () => {
|
test('should bail on non-eligible static trees', () => {
|
||||||
const { ast } = compileWithStringify(
|
const { ast } = compileWithStringify(
|
||||||
`<div><div><div>hello</div><div>hello</div></div></div>`,
|
`<div><div><div>hello</div><div>hello</div></div></div>`,
|
||||||
)
|
)
|
||||||
// should be a normal vnode call
|
// should be cached children array
|
||||||
expect(ast.hoists[0]!.type).toBe(NodeTypes.VNODE_CALL)
|
expect(ast.cached[0]!.value.type).toBe(NodeTypes.JS_ARRAY_EXPRESSION)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should work on eligible content (elements with binding > 5)', () => {
|
test('should work on eligible content (elements with binding > 5)', () => {
|
||||||
const { ast } = compileWithStringify(
|
const { code, ast } = compileWithStringify(
|
||||||
`<div><div>${repeat(
|
`<div><div>${repeat(
|
||||||
`<span class="foo"/>`,
|
`<span class="foo"/>`,
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</div></div>`,
|
)}</div></div>`,
|
||||||
)
|
)
|
||||||
|
|
||||||
// should be optimized now
|
// should be optimized now
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([
|
||||||
{
|
cachedArrayStaticNodeMatcher(
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
`<div>${repeat(
|
||||||
callee: CREATE_STATIC,
|
`<span class="foo"></span>`,
|
||||||
arguments: [
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
JSON.stringify(
|
)}</div>`,
|
||||||
`<div>${repeat(
|
1,
|
||||||
`<span class="foo"></span>`,
|
),
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
|
||||||
)}</div>`,
|
|
||||||
),
|
|
||||||
'1',
|
|
||||||
],
|
|
||||||
}, // the children array is hoisted as well
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should work on eligible content (elements > 20)', () => {
|
test('should work on eligible content (elements > 20)', () => {
|
||||||
const { ast } = compileWithStringify(
|
const { code, ast } = compileWithStringify(
|
||||||
`<div><div>${repeat(
|
`<div><div>${repeat(
|
||||||
`<span/>`,
|
`<span/>`,
|
||||||
StringifyThresholds.NODE_COUNT,
|
StringifyThresholds.NODE_COUNT,
|
||||||
)}</div></div>`,
|
)}</div></div>`,
|
||||||
)
|
)
|
||||||
// should be optimized now
|
// should be optimized now
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([
|
||||||
{
|
cachedArrayStaticNodeMatcher(
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
`<div>${repeat(`<span></span>`, StringifyThresholds.NODE_COUNT)}</div>`,
|
||||||
callee: CREATE_STATIC,
|
1,
|
||||||
arguments: [
|
),
|
||||||
JSON.stringify(
|
|
||||||
`<div>${repeat(
|
|
||||||
`<span></span>`,
|
|
||||||
StringifyThresholds.NODE_COUNT,
|
|
||||||
)}</div>`,
|
|
||||||
),
|
|
||||||
'1',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
// the children array is hoisted as well
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should work for multiple adjacent nodes', () => {
|
test('should work for multiple adjacent nodes', () => {
|
||||||
const { ast } = compileWithStringify(
|
const { ast, code } = compileWithStringify(
|
||||||
`<div>${repeat(
|
`<div>${repeat(
|
||||||
`<span class="foo"/>`,
|
`<span class="foo"/>`,
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</div>`,
|
)}</div>`,
|
||||||
)
|
)
|
||||||
// should have 6 hoisted nodes (including the entire array),
|
expect(ast.cached).toMatchObject([
|
||||||
// but 2~5 should be null because they are merged into 1
|
cachedArrayStaticNodeMatcher(
|
||||||
expect(ast.hoists).toMatchObject([
|
repeat(
|
||||||
{
|
`<span class="foo"></span>`,
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
callee: CREATE_STATIC,
|
),
|
||||||
arguments: [
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
JSON.stringify(
|
),
|
||||||
repeat(
|
|
||||||
`<span class="foo"></span>`,
|
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
'5',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('serializing constant bindings', () => {
|
test('serializing constant bindings', () => {
|
||||||
const { ast } = compileWithStringify(
|
const { ast, code } = compileWithStringify(
|
||||||
`<div><div :style="{ color: 'red' }">${repeat(
|
`<div><div :style="{ color: 'red' }">${repeat(
|
||||||
`<span :class="[{ foo: true }, { bar: true }]">{{ 1 }} + {{ false }}</span>`,
|
`<span :class="[{ foo: true }, { bar: true }]">{{ 1 }} + {{ false }}</span>`,
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</div></div>`,
|
)}</div></div>`,
|
||||||
)
|
)
|
||||||
// should be optimized now
|
// should be optimized now
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([
|
||||||
{
|
cachedArrayStaticNodeMatcher(
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
`<div style="color:red;">${repeat(
|
||||||
callee: CREATE_STATIC,
|
`<span class="foo bar">1 + false</span>`,
|
||||||
arguments: [
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
JSON.stringify(
|
)}</div>`,
|
||||||
`<div style="color:red;">${repeat(
|
1,
|
||||||
`<span class="foo bar">1 + false</span>`,
|
),
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
|
||||||
)}</div>`,
|
|
||||||
),
|
|
||||||
'1',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('escape', () => {
|
test('escape', () => {
|
||||||
const { ast } = compileWithStringify(
|
const { ast, code } = compileWithStringify(
|
||||||
`<div><div>${repeat(
|
`<div><div>${repeat(
|
||||||
`<span :class="'foo' + '>ar'">{{ 1 }} + {{ '<' }}</span>` +
|
`<span :class="'foo' + '>ar'">{{ 1 }} + {{ '<' }}</span>` +
|
||||||
`<span>&</span>`,
|
`<span>&</span>`,
|
||||||
|
@ -158,27 +171,19 @@ describe('stringify static html', () => {
|
||||||
)}</div></div>`,
|
)}</div></div>`,
|
||||||
)
|
)
|
||||||
// should be optimized now
|
// should be optimized now
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([
|
||||||
{
|
cachedArrayStaticNodeMatcher(
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
`<div>${repeat(
|
||||||
callee: CREATE_STATIC,
|
`<span class="foo>ar">1 + <</span>` + `<span>&</span>`,
|
||||||
arguments: [
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
JSON.stringify(
|
)}</div>`,
|
||||||
`<div>${repeat(
|
1,
|
||||||
`<span class="foo>ar">1 + <</span>` + `<span>&</span>`,
|
),
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
|
||||||
)}</div>`,
|
|
||||||
),
|
|
||||||
'1',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should bail on bindings that are hoisted but not stringifiable', () => {
|
test('should bail on bindings that are cached but not stringifiable', () => {
|
||||||
const { ast, code } = compile(
|
const { ast, code } = compile(
|
||||||
`<div><div>${repeat(
|
`<div><div>${repeat(
|
||||||
`<span class="foo">foo</span>`,
|
`<span class="foo">foo</span>`,
|
||||||
|
@ -195,7 +200,7 @@ describe('stringify static html', () => {
|
||||||
'_imports_0_',
|
'_imports_0_',
|
||||||
false,
|
false,
|
||||||
node.loc,
|
node.loc,
|
||||||
ConstantTypes.CAN_HOIST,
|
ConstantTypes.CAN_CACHE,
|
||||||
)
|
)
|
||||||
node.props[0] = {
|
node.props[0] = {
|
||||||
type: NodeTypes.DIRECTIVE,
|
type: NodeTypes.DIRECTIVE,
|
||||||
|
@ -210,17 +215,7 @@ describe('stringify static html', () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
{
|
|
||||||
// the expression and the tree are still hoistable
|
|
||||||
// but should stay NodeTypes.VNODE_CALL
|
|
||||||
// if it's stringified it will be NodeTypes.JS_CALL_EXPRESSION
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -258,35 +253,19 @@ describe('stringify static html', () => {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([cachedArraySuccessMatcher()])
|
||||||
{
|
|
||||||
// the hoisted node should be NodeTypes.JS_CALL_EXPRESSION
|
|
||||||
// of `createStaticVNode()` instead of dynamic NodeTypes.VNODE_CALL
|
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
// #1128
|
// #1128
|
||||||
test('should bail on non attribute bindings', () => {
|
test('should bail on non-attribute bindings', () => {
|
||||||
const { ast } = compileWithStringify(
|
const { ast } = compileWithStringify(
|
||||||
`<div><div><input indeterminate>${repeat(
|
`<div><div><input indeterminate>${repeat(
|
||||||
`<span class="foo">foo</span>`,
|
`<span class="foo">foo</span>`,
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</div></div>`,
|
)}</div></div>`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const { ast: ast2 } = compileWithStringify(
|
const { ast: ast2 } = compileWithStringify(
|
||||||
`<div><div><input :indeterminate="true">${repeat(
|
`<div><div><input :indeterminate="true">${repeat(
|
||||||
|
@ -294,46 +273,23 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</div></div>`,
|
)}</div></div>`,
|
||||||
)
|
)
|
||||||
expect(ast2.hoists).toMatchObject([
|
expect(ast2.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
test('should bail on non attribute bindings', () => {
|
const { ast: ast3 } = compileWithStringify(
|
||||||
const { ast } = compileWithStringify(
|
|
||||||
`<div><div>${repeat(
|
`<div><div>${repeat(
|
||||||
`<span class="foo">foo</span>`,
|
`<span class="foo">foo</span>`,
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}<input indeterminate></div></div>`,
|
)}<input indeterminate></div></div>`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast3.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
const { ast: ast2 } = compileWithStringify(
|
const { ast: ast4 } = compileWithStringify(
|
||||||
`<div><div>${repeat(
|
`<div><div>${repeat(
|
||||||
`<span class="foo">foo</span>`,
|
`<span class="foo">foo</span>`,
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}<input :indeterminate="true"></div></div>`,
|
)}<input :indeterminate="true"></div></div>`,
|
||||||
)
|
)
|
||||||
expect(ast2.hoists).toMatchObject([
|
expect(ast4.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should bail on tags that has placement constraints (eg.tables related tags)', () => {
|
test('should bail on tags that has placement constraints (eg.tables related tags)', () => {
|
||||||
|
@ -343,14 +299,7 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</tbody></table>`,
|
)}</tbody></table>`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should bail inside slots', () => {
|
test('should bail inside slots', () => {
|
||||||
|
@ -360,14 +309,9 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</foo>`,
|
)}</foo>`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists.length).toBe(
|
expect(ast.cached).toMatchObject([
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
cachedArrayBailedMatcher(StringifyThresholds.ELEMENT_WITH_BINDING_COUNT),
|
||||||
)
|
])
|
||||||
ast.hoists.forEach(node => {
|
|
||||||
expect(node).toMatchObject({
|
|
||||||
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const { ast: ast2 } = compileWithStringify(
|
const { ast: ast2 } = compileWithStringify(
|
||||||
`<foo><template #foo>${repeat(
|
`<foo><template #foo>${repeat(
|
||||||
|
@ -375,14 +319,9 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</template></foo>`,
|
)}</template></foo>`,
|
||||||
)
|
)
|
||||||
expect(ast2.hoists.length).toBe(
|
expect(ast2.cached).toMatchObject([
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
cachedArrayBailedMatcher(StringifyThresholds.ELEMENT_WITH_BINDING_COUNT),
|
||||||
)
|
])
|
||||||
ast2.hoists.forEach(node => {
|
|
||||||
expect(node).toMatchObject({
|
|
||||||
type: NodeTypes.VNODE_CALL, // not CALL_EXPRESSION
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should remove attribute for `null`', () => {
|
test('should remove attribute for `null`', () => {
|
||||||
|
@ -392,19 +331,13 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</div>`,
|
)}</div>`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists[0]).toMatchObject({
|
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
expect(ast.cached).toMatchObject([
|
||||||
callee: CREATE_STATIC,
|
cachedArrayStaticNodeMatcher(
|
||||||
arguments: [
|
repeat(`<span></span>`, StringifyThresholds.ELEMENT_WITH_BINDING_COUNT),
|
||||||
JSON.stringify(
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
`${repeat(
|
),
|
||||||
`<span></span>`,
|
])
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
|
||||||
)}`,
|
|
||||||
),
|
|
||||||
'5',
|
|
||||||
],
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// #6617
|
// #6617
|
||||||
|
@ -415,19 +348,24 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.NODE_COUNT,
|
StringifyThresholds.NODE_COUNT,
|
||||||
)}`,
|
)}`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists[0]).toMatchObject({
|
expect(ast.cached).toMatchObject([
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
{
|
||||||
callee: CREATE_STATIC,
|
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||||
arguments: [
|
value: {
|
||||||
JSON.stringify(
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
`<button>enable</button>${repeat(
|
callee: CREATE_STATIC,
|
||||||
`<div></div>`,
|
arguments: [
|
||||||
StringifyThresholds.NODE_COUNT,
|
JSON.stringify(
|
||||||
)}`,
|
`<button>enable</button>${repeat(
|
||||||
),
|
`<div></div>`,
|
||||||
'21',
|
StringifyThresholds.NODE_COUNT,
|
||||||
],
|
)}`,
|
||||||
})
|
),
|
||||||
|
'21',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should stringify svg', () => {
|
test('should stringify svg', () => {
|
||||||
|
@ -439,19 +377,16 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</svg></div>`,
|
)}</svg></div>`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists[0]).toMatchObject({
|
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
expect(ast.cached).toMatchObject([
|
||||||
callee: CREATE_STATIC,
|
cachedArrayStaticNodeMatcher(
|
||||||
arguments: [
|
`${svg}${repeat(
|
||||||
JSON.stringify(
|
repeated,
|
||||||
`${svg}${repeat(
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
repeated,
|
)}</svg>`,
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
1,
|
||||||
)}</svg>`,
|
),
|
||||||
),
|
])
|
||||||
'1',
|
|
||||||
],
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// #5439
|
// #5439
|
||||||
|
@ -494,23 +429,14 @@ describe('stringify static html', () => {
|
||||||
)}</select></div>`,
|
)}</select></div>`,
|
||||||
)
|
)
|
||||||
// should be optimized now
|
// should be optimized now
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([
|
||||||
{
|
cachedArrayStaticNodeMatcher(
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
`<select>${repeat(
|
||||||
callee: CREATE_STATIC,
|
`<option value="1"></option>`,
|
||||||
arguments: [
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
JSON.stringify(
|
)}</select>`,
|
||||||
`<select>${repeat(
|
1,
|
||||||
`<option value="1"></option>`,
|
),
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
|
||||||
)}</select>`,
|
|
||||||
),
|
|
||||||
'1',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
])
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
@ -522,14 +448,7 @@ describe('stringify static html', () => {
|
||||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||||
)}</select></div>`,
|
)}</select></div>`,
|
||||||
)
|
)
|
||||||
expect(ast.hoists).toMatchObject([
|
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
|
||||||
{
|
|
||||||
type: NodeTypes.VNODE_CALL,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_ARRAY_EXPRESSION,
|
|
||||||
},
|
|
||||||
])
|
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -268,7 +268,7 @@ describe('compiler-dom: transform v-on', () => {
|
||||||
prefixIdentifiers: true,
|
prefixIdentifiers: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
})
|
})
|
||||||
expect(root.cached).toBe(1)
|
expect(root.cached.length).toBe(1)
|
||||||
// should not treat cached handler as dynamicProp, so it should have no
|
// should not treat cached handler as dynamicProp, so it should have no
|
||||||
// dynamicProps flags and only the hydration flag
|
// dynamicProps flags and only the hydration flag
|
||||||
expect((root as any).children[0].codegenNode.patchFlag).toBe(
|
expect((root as any).children[0].codegenNode.patchFlag).toBe(
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
CREATE_STATIC,
|
CREATE_STATIC,
|
||||||
|
type CacheExpression,
|
||||||
ConstantTypes,
|
ConstantTypes,
|
||||||
type ElementNode,
|
type ElementNode,
|
||||||
ElementTypes,
|
ElementTypes,
|
||||||
type ExpressionNode,
|
type ExpressionNode,
|
||||||
type HoistTransform,
|
type HoistTransform,
|
||||||
type JSChildNode,
|
|
||||||
Namespaces,
|
Namespaces,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
type PlainElementNode,
|
type PlainElementNode,
|
||||||
|
@ -16,11 +16,14 @@ import {
|
||||||
type TemplateChildNode,
|
type TemplateChildNode,
|
||||||
type TextCallNode,
|
type TextCallNode,
|
||||||
type TransformContext,
|
type TransformContext,
|
||||||
|
type VNodeCall,
|
||||||
|
createArrayExpression,
|
||||||
createCallExpression,
|
createCallExpression,
|
||||||
isStaticArgOf,
|
isStaticArgOf,
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import {
|
import {
|
||||||
escapeHtml,
|
escapeHtml,
|
||||||
|
isArray,
|
||||||
isBooleanAttr,
|
isBooleanAttr,
|
||||||
isKnownHtmlAttr,
|
isKnownHtmlAttr,
|
||||||
isKnownSvgAttr,
|
isKnownSvgAttr,
|
||||||
|
@ -76,6 +79,14 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isParentCached =
|
||||||
|
parent.type === NodeTypes.ELEMENT &&
|
||||||
|
parent.codegenNode &&
|
||||||
|
parent.codegenNode.type === NodeTypes.VNODE_CALL &&
|
||||||
|
parent.codegenNode.children &&
|
||||||
|
!isArray(parent.codegenNode.children) &&
|
||||||
|
parent.codegenNode.children.type === NodeTypes.JS_CACHE_EXPRESSION
|
||||||
|
|
||||||
let nc = 0 // current node count
|
let nc = 0 // current node count
|
||||||
let ec = 0 // current element with binding count
|
let ec = 0 // current element with binding count
|
||||||
const currentChunk: StringifiableNode[] = []
|
const currentChunk: StringifiableNode[] = []
|
||||||
|
@ -94,19 +105,31 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
|
||||||
// will insert / hydrate
|
// will insert / hydrate
|
||||||
String(currentChunk.length),
|
String(currentChunk.length),
|
||||||
])
|
])
|
||||||
// replace the first node's hoisted expression with the static vnode call
|
|
||||||
replaceHoist(currentChunk[0], staticCall, context)
|
|
||||||
|
|
||||||
if (currentChunk.length > 1) {
|
if (isParentCached) {
|
||||||
for (let i = 1; i < currentChunk.length; i++) {
|
;((parent.codegenNode as VNodeCall).children as CacheExpression).value =
|
||||||
// for the merged nodes, set their hoisted expression to null
|
createArrayExpression([staticCall])
|
||||||
replaceHoist(currentChunk[i], null, context)
|
} else {
|
||||||
|
// replace the first node's hoisted expression with the static vnode call
|
||||||
|
;(currentChunk[0].codegenNode as CacheExpression).value = staticCall
|
||||||
|
if (currentChunk.length > 1) {
|
||||||
|
// remove merged nodes from children
|
||||||
|
const deleteCount = currentChunk.length - 1
|
||||||
|
children.splice(currentIndex - currentChunk.length + 1, deleteCount)
|
||||||
|
// also adjust index for the remaining cache items
|
||||||
|
const cacheIndex = context.cached.indexOf(
|
||||||
|
currentChunk[currentChunk.length - 1]
|
||||||
|
.codegenNode as CacheExpression,
|
||||||
|
)
|
||||||
|
if (cacheIndex > -1) {
|
||||||
|
for (let i = cacheIndex; i < context.cached.length; i++) {
|
||||||
|
const c = context.cached[i]
|
||||||
|
if (c) c.index -= deleteCount
|
||||||
|
}
|
||||||
|
context.cached.splice(cacheIndex - deleteCount + 1, deleteCount)
|
||||||
|
}
|
||||||
|
return deleteCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// also remove merged nodes from children
|
|
||||||
const deleteCount = currentChunk.length - 1
|
|
||||||
children.splice(currentIndex - currentChunk.length + 1, deleteCount)
|
|
||||||
return deleteCount
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
@ -115,16 +138,15 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
|
||||||
let i = 0
|
let i = 0
|
||||||
for (; i < children.length; i++) {
|
for (; i < children.length; i++) {
|
||||||
const child = children[i]
|
const child = children[i]
|
||||||
const hoisted = getHoistedNode(child)
|
const isCached = isParentCached || getCachedNode(child)
|
||||||
if (hoisted) {
|
if (isCached) {
|
||||||
// presence of hoisted means child must be a stringifiable node
|
// presence of cached means child must be a stringifiable node
|
||||||
const node = child as StringifiableNode
|
const result = analyzeNode(child as StringifiableNode)
|
||||||
const result = analyzeNode(node)
|
|
||||||
if (result) {
|
if (result) {
|
||||||
// node is stringifiable, record state
|
// node is stringifiable, record state
|
||||||
nc += result[0]
|
nc += result[0]
|
||||||
ec += result[1]
|
ec += result[1]
|
||||||
currentChunk.push(node)
|
currentChunk.push(child as StringifiableNode)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,12 +163,19 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
|
||||||
stringifyCurrentChunk(i)
|
stringifyCurrentChunk(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getHoistedNode = (node: TemplateChildNode) =>
|
const getCachedNode = (
|
||||||
((node.type === NodeTypes.ELEMENT && node.tagType === ElementTypes.ELEMENT) ||
|
node: TemplateChildNode,
|
||||||
node.type == NodeTypes.TEXT_CALL) &&
|
): CacheExpression | undefined => {
|
||||||
node.codegenNode &&
|
if (
|
||||||
node.codegenNode.type === NodeTypes.SIMPLE_EXPRESSION &&
|
((node.type === NodeTypes.ELEMENT &&
|
||||||
node.codegenNode.hoisted
|
node.tagType === ElementTypes.ELEMENT) ||
|
||||||
|
node.type === NodeTypes.TEXT_CALL) &&
|
||||||
|
node.codegenNode &&
|
||||||
|
node.codegenNode.type === NodeTypes.JS_CACHE_EXPRESSION
|
||||||
|
) {
|
||||||
|
return node.codegenNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const dataAriaRE = /^(data|aria)-/
|
const dataAriaRE = /^(data|aria)-/
|
||||||
const isStringifiableAttr = (name: string, ns: Namespaces) => {
|
const isStringifiableAttr = (name: string, ns: Namespaces) => {
|
||||||
|
@ -159,21 +188,12 @@ const isStringifiableAttr = (name: string, ns: Namespaces) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const replaceHoist = (
|
|
||||||
node: StringifiableNode,
|
|
||||||
replacement: JSChildNode | null,
|
|
||||||
context: TransformContext,
|
|
||||||
) => {
|
|
||||||
const hoistToReplace = (node.codegenNode as SimpleExpressionNode).hoisted!
|
|
||||||
context.hoists[context.hoists.indexOf(hoistToReplace)] = replacement
|
|
||||||
}
|
|
||||||
|
|
||||||
const isNonStringifiable = /*#__PURE__*/ makeMap(
|
const isNonStringifiable = /*#__PURE__*/ makeMap(
|
||||||
`caption,thead,tr,th,tbody,td,tfoot,colgroup,col`,
|
`caption,thead,tr,th,tbody,td,tfoot,colgroup,col`,
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for a hoisted node, analyze it and return:
|
* for a cached node, analyze it and return:
|
||||||
* - false: bailed (contains non-stringifiable props or runtime constant)
|
* - false: bailed (contains non-stringifiable props or runtime constant)
|
||||||
* - [nc, ec] where
|
* - [nc, ec] where
|
||||||
* - nc is the number of nodes inside
|
* - nc is the number of nodes inside
|
||||||
|
@ -381,7 +401,7 @@ function evaluateConstant(exp: ExpressionNode): string {
|
||||||
} else if (c.type === NodeTypes.INTERPOLATION) {
|
} else if (c.type === NodeTypes.INTERPOLATION) {
|
||||||
res += toDisplayString(evaluateConstant(c.content))
|
res += toDisplayString(evaluateConstant(c.content))
|
||||||
} else {
|
} else {
|
||||||
res += evaluateConstant(c)
|
res += evaluateConstant(c as ExpressionNode)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -851,8 +851,6 @@ return (_ctx, _cache) => {
|
||||||
exports[`SFC compile <script setup> > inlineTemplate mode > should work 1`] = `
|
exports[`SFC compile <script setup> > inlineTemplate mode > should work 1`] = `
|
||||||
"import { toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
"import { toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, "static", -1 /* HOISTED */)
|
|
||||||
|
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -863,7 +861,7 @@ export default {
|
||||||
return (_ctx, _cache) => {
|
return (_ctx, _cache) => {
|
||||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||||
_createElementVNode("div", null, _toDisplayString(count.value), 1 /* TEXT */),
|
_createElementVNode("div", null, _toDisplayString(count.value), 1 /* TEXT */),
|
||||||
_hoisted_1
|
_cache[0] || (_cache[0] = _createElementVNode("div", null, "static", -1 /* CACHED */))
|
||||||
], 64 /* STABLE_FRAGMENT */))
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,11 @@ import _imports_0 from '@svg/file.svg'
|
||||||
|
|
||||||
|
|
||||||
const _hoisted_1 = _imports_0 + '#fragment'
|
const _hoisted_1 = _imports_0 + '#fragment'
|
||||||
const _hoisted_2 = /*#__PURE__*/_createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_3 = /*#__PURE__*/_createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */)
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||||
_hoisted_2,
|
_cache[0] || (_cache[0] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */)),
|
||||||
_hoisted_3
|
_cache[1] || (_cache[1] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */))
|
||||||
], 64 /* STABLE_FRAGMENT */))
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -82,13 +80,10 @@ import _imports_0 from './bar.png'
|
||||||
import _imports_1 from '/bar.png'
|
import _imports_1 from '/bar.png'
|
||||||
|
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<img src=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_1 + "\\"><img src=\\"https://foo.bar/baz.png\\"><img src=\\"//foo.bar/baz.png\\"><img src=\\"" + _imports_0 + "\\">", 5)
|
|
||||||
const _hoisted_6 = [
|
|
||||||
_hoisted_1
|
|
||||||
]
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_6))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<img src=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_1 + "\\"><img src=\\"https://foo.bar/baz.png\\"><img src=\\"//foo.bar/baz.png\\"><img src=\\"" + _imports_0 + "\\">", 5)
|
||||||
|
])))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,11 @@ import _imports_0 from '@/logo.png'
|
||||||
|
|
||||||
const _hoisted_1 = _imports_0 + ', ' + _imports_0 + ' 2x'
|
const _hoisted_1 = _imports_0 + ', ' + _imports_0 + ' 2x'
|
||||||
const _hoisted_2 = _imports_0 + ' 1x, ' + "/foo/logo.png" + ' 2x'
|
const _hoisted_2 = _imports_0 + ' 1x, ' + "/foo/logo.png" + ' 2x'
|
||||||
const _hoisted_3 = /*#__PURE__*/_createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_4 = /*#__PURE__*/_createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* HOISTED */)
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||||
_hoisted_3,
|
_cache[0] || (_cache[0] = _createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* CACHED */)),
|
||||||
_hoisted_4
|
_cache[1] || (_cache[1] = _createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* CACHED */))
|
||||||
], 64 /* STABLE_FRAGMENT */))
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -31,69 +29,57 @@ const _hoisted_5 = _imports_0 + ' 2x, ' + _imports_0
|
||||||
const _hoisted_6 = _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
const _hoisted_6 = _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
||||||
const _hoisted_7 = _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
const _hoisted_7 = _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
||||||
const _hoisted_8 = "/logo.png" + ', ' + _imports_0 + ' 2x'
|
const _hoisted_8 = "/logo.png" + ', ' + _imports_0 + ' 2x'
|
||||||
const _hoisted_9 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: ""
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_10 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_1
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_11 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_2
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_12 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_3
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_13 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_4
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_14 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_5
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_15 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_6
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_16 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_7
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_17 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "/logo.png",
|
|
||||||
srcset: "/logo.png, /logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_18 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "https://example.com/logo.png",
|
|
||||||
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_19 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "/logo.png",
|
|
||||||
srcset: _hoisted_8
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_20 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "data:image/png;base64,i",
|
|
||||||
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||||
_hoisted_9,
|
_cache[0] || (_cache[0] = _createElementVNode("img", {
|
||||||
_hoisted_10,
|
src: "./logo.png",
|
||||||
_hoisted_11,
|
srcset: ""
|
||||||
_hoisted_12,
|
}, null, -1 /* CACHED */)),
|
||||||
_hoisted_13,
|
_cache[1] || (_cache[1] = _createElementVNode("img", {
|
||||||
_hoisted_14,
|
src: "./logo.png",
|
||||||
_hoisted_15,
|
srcset: _hoisted_1
|
||||||
_hoisted_16,
|
}, null, -1 /* CACHED */)),
|
||||||
_hoisted_17,
|
_cache[2] || (_cache[2] = _createElementVNode("img", {
|
||||||
_hoisted_18,
|
src: "./logo.png",
|
||||||
_hoisted_19,
|
srcset: _hoisted_2
|
||||||
_hoisted_20
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[3] || (_cache[3] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_3
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[4] || (_cache[4] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_4
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[5] || (_cache[5] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_5
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[6] || (_cache[6] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_6
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[7] || (_cache[7] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_7
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[8] || (_cache[8] = _createElementVNode("img", {
|
||||||
|
src: "/logo.png",
|
||||||
|
srcset: "/logo.png, /logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[9] || (_cache[9] = _createElementVNode("img", {
|
||||||
|
src: "https://example.com/logo.png",
|
||||||
|
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[10] || (_cache[10] = _createElementVNode("img", {
|
||||||
|
src: "/logo.png",
|
||||||
|
srcset: _hoisted_8
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[11] || (_cache[11] = _createElementVNode("img", {
|
||||||
|
src: "data:image/png;base64,i",
|
||||||
|
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
||||||
|
}, null, -1 /* CACHED */))
|
||||||
], 64 /* STABLE_FRAGMENT */))
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -101,69 +87,56 @@ export function render(_ctx, _cache) {
|
||||||
exports[`compiler sfc: transform srcset > transform srcset w/ base 1`] = `
|
exports[`compiler sfc: transform srcset > transform srcset w/ base 1`] = `
|
||||||
"import { createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
"import { createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"
|
||||||
|
|
||||||
const _hoisted_1 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: ""
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_2 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: "/foo/logo.png"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_3 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: "/foo/logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_4 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: "/foo/logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_5 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: "/foo/logo.png, /foo/logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_6 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: "/foo/logo.png 2x, /foo/logo.png"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_7 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: "/foo/logo.png 2x, /foo/logo.png 3x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_8 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: "/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_9 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "/logo.png",
|
|
||||||
srcset: "/logo.png, /logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_10 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "https://example.com/logo.png",
|
|
||||||
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_11 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "/logo.png",
|
|
||||||
srcset: "/logo.png, /foo/logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_12 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "data:image/png;base64,i",
|
|
||||||
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||||
_hoisted_1,
|
_cache[0] || (_cache[0] = _createElementVNode("img", {
|
||||||
_hoisted_2,
|
src: "./logo.png",
|
||||||
_hoisted_3,
|
srcset: ""
|
||||||
_hoisted_4,
|
}, null, -1 /* CACHED */)),
|
||||||
_hoisted_5,
|
_cache[1] || (_cache[1] = _createElementVNode("img", {
|
||||||
_hoisted_6,
|
src: "./logo.png",
|
||||||
_hoisted_7,
|
srcset: "/foo/logo.png"
|
||||||
_hoisted_8,
|
}, null, -1 /* CACHED */)),
|
||||||
_hoisted_9,
|
_cache[2] || (_cache[2] = _createElementVNode("img", {
|
||||||
_hoisted_10,
|
src: "./logo.png",
|
||||||
_hoisted_11,
|
srcset: "/foo/logo.png 2x"
|
||||||
_hoisted_12
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[3] || (_cache[3] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: "/foo/logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[4] || (_cache[4] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: "/foo/logo.png, /foo/logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[5] || (_cache[5] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: "/foo/logo.png 2x, /foo/logo.png"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[6] || (_cache[6] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: "/foo/logo.png 2x, /foo/logo.png 3x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[7] || (_cache[7] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: "/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[8] || (_cache[8] = _createElementVNode("img", {
|
||||||
|
src: "/logo.png",
|
||||||
|
srcset: "/logo.png, /logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[9] || (_cache[9] = _createElementVNode("img", {
|
||||||
|
src: "https://example.com/logo.png",
|
||||||
|
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[10] || (_cache[10] = _createElementVNode("img", {
|
||||||
|
src: "/logo.png",
|
||||||
|
srcset: "/logo.png, /foo/logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[11] || (_cache[11] = _createElementVNode("img", {
|
||||||
|
src: "data:image/png;base64,i",
|
||||||
|
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
||||||
|
}, null, -1 /* CACHED */))
|
||||||
], 64 /* STABLE_FRAGMENT */))
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -183,69 +156,57 @@ const _hoisted_6 = _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
||||||
const _hoisted_7 = _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
const _hoisted_7 = _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
||||||
const _hoisted_8 = _imports_1 + ', ' + _imports_1 + ' 2x'
|
const _hoisted_8 = _imports_1 + ', ' + _imports_1 + ' 2x'
|
||||||
const _hoisted_9 = _imports_1 + ', ' + _imports_0 + ' 2x'
|
const _hoisted_9 = _imports_1 + ', ' + _imports_0 + ' 2x'
|
||||||
const _hoisted_10 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: ""
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_11 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_1
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_12 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_2
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_13 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_3
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_14 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_4
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_15 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_5
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_16 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_6
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_17 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "./logo.png",
|
|
||||||
srcset: _hoisted_7
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_18 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "/logo.png",
|
|
||||||
srcset: _hoisted_8
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_19 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "https://example.com/logo.png",
|
|
||||||
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_20 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "/logo.png",
|
|
||||||
srcset: _hoisted_9
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
const _hoisted_21 = /*#__PURE__*/_createElementVNode("img", {
|
|
||||||
src: "data:image/png;base64,i",
|
|
||||||
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
|
||||||
}, null, -1 /* HOISTED */)
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||||
_hoisted_10,
|
_cache[0] || (_cache[0] = _createElementVNode("img", {
|
||||||
_hoisted_11,
|
src: "./logo.png",
|
||||||
_hoisted_12,
|
srcset: ""
|
||||||
_hoisted_13,
|
}, null, -1 /* CACHED */)),
|
||||||
_hoisted_14,
|
_cache[1] || (_cache[1] = _createElementVNode("img", {
|
||||||
_hoisted_15,
|
src: "./logo.png",
|
||||||
_hoisted_16,
|
srcset: _hoisted_1
|
||||||
_hoisted_17,
|
}, null, -1 /* CACHED */)),
|
||||||
_hoisted_18,
|
_cache[2] || (_cache[2] = _createElementVNode("img", {
|
||||||
_hoisted_19,
|
src: "./logo.png",
|
||||||
_hoisted_20,
|
srcset: _hoisted_2
|
||||||
_hoisted_21
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[3] || (_cache[3] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_3
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[4] || (_cache[4] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_4
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[5] || (_cache[5] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_5
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[6] || (_cache[6] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_6
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[7] || (_cache[7] = _createElementVNode("img", {
|
||||||
|
src: "./logo.png",
|
||||||
|
srcset: _hoisted_7
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[8] || (_cache[8] = _createElementVNode("img", {
|
||||||
|
src: "/logo.png",
|
||||||
|
srcset: _hoisted_8
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[9] || (_cache[9] = _createElementVNode("img", {
|
||||||
|
src: "https://example.com/logo.png",
|
||||||
|
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[10] || (_cache[10] = _createElementVNode("img", {
|
||||||
|
src: "/logo.png",
|
||||||
|
srcset: _hoisted_9
|
||||||
|
}, null, -1 /* CACHED */)),
|
||||||
|
_cache[11] || (_cache[11] = _createElementVNode("img", {
|
||||||
|
src: "data:image/png;base64,i",
|
||||||
|
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
||||||
|
}, null, -1 /* CACHED */))
|
||||||
], 64 /* STABLE_FRAGMENT */))
|
], 64 /* STABLE_FRAGMENT */))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -265,12 +226,10 @@ const _hoisted_6 = _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
||||||
const _hoisted_7 = _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
const _hoisted_7 = _imports_0 + ', ' + _imports_0 + ' 2x, ' + _imports_0 + ' 3x'
|
||||||
const _hoisted_8 = _imports_1 + ', ' + _imports_1 + ' 2x'
|
const _hoisted_8 = _imports_1 + ', ' + _imports_1 + ' 2x'
|
||||||
const _hoisted_9 = _imports_1 + ', ' + _imports_0 + ' 2x'
|
const _hoisted_9 = _imports_1 + ', ' + _imports_0 + ' 2x'
|
||||||
const _hoisted_10 = /*#__PURE__*/_createStaticVNode("<img src=\\"./logo.png\\" srcset=\\"\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_1 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_2 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_3 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_4 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_5 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_6 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_7 + "\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_8 + "\\"><img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_9 + "\\"><img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">", 12)
|
|
||||||
const _hoisted_22 = [
|
|
||||||
_hoisted_10
|
|
||||||
]
|
|
||||||
|
|
||||||
export function render(_ctx, _cache) {
|
export function render(_ctx, _cache) {
|
||||||
return (_openBlock(), _createElementBlock("div", null, _hoisted_22))
|
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||||
|
_createStaticVNode("<img src=\\"./logo.png\\" srcset=\\"\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_1 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_2 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_3 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_4 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_5 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_6 + "\\"><img src=\\"./logo.png\\" srcset=\\"" + _hoisted_7 + "\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_8 + "\\"><img src=\\"https://example.com/logo.png\\" srcset=\\"https://example.com/logo.png, https://example.com/logo.png 2x\\"><img src=\\"/logo.png\\" srcset=\\"" + _hoisted_9 + "\\"><img src=\\"data:image/png;base64,i\\" srcset=\\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\">", 12)
|
||||||
|
])))
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1122,7 +1122,7 @@ describe('SSR hydration', () => {
|
||||||
'input',
|
'input',
|
||||||
{ type: 'checkbox', indeterminate: '' },
|
{ type: 'checkbox', indeterminate: '' },
|
||||||
null,
|
null,
|
||||||
PatchFlags.HOISTED,
|
PatchFlags.CACHED,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
expect((container.firstChild as any).indeterminate).toBe(true)
|
expect((container.firstChild as any).indeterminate).toBe(true)
|
||||||
|
|
|
@ -366,7 +366,7 @@ export function createHydrationFunctions(
|
||||||
const forcePatch = type === 'input' || type === 'option'
|
const forcePatch = type === 'input' || type === 'option'
|
||||||
// skip props & children if this is hoisted static nodes
|
// skip props & children if this is hoisted static nodes
|
||||||
// #5405 in dev, always hydrate children for HMR
|
// #5405 in dev, always hydrate children for HMR
|
||||||
if (__DEV__ || forcePatch || patchFlag !== PatchFlags.HOISTED) {
|
if (__DEV__ || forcePatch || patchFlag !== PatchFlags.CACHED) {
|
||||||
if (dirs) {
|
if (dirs) {
|
||||||
invokeDirectiveHook(vnode, null, parentComponent, 'created')
|
invokeDirectiveHook(vnode, null, parentComponent, 'created')
|
||||||
}
|
}
|
||||||
|
|
|
@ -650,7 +650,7 @@ export function cloneVNode<T, U>(
|
||||||
scopeId: vnode.scopeId,
|
scopeId: vnode.scopeId,
|
||||||
slotScopeIds: vnode.slotScopeIds,
|
slotScopeIds: vnode.slotScopeIds,
|
||||||
children:
|
children:
|
||||||
__DEV__ && patchFlag === PatchFlags.HOISTED && isArray(children)
|
__DEV__ && patchFlag === PatchFlags.CACHED && isArray(children)
|
||||||
? (children as VNode[]).map(deepCloneVNode)
|
? (children as VNode[]).map(deepCloneVNode)
|
||||||
: children,
|
: children,
|
||||||
target: vnode.target,
|
target: vnode.target,
|
||||||
|
@ -663,7 +663,7 @@ export function cloneVNode<T, U>(
|
||||||
// fast paths only.
|
// fast paths only.
|
||||||
patchFlag:
|
patchFlag:
|
||||||
extraProps && vnode.type !== Fragment
|
extraProps && vnode.type !== Fragment
|
||||||
? patchFlag === PatchFlags.HOISTED // hoisted node
|
? patchFlag === PatchFlags.CACHED // hoisted node
|
||||||
? PatchFlags.FULL_PROPS
|
? PatchFlags.FULL_PROPS
|
||||||
: patchFlag | PatchFlags.FULL_PROPS
|
: patchFlag | PatchFlags.FULL_PROPS
|
||||||
: patchFlag,
|
: patchFlag,
|
||||||
|
@ -772,7 +772,7 @@ export function normalizeVNode(child: VNodeChild): VNode {
|
||||||
|
|
||||||
// optimized normalization for template-compiled render fns
|
// optimized normalization for template-compiled render fns
|
||||||
export function cloneIfMounted(child: VNode): VNode {
|
export function cloneIfMounted(child: VNode): VNode {
|
||||||
return (child.el === null && child.patchFlag !== PatchFlags.HOISTED) ||
|
return (child.el === null && child.patchFlag !== PatchFlags.CACHED) ||
|
||||||
child.memo
|
child.memo
|
||||||
? child
|
? child
|
||||||
: cloneVNode(child)
|
: cloneVNode(child)
|
||||||
|
|
|
@ -109,10 +109,10 @@ export enum PatchFlags {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates a hoisted static vnode. This is a hint for hydration to skip
|
* Indicates a cached static vnode. This is also a hint for hydration to skip
|
||||||
* the entire sub tree since static content never needs to be updated.
|
* the entire sub tree since static content never needs to be updated.
|
||||||
*/
|
*/
|
||||||
HOISTED = -1,
|
CACHED = -1,
|
||||||
/**
|
/**
|
||||||
* A special flag that indicates that the diffing algorithm should bail out
|
* A special flag that indicates that the diffing algorithm should bail out
|
||||||
* of optimized mode. For example, on block fragments created by renderSlot()
|
* of optimized mode. For example, on block fragments created by renderSlot()
|
||||||
|
@ -139,6 +139,6 @@ export const PatchFlagNames: Record<PatchFlags, string> = {
|
||||||
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
|
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
|
||||||
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`,
|
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`,
|
||||||
[PatchFlags.DEV_ROOT_FRAGMENT]: `DEV_ROOT_FRAGMENT`,
|
[PatchFlags.DEV_ROOT_FRAGMENT]: `DEV_ROOT_FRAGMENT`,
|
||||||
[PatchFlags.HOISTED]: `HOISTED`,
|
[PatchFlags.CACHED]: `HOISTED`,
|
||||||
[PatchFlags.BAIL]: `BAIL`,
|
[PatchFlags.BAIL]: `BAIL`,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue