Przeglądaj źródła

build: introduce feature flags, hide new slot syntax behind flag

Evan You 7 lat temu
rodzic
commit
7fb6fdd168

+ 7 - 2
scripts/config.js

@@ -7,6 +7,7 @@ const node = require('rollup-plugin-node-resolve')
 const flow = require('rollup-plugin-flow-no-whitespace')
 const version = process.env.VERSION || require('../package.json').version
 const weexVersion = process.env.WEEX_VERSION || require('../packages/weex-vue-framework/package.json').version
+const featureFlags = require('./feature-flags')
 
 const banner =
   '/*!\n' +
@@ -241,9 +242,13 @@ function genConfig (name) {
   }
 
   if (opts.env) {
-    config.plugins.push(replace({
+    const vars = {
       'process.env.NODE_ENV': JSON.stringify(opts.env)
-    }))
+    }
+    Object.keys(featureFlags).forEach(key => {
+      vars[`process.env.${key}`] = featureFlags[key]
+    })
+    config.plugins.push(replace(vars))
   }
 
   if (opts.transpile !== false) {

+ 3 - 0
scripts/feature-flags.js

@@ -0,0 +1,3 @@
+module.exports = {
+  NEW_SLOT_SYNTAX: false
+}

+ 16 - 14
src/compiler/parser/index.js

@@ -568,22 +568,24 @@ function processSlotContent (el) {
     }
     el.slotScope = (
       slotScope ||
-      getAndRemoveAttr(el, 'slot-scope') ||
+      getAndRemoveAttr(el, 'slot-scope')
+    )
+    if (process.env.NEW_SLOT_SYNTAX) {
       // new in 2.6: slot-props and its shorthand works the same as slot-scope
       // when used on <template> containers
-      getAndRemoveAttr(el, 'slot-props')
-    )
-    // 2.6 shorthand syntax
-    const shorthand = getAndRemoveAttrByRegex(el, scopedSlotShorthandRE)
-    if (shorthand) {
-      if (process.env.NODE_ENV !== 'production' && el.slotScope) {
-        warn(
-          `Unexpected mixed usage of different slot syntaxes.`,
-          el
-        )
+      el.slotScope = el.slotScope || getAndRemoveAttr(el, 'slot-props')
+      // 2.6 shorthand syntax
+      const shorthand = getAndRemoveAttrByRegex(el, scopedSlotShorthandRE)
+      if (shorthand) {
+        if (process.env.NODE_ENV !== 'production' && el.slotScope) {
+          warn(
+            `Unexpected mixed usage of different slot syntaxes.`,
+            el
+          )
+        }
+        el.slotTarget = getScopedSlotShorthandName(shorthand)
+        el.slotScope = shorthand.value
       }
-      el.slotTarget = getScopedSlotShorthandName(shorthand)
-      el.slotScope = shorthand.value
     }
   } else if ((slotScope = getAndRemoveAttr(el, 'slot-scope'))) {
     /* istanbul ignore if */
@@ -597,7 +599,7 @@ function processSlotContent (el) {
       )
     }
     el.slotScope = slotScope
-  } else {
+  } else if (process.env.NEW_SLOT_SYNTAX) {
     // 2.6: slot-props on component, denotes default slot
     slotScope = getAndRemoveAttr(el, 'slot-props')
     const shorthand = getAndRemoveAttrByRegex(el, scopedSlotShorthandRE)

+ 1 - 1
src/core/vdom/helpers/normalize-scoped-slots.js

@@ -32,7 +32,7 @@ export function normalizeScopedSlots (
 function normalizeScopedSlot(fn: Function): Function {
   return scope => {
     const res = fn(scope)
-    return res && typeof res === 'object'
+    return res && typeof res === 'object' && !Array.isArray(res)
       ? [res] // single vnode
       : normalizeChildren(res)
   }

+ 126 - 124
test/unit/features/component/component-scoped-slot.spec.js

@@ -632,64 +632,116 @@ describe('Component scoped slot', () => {
     }).then(done)
   })
 
-  // new in 2.6
-  describe('slot-props syntax', () => {
-    const Foo = {
-      render(h) {
-        return h('div', [
-          this.$scopedSlots.default && this.$scopedSlots.default('from foo default'),
-          this.$scopedSlots.one && this.$scopedSlots.one('from foo one'),
-          this.$scopedSlots.two && this.$scopedSlots.two('from foo two')
-        ])
+  // 2.6 new slot syntax
+  if (process.env.NEW_SLOT_SYNTAX) {
+    describe('slot-props syntax', () => {
+      const Foo = {
+        render(h) {
+          return h('div', [
+            this.$scopedSlots.default && this.$scopedSlots.default('from foo default'),
+            this.$scopedSlots.one && this.$scopedSlots.one('from foo one'),
+            this.$scopedSlots.two && this.$scopedSlots.two('from foo two')
+          ])
+        }
       }
-    }
 
-    const Bar = {
-      render(h) {
-        return this.$scopedSlots.default && this.$scopedSlots.default('from bar')[0]
+      const Bar = {
+        render(h) {
+          return this.$scopedSlots.default && this.$scopedSlots.default('from bar')
+        }
       }
-    }
 
-    const Baz = {
-      render(h) {
-        return this.$scopedSlots.default && this.$scopedSlots.default('from baz')[0]
+      const Baz = {
+        render(h) {
+          return this.$scopedSlots.default && this.$scopedSlots.default('from baz')
+        }
       }
-    }
 
-    function runSuite(syntax) {
-      it('default slot', () => {
-        const vm = new Vue({
-          template: `<foo ${syntax}="foo">{{ foo }}<div>{{ foo }}</div></foo>`,
-          components: { Foo }
-        }).$mount()
-        expect(vm.$el.innerHTML).toBe(`from foo default<div>from foo default</div>`)
-      })
+      function runSuite(syntax) {
+        it('default slot', () => {
+          const vm = new Vue({
+            template: `<foo ${syntax}="foo">{{ foo }}<div>{{ foo }}</div></foo>`,
+            components: { Foo }
+          }).$mount()
+          expect(vm.$el.innerHTML).toBe(`from foo default<div>from foo default</div>`)
+        })
 
-      it('nested default slots', () => {
-        const vm = new Vue({
-          template: `
-            <foo ${syntax}="foo">
-              <bar ${syntax}="bar">
-                <baz ${syntax}="baz">
-                  {{ foo }} | {{ bar }} | {{ baz }}
-                </baz>
-              </bar>
-            </foo>
-          `,
-          components: { Foo, Bar, Baz }
-        }).$mount()
-        expect(vm.$el.innerHTML.trim()).toBe(`from foo default | from bar | from baz`)
-      })
+        it('nested default slots', () => {
+          const vm = new Vue({
+            template: `
+              <foo ${syntax}="foo">
+                <bar ${syntax}="bar">
+                  <baz ${syntax}="baz">
+                    {{ foo }} | {{ bar }} | {{ baz }}
+                  </baz>
+                </bar>
+              </foo>
+            `,
+            components: { Foo, Bar, Baz }
+          }).$mount()
+          expect(vm.$el.innerHTML.trim()).toBe(`from foo default | from bar | from baz`)
+        })
+
+        it('default + named slots', () => {
+          const vm = new Vue({
+            template: `
+              <foo ()="foo">
+                {{ foo }}
+                <template slot="one" ${syntax}="one">
+                  {{ one }}
+                </template>
+                <template slot="two" ${syntax}="two">
+                  {{ two }}
+                </template>
+              </foo>
+            `,
+            components: { Foo }
+          }).$mount()
+          expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo default from foo one from foo two`)
+        })
+
+        it('nested + named + default slots', () => {
+          const vm = new Vue({
+            template: `
+              <foo>
+                <template slot="one" ${syntax}="one">
+                  <bar ${syntax}="bar">
+                    {{ one }} {{ bar }}
+                  </bar>
+                </template>
+                <template slot="two" ${syntax}="two">
+                  <baz ${syntax}="baz">
+                    {{ two }} {{ baz }}
+                  </baz>
+                </template>
+              </foo>
+            `,
+            components: { Foo, Bar, Baz }
+          }).$mount()
+          expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from bar from foo two from baz`)
+        })
+
+        it('should warn slot-props usage on non-component elements', () => {
+          const vm = new Vue({
+            template: `<div ${syntax}="foo"/>`
+          }).$mount()
+          expect(`slot-props cannot be used on non-component elements`).toHaveBeenWarned()
+        })
+      }
+
+      // run tests for both full syntax and shorthand
+      runSuite('slot-props')
+      runSuite('()')
 
-      it('default + named slots', () => {
+      it('shorthand named slots', () => {
         const vm = new Vue({
           template: `
             <foo ()="foo">
               {{ foo }}
-              <template slot="one" ${syntax}="one">
+              <template (one)="one">
                 {{ one }}
               </template>
-              <template slot="two" ${syntax}="two">
+              <template (two)="two">
                 {{ two }}
               </template>
             </foo>
@@ -699,97 +751,47 @@ describe('Component scoped slot', () => {
         expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo default from foo one from foo two`)
       })
 
-      it('nested + named + default slots', () => {
+      it('shorthand without scope variable', () => {
         const vm = new Vue({
           template: `
             <foo>
-              <template slot="one" ${syntax}="one">
-                <bar ${syntax}="bar">
-                  {{ one }} {{ bar }}
-                </bar>
-              </template>
-              <template slot="two" ${syntax}="two">
-                <baz ${syntax}="baz">
-                  {{ two }} {{ baz }}
-                </baz>
-              </template>
+              <template (one)>one</template>
+              <template (two)>two</template>
             </foo>
           `,
-          components: { Foo, Bar, Baz }
+          components: { Foo }
         }).$mount()
-        expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from bar from foo two from baz`)
+        expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`onetwo`)
       })
 
-      it('should warn slot-props usage on non-component elements', () => {
+      it('shorthand named slots on root', () => {
         const vm = new Vue({
-          template: `<div ${syntax}="foo"/>`
+          template: `
+            <foo (one)="one">
+              {{ one }}
+            </foo>
+          `,
+          components: { Foo }
         }).$mount()
-        expect(`slot-props cannot be used on non-component elements`).toHaveBeenWarned()
+        expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one`)
       })
-    }
-
-    // run tests for both full syntax and shorthand
-    runSuite('slot-props')
-    runSuite('()')
-
-    it('shorthand named slots', () => {
-      const vm = new Vue({
-        template: `
-          <foo ()="foo">
-            {{ foo }}
-            <template (one)="one">
-              {{ one }}
-            </template>
-            <template (two)="two">
-              {{ two }}
-            </template>
-          </foo>
-        `,
-        components: { Foo }
-      }).$mount()
-      expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo default from foo one from foo two`)
-    })
 
-    it('shorthand without scope variable', () => {
-      const vm = new Vue({
-        template: `
-          <foo>
-            <template (one)>one</template>
-            <template (two)>two</template>
-          </foo>
-        `,
-        components: { Foo }
-      }).$mount()
-      expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`onetwo`)
-    })
-
-    it('shorthand named slots on root', () => {
-      const vm = new Vue({
-        template: `
-          <foo (one)="one">
-            {{ one }}
-          </foo>
-        `,
-        components: { Foo }
-      }).$mount()
-      expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one`)
-    })
-
-    it('dynamic shorthand', () => {
-      const vm = new Vue({
-        data: {
-          a: 'one',
-          b: 'two'
-        },
-        template: `
-          <foo>
-            <template :(a)="one">{{ one }} </template>
-            <template :(b)="two">{{ two }}</template>
-          </foo>
-        `,
-        components: { Foo }
-      }).$mount()
-      expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from foo two`)
+      it('dynamic shorthand', () => {
+        const vm = new Vue({
+          data: {
+            a: 'one',
+            b: 'two'
+          },
+          template: `
+            <foo>
+              <template :(a)="one">{{ one }} </template>
+              <template :(b)="two">{{ two }}</template>
+            </foo>
+          `,
+          components: { Foo }
+        }).$mount()
+        expect(vm.$el.innerHTML.replace(/\s+/g, ' ')).toMatch(`from foo one from foo two`)
+      })
     })
-  })
+  }
 })

+ 3 - 1
test/unit/karma.base.config.js

@@ -1,4 +1,5 @@
 const alias = require('../../scripts/alias')
+const featureFlags = require('../../scripts/feature-flags')
 const webpack = require('webpack')
 
 const webpackConfig = {
@@ -20,7 +21,8 @@ const webpackConfig = {
       __WEEX__: false,
       'process.env': {
         TRANSITION_DURATION: process.env.CI ? 100 : 50,
-        TRANSITION_BUFFER: 10
+        TRANSITION_BUFFER: 10,
+        ...featureFlags
       }
     })
   ],