From 495f61629a7f6c4a679d7c0fbde81610c512ddff Mon Sep 17 00:00:00 2001 From: Declan de Wet Date: Thu, 10 Nov 2016 15:28:21 +0200 Subject: [PATCH 1/3] Favor function syntax over per-attribute function syntax --- README.md | 72 ++++++++++++------------------ examples/basic-render/app.js | 6 +-- examples/basic/app.js | 4 +- examples/vue-router/app.js | 6 +-- examples/vuex-async/App.vue | 10 +++++ examples/vuex-async/views/Home.vue | 5 ++- examples/vuex-async/views/Post.vue | 9 ++-- examples/vuex/App.vue | 10 +++++ examples/vuex/views/Home.vue | 5 ++- examples/vuex/views/Post.vue | 9 ++-- src/shared/getComponentOption.js | 16 ++++--- src/shared/getMetaInfo.js | 14 +----- 12 files changed, 87 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 3961e49..4601e96 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,7 @@ - [Performance](#performance) - [How to prevent the update on the initial page render](#how-to-prevent-the-update-on-the-initial-page-render) - [FAQ](#faq) - - [How do I use component data in `metaInfo`?](#how-do-i-use-component-data-in-metainfo) - - [How do I use component props in `metaInfo`?](#how-do-i-use-component-props-in-metainfo) + - [How do I use component props and/or component data in `metaInfo`?](#how-do-i-use-component-props-andor-component-data-in-metainfo) - [How do I populate `metaInfo` from the result of an asynchronous action?](#how-do-i-populate-metainfo-from-the-result-of-an-asynchronous-action) - [Examples](#examples) @@ -610,71 +609,56 @@ Add the `data-vue-meta-server-rendered` attribute to the `` tag on the ser Here are some answers to some frequently asked questions. -## How do I use component data in `metaInfo`? -Specify a function instead of an object. It will need to return the same type as its definition. +## How do I use component props and/or component data in `metaInfo`? -**BlogPost.vue:** +Easy. Instead of defining `metaInfo` as an object, define it as a function and access `this` as usual: + +**Post.vue:** ```html ``` -## How do I use component props in `metaInfo`? -The same way you use data - specify a function instead of an object. It will need to return the same type as its definition. - -**BlogPostWrapper.vue** +**PostContainer.vue:** ```html -``` - -**BlogPost.vue** -```html - - - diff --git a/examples/vuex-async/views/Home.vue b/examples/vuex-async/views/Home.vue index b97fdf7..d620373 100644 --- a/examples/vuex-async/views/Home.vue +++ b/examples/vuex-async/views/Home.vue @@ -20,7 +20,10 @@ postsCount: 'publishedPostsCount' }), metaInfo: { - title: 'Home' + title: 'Home', + meta: [ + { vmid: 'description', name: 'description', content: 'The home page' } + ] } } diff --git a/examples/vuex-async/views/Post.vue b/examples/vuex-async/views/Post.vue index c648891..5032983 100644 --- a/examples/vuex-async/views/Post.vue +++ b/examples/vuex-async/views/Post.vue @@ -28,9 +28,12 @@ 'isLoading', 'post' ]), - metaInfo: { - title () { - return this.isLoading ? 'Loading...' : this.post.title + metaInfo () { + return { + title: this.isLoading ? 'Loading...' : this.post.title, + meta: [ + { vmid: 'description', name: 'description', content: this.post.title } + ] } } } diff --git a/examples/vuex/App.vue b/examples/vuex/App.vue index 0ff3c68..5c14077 100644 --- a/examples/vuex/App.vue +++ b/examples/vuex/App.vue @@ -5,3 +5,13 @@

Inspect Element to see the meta info

+ + diff --git a/examples/vuex/views/Home.vue b/examples/vuex/views/Home.vue index b97fdf7..d620373 100644 --- a/examples/vuex/views/Home.vue +++ b/examples/vuex/views/Home.vue @@ -20,7 +20,10 @@ postsCount: 'publishedPostsCount' }), metaInfo: { - title: 'Home' + title: 'Home', + meta: [ + { vmid: 'description', name: 'description', content: 'The home page' } + ] } } diff --git a/examples/vuex/views/Post.vue b/examples/vuex/views/Post.vue index 1a1202c..26d3a3c 100644 --- a/examples/vuex/views/Post.vue +++ b/examples/vuex/views/Post.vue @@ -18,9 +18,12 @@ computed: mapGetters([ 'post' ]), - metaInfo: { - title () { - return this.post.title + metaInfo () { + return { + title: this.post.title, + meta: [ + { vmid: 'description', name: 'description', content: this.post.title } + ] } } } diff --git a/src/shared/getComponentOption.js b/src/shared/getComponentOption.js index 6667252..58e2405 100644 --- a/src/shared/getComponentOption.js +++ b/src/shared/getComponentOption.js @@ -13,26 +13,28 @@ import deepmerge from 'deepmerge' * @param {Function} opts.arrayMerge - how should arrays be merged? * @param {Object} [result={}] - result so far * @return {Object} result - final aggregated result - * @return {Object} result.mergedOption - the actual merged options - * @return {Object} result.deepestComponentWithMetaInfo - the deepest component in the heirarchy that has a `metaInfo` instance property */ -export default function getComponentOption (opts, result = { mergedOption: {} }) { +export default function getComponentOption (opts, result = {}) { const { component, option, deep, arrayMerge } = opts const { $options } = component // only collect option data if it exists if (typeof $options[option] !== 'undefined' && $options[option] !== null) { - const data = $options[option] + let data = $options[option] + + // if option is a function, replace it with it's result + if (typeof data === 'function') { + data = data.call(component) + } if (typeof data === 'object') { // merge with existing options - result.mergedOption = deepmerge(result.mergedOption, data, { + result = deepmerge(result, data, { clone: true, arrayMerge }) - result.deepestComponentWithMetaInfo = component } else { - result.mergedOption = data + result = data } } diff --git a/src/shared/getMetaInfo.js b/src/shared/getMetaInfo.js index 90cbd32..3f7fd1a 100644 --- a/src/shared/getMetaInfo.js +++ b/src/shared/getMetaInfo.js @@ -25,7 +25,7 @@ export default function getMetaInfo (component) { } // collect & aggregate all metaInfo $options - const { mergedOption: info, deepestComponentWithMetaInfo } = getComponentOption({ + const info = getComponentOption({ component, option: 'metaInfo', deep: true, @@ -71,15 +71,5 @@ export default function getMetaInfo (component) { info.base = Object.keys(info.base).length ? [info.base] : [] } - const metaInfo = deepmerge(defaultInfo, info) - - // inject component context into functions & call to normalize data - Object.keys(metaInfo).forEach((key) => { - const val = metaInfo[key] - if (typeof val === 'function') { - metaInfo[key] = val.call(deepestComponentWithMetaInfo) - } - }) - - return metaInfo + return deepmerge(defaultInfo, info) } From 6502c13793bcc9d6847308de334b2d08a15abd1c Mon Sep 17 00:00:00 2001 From: Declan de Wet Date: Thu, 10 Nov 2016 15:37:36 +0200 Subject: [PATCH 2/3] fix broken tests --- test/getComponentOption.spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/getComponentOption.spec.js b/test/getComponentOption.spec.js index 839793d..4dac96a 100644 --- a/test/getComponentOption.spec.js +++ b/test/getComponentOption.spec.js @@ -9,13 +9,13 @@ describe('getComponentOption', () => { it('returns an empty object when no matching options are found', () => { component = new Vue() - const { mergedOption } = getComponentOption({ component, option: 'noop' }) + const mergedOption = getComponentOption({ component, option: 'noop' }) expect(mergedOption).to.eql({}) }) it('fetches the given option from the given component', () => { component = new Vue({ someOption: 'foo' }) - const { mergedOption } = getComponentOption({ component, option: 'someOption' }) + const mergedOption = getComponentOption({ component, option: 'someOption' }) expect(mergedOption).to.eql('foo') }) @@ -28,7 +28,7 @@ describe('getComponentOption', () => { el: container }) - const { mergedOption } = getComponentOption({ component, option: 'foo', deep: true }) + const mergedOption = getComponentOption({ component, option: 'foo', deep: true }) expect(mergedOption).to.eql({ bar: 'baz', fizz: 'buzz' }) }) @@ -48,7 +48,7 @@ describe('getComponentOption', () => { el: container }) - const { mergedOption } = getComponentOption({ + const mergedOption = getComponentOption({ component, option: 'foo', deep: true, From beda7041d0d13815332ea5a6649eb5541554532e Mon Sep 17 00:00:00 2001 From: Declan de Wet Date: Thu, 10 Nov 2016 15:51:00 +0200 Subject: [PATCH 3/3] test getComponentOption function call --- test/getComponentOption.spec.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/getComponentOption.spec.js b/test/getComponentOption.spec.js index 4dac96a..af2e2a9 100644 --- a/test/getComponentOption.spec.js +++ b/test/getComponentOption.spec.js @@ -19,6 +19,17 @@ describe('getComponentOption', () => { expect(mergedOption).to.eql('foo') }) + it('calls a function option, injecting the component as context', () => { + component = new Vue({ + name: 'foobar', + someFunc () { + return this.$options.name + } + }) + const mergedOption = getComponentOption({ component, option: 'someFunc' }) + expect(mergedOption).to.eql('foobar') + }) + it('fetches deeply nested component options and merges them', () => { Vue.component('merge-child', { template: '
', foo: { bar: 'baz' } })