]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(compiler): transformStyle + context.hoist
authorEvan You <yyx990803@gmail.com>
Wed, 25 Sep 2019 18:13:33 +0000 (14:13 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 25 Sep 2019 18:13:33 +0000 (14:13 -0400)
13 files changed:
packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap
packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
packages/compiler-core/__tests__/codegen.spec.ts
packages/compiler-core/__tests__/transform.spec.ts
packages/compiler-core/__tests__/transforms/transformElement.spec.ts
packages/compiler-core/src/ast.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/index.ts
packages/compiler-core/src/parse.ts
packages/compiler-core/src/transform.ts
packages/compiler-core/src/transforms/transformElement.ts
packages/compiler-core/src/transforms/transformExpression.ts
packages/compiler-core/src/transforms/transformStyle.ts [new file with mode: 0644]

index 765602697fa0e96a856d528f7d3b8f4b4a8a0b7a..8ce723cf944b3ab709b9052749b8d2d90d0d142e 100644 (file)
@@ -1,7 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`compiler: codegen callExpression + objectExpression + arrayExpression 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return createVNode(\\"div\\", {
       id: \\"foo\\",
@@ -16,7 +17,8 @@ exports[`compiler: codegen callExpression + objectExpression + arrayExpression 1
 `;
 
 exports[`compiler: codegen comment 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return createVNode(Comment, 0, \\"foo\\")
   }
@@ -24,7 +26,8 @@ exports[`compiler: codegen comment 1`] = `
 `;
 
 exports[`compiler: codegen compound expression 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return toString(_ctx.foo)
   }
@@ -32,7 +35,8 @@ exports[`compiler: codegen compound expression 1`] = `
 `;
 
 exports[`compiler: codegen forNode 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return renderList(list, (v, k, i) => toString(v))
   }
@@ -40,7 +44,8 @@ exports[`compiler: codegen forNode 1`] = `
 `;
 
 exports[`compiler: codegen forNode w/ skipped key alias 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return renderList(list, (v, __key, i) => toString(v))
   }
@@ -48,7 +53,8 @@ exports[`compiler: codegen forNode w/ skipped key alias 1`] = `
 `;
 
 exports[`compiler: codegen forNode w/ skipped value alias 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return renderList(list, (__value, k, i) => toString(v))
   }
@@ -56,7 +62,8 @@ exports[`compiler: codegen forNode w/ skipped value alias 1`] = `
 `;
 
 exports[`compiler: codegen forNode w/ skipped value and key aliases 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return renderList(list, (__value, __key, i) => toString(v))
   }
@@ -73,8 +80,20 @@ return function render() {
 }"
 `;
 
+exports[`compiler: codegen hoists 1`] = `
+"const _hoisted_1 = hello
+const _hoisted_2 = { id: \\"foo\\" }
+
+return function render() {
+  with (this) {
+    return null
+  }
+}"
+`;
+
 exports[`compiler: codegen ifNode 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return foo
       ? \\"foo\\"
@@ -86,7 +105,8 @@ exports[`compiler: codegen ifNode 1`] = `
 `;
 
 exports[`compiler: codegen ifNode with no v-else 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return foo
       ? \\"foo\\"
@@ -98,7 +118,8 @@ exports[`compiler: codegen ifNode with no v-else 1`] = `
 `;
 
 exports[`compiler: codegen interpolation 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return toString(hello)
   }
@@ -116,14 +137,16 @@ export default function render() {
 `;
 
 exports[`compiler: codegen prefixIdentifiers: true should inject _ctx statement 1`] = `
-"return function render() {
+"
+return function render() {
   const _ctx = this
   return null
 }"
 `;
 
-exports[`compiler: codegen statement preambles 1`] = `
-"return function render() {
+exports[`compiler: codegen statements 1`] = `
+"
+return function render() {
   const a = 1
   const b = 2
   
@@ -134,7 +157,8 @@ exports[`compiler: codegen statement preambles 1`] = `
 `;
 
 exports[`compiler: codegen static text 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return \\"hello\\"
   }
@@ -142,7 +166,8 @@ exports[`compiler: codegen static text 1`] = `
 `;
 
 exports[`compiler: codegen text + comment + interpolation 1`] = `
-"return function render() {
+"
+return function render() {
   with (this) {
     return [
       \\"foo\\",
index 695935fa2926e0362e9a8ab2f1ffa8b360223676..250b91ae099181bcb15f0066db3f7cc4e5364674 100644 (file)
@@ -45,6 +45,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -109,6 +110,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -173,6 +175,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -255,6 +258,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -337,6 +341,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -419,6 +424,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -501,6 +507,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -566,6 +573,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -631,6 +639,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -696,6 +705,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -761,6 +771,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -825,6 +836,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -914,6 +926,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -979,6 +992,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1044,6 +1058,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1109,6 +1124,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1250,6 +1266,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1320,6 +1337,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1390,6 +1408,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1455,6 +1474,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1520,6 +1540,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1590,6 +1611,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1679,6 +1701,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1743,6 +1766,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1807,6 +1831,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1871,6 +1896,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1935,6 +1961,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -1999,6 +2026,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2064,6 +2092,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2129,6 +2158,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2199,6 +2229,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2269,6 +2300,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2358,6 +2390,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2447,6 +2480,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2536,6 +2570,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2642,6 +2677,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2748,6 +2784,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2854,6 +2891,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -2960,6 +2998,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3066,6 +3105,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3172,6 +3212,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3278,6 +3319,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3384,6 +3426,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3448,6 +3491,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3488,6 +3532,7 @@ Object {
       "type": 3,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3552,6 +3597,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3616,6 +3662,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3680,6 +3727,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3744,6 +3792,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3809,6 +3858,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3875,6 +3925,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -3940,6 +3991,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4022,6 +4074,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4128,6 +4181,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4217,6 +4271,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4306,6 +4361,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4352,6 +4408,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4417,6 +4474,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4482,6 +4540,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4547,6 +4606,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4690,6 +4750,7 @@ class=\\"bar\\"></div></template>",
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4832,6 +4893,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4896,6 +4958,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -4960,6 +5023,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5024,6 +5088,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5088,6 +5153,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5153,6 +5219,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5218,6 +5285,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5283,6 +5351,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5348,6 +5417,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5454,6 +5524,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5560,6 +5631,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5666,6 +5738,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5772,6 +5845,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5878,6 +5952,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -5984,6 +6059,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6090,6 +6166,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6196,6 +6273,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6285,6 +6363,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6391,6 +6470,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6455,6 +6535,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6562,6 +6643,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6627,6 +6709,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6692,6 +6775,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6756,6 +6840,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6802,6 +6887,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6848,6 +6934,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6914,6 +7001,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -6979,6 +7067,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7049,6 +7138,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7119,6 +7209,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7160,6 +7251,7 @@ Object {
       "type": 2,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7201,6 +7293,7 @@ Object {
       "type": 2,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7243,6 +7336,7 @@ Object {
       "type": 4,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7316,6 +7410,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7502,6 +7597,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
@@ -7707,6 +7803,7 @@ Object {
       "type": 1,
     },
   ],
+  "hoists": Array [],
   "imports": Array [],
   "loc": Object {
     "end": Object {
index 42c73c2b98f1bcd24f7b7d540c7d5620507b3c46..5f21af633fa148d8616fd109dc9a10cd2f7a8cb8 100644 (file)
@@ -34,6 +34,7 @@ function createRoot(options: Partial<RootNode> = {}): RootNode {
     children: [],
     imports: [],
     statements: [],
+    hoists: [],
     loc: mockLoc,
     ...options
   }
@@ -58,7 +59,7 @@ describe('compiler: codegen', () => {
     expect(code).toMatchSnapshot()
   })
 
-  test('statement preambles', () => {
+  test('statements', () => {
     const root = createRoot({
       statements: [`const a = 1`, `const b = 2`]
     })
@@ -68,6 +69,28 @@ describe('compiler: codegen', () => {
     expect(code).toMatchSnapshot()
   })
 
+  test('hoists', () => {
+    const root = createRoot({
+      hoists: [
+        createExpression(`hello`, false, mockLoc),
+        createObjectExpression(
+          [
+            createObjectProperty(
+              createExpression(`id`, true, mockLoc),
+              createExpression(`foo`, true, mockLoc),
+              mockLoc
+            )
+          ],
+          mockLoc
+        )
+      ]
+    })
+    const { code } = generate(root)
+    expect(code).toMatch(`const _hoisted_1 = hello`)
+    expect(code).toMatch(`const _hoisted_2 = { id: "foo" }`)
+    expect(code).toMatchSnapshot()
+  })
+
   test('prefixIdentifiers: true should inject _ctx statement', () => {
     const { code } = generate(createRoot(), { prefixIdentifiers: true })
     expect(code).toMatch(`const _ctx = this\n`)
index d30128fd93c93d05030cb0639e9667510ac52f80..8ebf221f93628a4b56191b485ca18095afedf290 100644 (file)
@@ -1,6 +1,11 @@
 import { parse } from '../src/parse'
 import { transform, NodeTransform } from '../src/transform'
-import { ElementNode, NodeTypes } from '../src/ast'
+import {
+  ElementNode,
+  NodeTypes,
+  DirectiveNode,
+  ExpressionNode
+} from '../src/ast'
 import { ErrorCodes, createCompilerError } from '../src/errors'
 import { TO_STRING, CREATE_VNODE, COMMENT } from '../src/runtimeConstants'
 
@@ -158,6 +163,22 @@ describe('compiler: transform', () => {
     expect(spy.mock.calls[1][0]).toBe(d1)
   })
 
+  test('context.hoist', () => {
+    const ast = parse(`<div :id="foo"/><div :id="bar"/>`)
+    const hoisted: ExpressionNode[] = []
+    const mock: NodeTransform = (node, context) => {
+      const dir = (node as ElementNode).props[0] as DirectiveNode
+      hoisted.push(dir.exp!)
+      dir.exp = context.hoist(dir.exp!)
+    }
+    transform(ast, {
+      nodeTransforms: [mock]
+    })
+    expect(ast.hoists).toMatchObject(hoisted)
+    expect((ast as any).children[0].props[0].exp.content).toBe(`_hoisted_1`)
+    expect((ast as any).children[1].props[0].exp.content).toBe(`_hoisted_2`)
+  })
+
   test('onError option', () => {
     const ast = parse(`<div/>`)
     const loc = ast.children[0].loc
index 137d373b8e5d0633c9332f2816b0383ca7da3305..1723d0f624ef2c5b45406dd63492049703041d30 100644 (file)
@@ -71,25 +71,42 @@ describe('compiler: element transform', () => {
   })
 
   test('static props', () => {
-    const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`)
+    const { root, node } = parseWithElementTransform(
+      `<div id="foo" class="bar" />`
+    )
     expect(node.callee).toBe(CREATE_VNODE)
-    expect(node.arguments).toMatchObject([
-      `"div"`,
+    // should hoist the static object
+    expect(root.hoists).toMatchObject([
       createStaticObjectMatcher({
         id: 'foo',
         class: 'bar'
       })
     ])
+    expect(node.arguments).toMatchObject([
+      `"div"`,
+      {
+        type: NodeTypes.EXPRESSION,
+        content: `_hoisted_1`
+      }
+    ])
   })
 
   test('props + children', () => {
-    const { node } = parseWithElementTransform(`<div id="foo"><span/></div>`)
+    const { root, node } = parseWithElementTransform(
+      `<div id="foo"><span/></div>`
+    )
     expect(node.callee).toBe(CREATE_VNODE)
-    expect(node.arguments).toMatchObject([
-      `"div"`,
+    expect(root.hoists).toMatchObject([
       createStaticObjectMatcher({
         id: 'foo'
-      }),
+      })
+    ])
+    expect(node.arguments).toMatchObject([
+      `"div"`,
+      {
+        type: NodeTypes.EXPRESSION,
+        content: `_hoisted_1`
+      },
       [
         {
           type: NodeTypes.ELEMENT,
@@ -452,7 +469,8 @@ describe('compiler: element transform', () => {
 
   test('props dedupe', () => {
     const { code } = compile(
-      `<div class="a" :class="b" @click.foo="a" @click.bar="b" style="color: red" :style="{fontSize: 14}" />`
+      `<div class="a" :class="b" @click.foo="a" @click.bar="b" style="color: red" />
+      <div id="foo"/>`
     )
     console.log(code)
   })
index de828ef6dd556b3dab43f2511ff712f470aeda7c..786cdfd4dd04be32a84a9333349802567e099c3e 100644 (file)
@@ -68,6 +68,7 @@ export interface RootNode extends Node {
   children: ChildNode[]
   imports: string[]
   statements: string[]
+  hoists: JSChildNode[]
 }
 
 export interface ElementNode extends Node {
index 94d7241f64dfd0a7ba0934e47e60be5dc221b239..b6c66a7d373d76c6c05229cf1652cbb7ae452c6d 100644 (file)
@@ -148,14 +148,16 @@ export function generate(
   if (mode === 'function') {
     // generate const declarations for helpers
     if (imports) {
-      push(`const { ${imports} } = Vue\n\n`)
+      push(`const { ${imports} } = Vue\n`)
     }
+    genHoists(ast.hoists, context)
     push(`return `)
   } else {
     // generate import statements for helpers
     if (imports) {
-      push(`import { ${imports} } from 'vue'\n\n`)
+      push(`import { ${imports} } from 'vue'\n`)
     }
+    genHoists(ast.hoists, context)
     push(`export default `)
   }
   push(`function render() {`)
@@ -190,6 +192,15 @@ export function generate(
   }
 }
 
+function genHoists(hoists: JSChildNode[], context: CodegenContext) {
+  hoists.forEach((exp, i) => {
+    context.push(`const _hoisted_${i + 1} = `)
+    genNode(exp, context)
+    context.newline()
+  })
+  context.newline()
+}
+
 // This will generate a single vnode call if:
 // - The list has length === 1, AND:
 // - This is a root node, OR:
index 70de04696280d3a2237e5d9ec873fd9c36646a60..572abeadf86188d565dd0398506ad6a9ef86bdc1 100644 (file)
@@ -10,6 +10,7 @@ import { transformOn } from './transforms/vOn'
 import { transformBind } from './transforms/vBind'
 import { transformExpression } from './transforms/transformExpression'
 import { defaultOnError, createCompilerError, ErrorCodes } from './errors'
+import { transformStyle } from './transforms/transformStyle'
 
 export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
 
@@ -33,6 +34,7 @@ export function compile(
       transformIf,
       transformFor,
       ...(prefixIdentifiers ? [transformExpression] : []),
+      transformStyle,
       transformElement,
       ...(options.nodeTransforms || []) // user transforms
     ],
@@ -53,7 +55,7 @@ export {
   createStructuralDirectiveTransform,
   TransformOptions,
   TransformContext,
-  NodeTransform as Transform,
+  NodeTransform,
   StructuralDirectiveTransform
 } from './transform'
 export {
@@ -64,8 +66,3 @@ export {
 } from './codegen'
 export { ErrorCodes, CompilerError, createCompilerError } from './errors'
 export * from './ast'
-
-// debug
-export {
-  transformElement as prepareElementForCodegen
-} from './transforms/transformElement'
index 84677fd87377f5d2547fa6152086b28675998e3d..e80480fba8fa223ddc9fe51668b5fd2bd197325b 100644 (file)
@@ -84,6 +84,7 @@ export function parse(content: string, options: ParserOptions = {}): RootNode {
     children: parseChildren(context, TextModes.DATA, []),
     imports: [],
     statements: [],
+    hoists: [],
     loc: getSelection(context, start)
   }
 }
index 4dac7986ab5672b818afe767055699fc229e3a01..ad62b402b6abbdf175fcd17185ab32c4317d3982 100644 (file)
@@ -6,7 +6,9 @@ import {
   ElementNode,
   DirectiveNode,
   Property,
-  ExpressionNode
+  ExpressionNode,
+  createExpression,
+  JSChildNode
 } from './ast'
 import { isString, isArray } from '@vue/shared'
 import { CompilerError, defaultOnError } from './errors'
@@ -52,6 +54,7 @@ export interface TransformContext extends Required<TransformOptions> {
   root: RootNode
   imports: Set<string>
   statements: string[]
+  hoists: JSChildNode[]
   identifiers: { [name: string]: number | undefined }
   parent: ParentNode
   childIndex: number
@@ -61,6 +64,7 @@ export interface TransformContext extends Required<TransformOptions> {
   onNodeRemoved: () => void
   addIdentifier(exp: ExpressionNode): void
   removeIdentifier(exp: ExpressionNode): void
+  hoist(exp: JSChildNode): ExpressionNode
 }
 
 function createTransformContext(
@@ -76,6 +80,7 @@ function createTransformContext(
     root,
     imports: new Set(),
     statements: [],
+    hoists: [],
     identifiers: {},
     prefixIdentifiers,
     nodeTransforms,
@@ -125,6 +130,14 @@ function createTransformContext(
     },
     removeIdentifier({ content }) {
       ;(context.identifiers[content] as number)--
+    },
+    hoist(exp) {
+      context.hoists.push(exp)
+      return createExpression(
+        `_hoisted_${context.hoists.length}`,
+        false,
+        exp.loc
+      )
     }
   }
   return context
@@ -135,6 +148,7 @@ export function transform(root: RootNode, options: TransformOptions) {
   traverseChildren(root, context)
   root.imports = [...context.imports]
   root.statements = context.statements
+  root.hoists = context.hoists
 }
 
 export function traverseChildren(
index fa58cb946de670413b2b695cfd75fdd9dc790d51..a28a9e1eafa00a53380530159477e6b0231387ea 100644 (file)
@@ -108,6 +108,7 @@ function buildProps(
   props: PropsExpression
   directives: DirectiveNode[]
 } {
+  let isStatic = true
   let properties: ObjectExpression['properties'] = []
   const mergeArgs: PropsExpression[] = []
   const runtimeDirectives: DirectiveNode[] = []
@@ -130,6 +131,7 @@ function buildProps(
       )
     } else {
       // directives
+      isStatic = false
       const { name, arg, exp, loc } = prop
       // special case for v-bind and v-on with no argument
       const isBind = name === 'bind'
@@ -208,6 +210,11 @@ function buildProps(
     )
   }
 
+  // hoist the object if it's fully static
+  if (isStatic) {
+    propsExpression = context.hoist(propsExpression)
+  }
+
   return {
     props: propsExpression,
     directives: runtimeDirectives
@@ -233,10 +240,8 @@ function dedupeProperties(properties: Property[]): Property[] {
     const name = prop.key.content
     const existing = knownProps[name]
     if (existing) {
-      if (name.startsWith('on')) {
+      if (name.startsWith('on') || name === 'style') {
         mergeAsArray(existing, prop)
-      } else if (name === 'style') {
-        mergeStyles(existing, prop)
       } else if (name === 'class') {
         mergeClasses(existing, prop)
       }
@@ -260,25 +265,9 @@ function mergeAsArray(existing: Property, incoming: Property) {
   }
 }
 
-// Merge dynamic and static style into a single prop
-export function mergeStyles(existing: Property, incoming: Property) {
-  if (
-    existing.value.type === NodeTypes.JS_OBJECT_EXPRESSION &&
-    incoming.value.type === NodeTypes.JS_OBJECT_EXPRESSION
-  ) {
-    // if both are objects, merge the object expressions.
-    // style="color: red" :style="{ a: b }"
-    // -> { color: "red", a: b }
-    existing.value.properties.push(...incoming.value.properties)
-  } else {
-    // otherwise merge as array
-    // style="color:red" :style="a"
-    // -> style: [{ color: "red" }, a]
-    mergeAsArray(existing, incoming)
-  }
-}
-
 // Merge dynamic and static class into a single prop
+// :class="expression" class="string"
+// -> class: expression + "string"
 function mergeClasses(existing: Property, incoming: Property) {
   const e = existing.value as ExpressionNode
   const children =
@@ -289,8 +278,6 @@ function mergeClasses(existing: Property, incoming: Property) {
         children: undefined
       }
     ])
-  // :class="expression" class="string"
-  // -> class: expression + "string"
   children.push(` + " " + `, incoming.value as ExpressionNode)
 }
 
index 224438fa636981ea34965be00c6af2fafa3d48a9..be09c6904301c9dbcb9339e04a20950da54da1e3 100644 (file)
@@ -28,12 +28,11 @@ export const transformExpression: NodeTransform = (node, context) => {
         if (prop.arg && !prop.arg.isStatic) {
           if (prop.name === 'class') {
             // TODO special expression optimization for classes
+            processExpression(prop.arg, context)
           } else {
             processExpression(prop.arg, context)
           }
         }
-      } else if (prop.name === 'style') {
-        // TODO parse inline CSS literals into objects
       }
     }
   }
diff --git a/packages/compiler-core/src/transforms/transformStyle.ts b/packages/compiler-core/src/transforms/transformStyle.ts
new file mode 100644 (file)
index 0000000..d2c10db
--- /dev/null
@@ -0,0 +1,37 @@
+import { NodeTransform } from '../transform'
+import { NodeTypes, createExpression } from '../ast'
+
+// prase inline CSS strings for static style attributes into an object
+export const transformStyle: NodeTransform = (node, context) => {
+  if (node.type === NodeTypes.ELEMENT) {
+    node.props.forEach((p, i) => {
+      if (p.type === NodeTypes.ATTRIBUTE && p.name === 'style' && p.value) {
+        // replace p with an expression node
+        const parsed = JSON.stringify(parseInlineCSS(p.value.content))
+        const exp = context.hoist(createExpression(parsed, false, p.loc))
+        node.props[i] = {
+          type: NodeTypes.DIRECTIVE,
+          name: `bind`,
+          arg: createExpression(`style`, true, p.loc),
+          exp,
+          modifiers: [],
+          loc: p.loc
+        }
+      }
+    })
+  }
+}
+
+const listDelimiterRE = /;(?![^(]*\))/g
+const propertyDelimiterRE = /:(.+)/
+
+function parseInlineCSS(cssText: string): Record<string, string> {
+  const res: Record<string, string> = {}
+  cssText.split(listDelimiterRE).forEach(function(item) {
+    if (item) {
+      const tmp = item.split(propertyDelimiterRE)
+      tmp.length > 1 && (res[tmp[0].trim()] = tmp[1].trim())
+    }
+  })
+  return res
+}