From 5a02e2a79d9660e1a903c2c2f026f2cb773b49d9 Mon Sep 17 00:00:00 2001 From: ludanxer Date: Sun, 2 Feb 2020 18:15:25 +0800 Subject: [PATCH 1/8] fix: duplicate meta in ssr --- .../@vuepress/core/lib/client/index.ssr.html | 1 - .../@vuepress/core/lib/node/build/index.js | 23 ------------------- 2 files changed, 24 deletions(-) diff --git a/packages/@vuepress/core/lib/client/index.ssr.html b/packages/@vuepress/core/lib/client/index.ssr.html index 1c5e66bc8c..2dda53994f 100644 --- a/packages/@vuepress/core/lib/client/index.ssr.html +++ b/packages/@vuepress/core/lib/client/index.ssr.html @@ -7,7 +7,6 @@ {{{ userHeadTags }}} - {{{ pageMeta }}} {{{ renderResourceHints() }}} {{{ renderStyles() }}} diff --git a/packages/@vuepress/core/lib/node/build/index.js b/packages/@vuepress/core/lib/node/build/index.js index 912eca8c23..f124693ad5 100644 --- a/packages/@vuepress/core/lib/node/build/index.js +++ b/packages/@vuepress/core/lib/node/build/index.js @@ -138,14 +138,9 @@ module.exports = class Build extends EventEmitter { readline.cursorTo(process.stdout, 0) process.stdout.write(`Rendering page: ${pagePath}`) - // #565 Avoid duplicate description meta at SSR. - const meta = (page.frontmatter && page.frontmatter.meta || []).filter(item => item.name !== 'description') - const pageMeta = renderPageMeta(meta) - const context = { url: page.path, userHeadTags: this.userHeadTags, - pageMeta, title: 'VuePress', lang: 'en', description: '', @@ -225,24 +220,6 @@ function renderAttrs (attrs = {}) { } } -/** - * Render meta tags - * - * @param {Array} meta - * @returns {Array} - */ - -function renderPageMeta (meta) { - if (!meta) return '' - return meta.map(m => { - let res = ` { - res += ` ${key}="${escape(m[key])}"` - }) - return res + `>` - }).join('') -} - /** * find and remove empty style chunk caused by * https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85 From 147d61920d5eeb2b1f05b858732a07f37cea2e92 Mon Sep 17 00:00:00 2001 From: ludanxer Date: Mon, 24 Feb 2020 17:51:13 +0800 Subject: [PATCH 2/8] fix: page metas have higher priority --- .../core/lib/client/root-mixins/updateMeta.js | 65 +++++++++++++------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js index bfa818be2d..f224e6965e 100644 --- a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js +++ b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js @@ -1,3 +1,5 @@ +import unionBy from 'lodash/unionBy' + export default { created () { if (this.$ssrContext) { @@ -8,8 +10,19 @@ export default { }, mounted () { + // init currentMetaTags from DOM + this.currentMetaTags = [...document.querySelectorAll('meta')] + + // indirectly init siteMetaTags from DOM + this.siteMetaTags = this.currentMetaTags.map(element => { + const siteMeta = {} + for (const attribute of element.attributes) { + siteMeta[attribute.name] = attribute.value + } + return siteMeta + }) + // update title / meta tags - this.currentMetaTags = new Set() this.updateMeta() }, @@ -17,22 +30,14 @@ export default { updateMeta () { document.title = this.$title document.documentElement.lang = this.$lang - const userMeta = this.$page.frontmatter.meta || [] - const meta = userMeta.slice(0) - const useGlobalDescription = userMeta.filter(m => m.name === 'description').length === 0 - // #665 Avoid duplicate description meta at runtime. - if (useGlobalDescription) { - meta.push({ name: 'description', content: this.$description }) - } + const pageMetaTags = (this.$page.frontmatter.meta || []).slice(0) + // pageMetaTags have higher priority than siteMetaTags + // description needs special attention for it has too many entries + const newMetaTags = unionBy([{ name: 'description', content: this.$description }], + pageMetaTags, this.siteMetaTags, metaIdentifier) - // Including description meta coming from SSR. - const descriptionMetas = document.querySelectorAll('meta[name="description"]') - if (descriptionMetas.length) { - descriptionMetas.forEach(m => this.currentMetaTags.add(m)) - } - - this.currentMetaTags = new Set(updateMetaTags(meta, this.currentMetaTags)) + this.currentMetaTags = updateMetaTags(newMetaTags, this.currentMetaTags) } }, @@ -47,14 +52,20 @@ export default { } } -function updateMetaTags (meta, current) { - if (current) { - [...current].forEach(c => { +/** + * Replace currentMetaTags with newMetaTags + * @param {Array} newMetaTags + * @param {Array} currentMetaTags + * @returns {Array} + */ +function updateMetaTags (newMetaTags, currentMetaTags) { + if (currentMetaTags) { + [...currentMetaTags].forEach(c => { document.head.removeChild(c) }) } - if (meta) { - return meta.map(m => { + if (newMetaTags) { + return newMetaTags.map(m => { const tag = document.createElement('meta') Object.keys(m).forEach(key => { tag.setAttribute(key, m[key]) @@ -64,3 +75,17 @@ function updateMetaTags (meta, current) { }) } } + +/** + * Try to identify a meta tag by name, property or itemprop + * + * Return a complete string if none provided + * @param {Object} tag from frontmatter or siteMetaTags + * @returns {String} + */ +function metaIdentifier (tag) { + for (const item of ['name', 'property', 'itemprop']) { + if (tag.hasOwnProperty(item)) return tag[item] + item + } + return JSON.stringify(tag) +} From 4f50deb8351f31fba718e5adf2c2e485d1b92fe1 Mon Sep 17 00:00:00 2001 From: ludanxer Date: Wed, 26 Feb 2020 11:46:24 +0800 Subject: [PATCH 3/8] Revert "fix: duplicate meta in ssr" This reverts commit 5a02e2a79d9660e1a903c2c2f026f2cb773b49d9. --- .../@vuepress/core/lib/client/index.ssr.html | 1 + .../@vuepress/core/lib/node/build/index.js | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/packages/@vuepress/core/lib/client/index.ssr.html b/packages/@vuepress/core/lib/client/index.ssr.html index 2dda53994f..1c5e66bc8c 100644 --- a/packages/@vuepress/core/lib/client/index.ssr.html +++ b/packages/@vuepress/core/lib/client/index.ssr.html @@ -7,6 +7,7 @@ {{{ userHeadTags }}} + {{{ pageMeta }}} {{{ renderResourceHints() }}} {{{ renderStyles() }}} diff --git a/packages/@vuepress/core/lib/node/build/index.js b/packages/@vuepress/core/lib/node/build/index.js index f124693ad5..912eca8c23 100644 --- a/packages/@vuepress/core/lib/node/build/index.js +++ b/packages/@vuepress/core/lib/node/build/index.js @@ -138,9 +138,14 @@ module.exports = class Build extends EventEmitter { readline.cursorTo(process.stdout, 0) process.stdout.write(`Rendering page: ${pagePath}`) + // #565 Avoid duplicate description meta at SSR. + const meta = (page.frontmatter && page.frontmatter.meta || []).filter(item => item.name !== 'description') + const pageMeta = renderPageMeta(meta) + const context = { url: page.path, userHeadTags: this.userHeadTags, + pageMeta, title: 'VuePress', lang: 'en', description: '', @@ -220,6 +225,24 @@ function renderAttrs (attrs = {}) { } } +/** + * Render meta tags + * + * @param {Array} meta + * @returns {Array} + */ + +function renderPageMeta (meta) { + if (!meta) return '' + return meta.map(m => { + let res = ` { + res += ` ${key}="${escape(m[key])}"` + }) + return res + `>` + }).join('') +} + /** * find and remove empty style chunk caused by * https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85 From f6ca3973e61d42100b5133afade7e37e2123bc1e Mon Sep 17 00:00:00 2001 From: ludanxer Date: Thu, 27 Feb 2020 09:38:04 +0800 Subject: [PATCH 4/8] fix: render meta tags during ssr --- .../@vuepress/core/lib/client/index.ssr.html | 1 - .../core/lib/client/root-mixins/updateMeta.js | 42 +++++++++++++++---- packages/@vuepress/core/lib/node/App.js | 2 +- .../@vuepress/core/lib/node/build/index.js | 28 ++----------- 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/packages/@vuepress/core/lib/client/index.ssr.html b/packages/@vuepress/core/lib/client/index.ssr.html index 1c5e66bc8c..351c008efe 100644 --- a/packages/@vuepress/core/lib/client/index.ssr.html +++ b/packages/@vuepress/core/lib/client/index.ssr.html @@ -4,7 +4,6 @@ {{ title }} - {{{ userHeadTags }}} {{{ pageMeta }}} diff --git a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js index f224e6965e..21e3433176 100644 --- a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js +++ b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js @@ -1,14 +1,21 @@ import unionBy from 'lodash/unionBy' export default { + // created will be called on both client and ssr created () { if (this.$ssrContext) { + const siteMetaTags = this.$site.headTags + .filter(item => item[0] === 'meta') + .map(item => item[1]) + + const meta = this.getMergedMetaTags(siteMetaTags) + this.$ssrContext.title = this.$title this.$ssrContext.lang = this.$lang - this.$ssrContext.description = this.$page.description || this.$description + this.$ssrContext.pageMeta = renderPageMeta(meta) } }, - + // Other life cycles will only be called at client mounted () { // init currentMetaTags from DOM this.currentMetaTags = [...document.querySelectorAll('meta')] @@ -31,13 +38,16 @@ export default { document.title = this.$title document.documentElement.lang = this.$lang - const pageMetaTags = (this.$page.frontmatter.meta || []).slice(0) + const newMetaTags = this.getMergedMetaTags(this.siteMetaTags) + this.currentMetaTags = updateMetaTags(newMetaTags, this.currentMetaTags) + }, + + getMergedMetaTags (siteMeta) { + const pageMeta = (this.$page.frontmatter.meta || []).slice(0) // pageMetaTags have higher priority than siteMetaTags // description needs special attention for it has too many entries - const newMetaTags = unionBy([{ name: 'description', content: this.$description }], - pageMetaTags, this.siteMetaTags, metaIdentifier) - - this.currentMetaTags = updateMetaTags(newMetaTags, this.currentMetaTags) + return unionBy([{ name: 'description', content: this.$description }], + pageMeta, siteMeta, metaIdentifier) } }, @@ -89,3 +99,21 @@ function metaIdentifier (tag) { } return JSON.stringify(tag) } + +/** + * Render meta tags + * + * @param {Array} meta + * @returns {Array} + */ + +function renderPageMeta (meta) { + if (!meta) return '' + return meta.map(m => { + let res = ` { + res += ` ${key}="${m[key]}"` + }) + return res + `>` + }).join('\n ') +} diff --git a/packages/@vuepress/core/lib/node/App.js b/packages/@vuepress/core/lib/node/App.js index 2a6cdc261b..a6d17320ff 100755 --- a/packages/@vuepress/core/lib/node/App.js +++ b/packages/@vuepress/core/lib/node/App.js @@ -438,6 +438,7 @@ module.exports = class App { title: this.siteConfig.title || '', description: this.siteConfig.description || '', base: this.base, + headTags: this.siteConfig.head || [], pages: this.pages.map(page => page.toJson()), themeConfig: this.siteConfig.themeConfig || {}, locales @@ -499,4 +500,3 @@ module.exports = class App { return this } } - diff --git a/packages/@vuepress/core/lib/node/build/index.js b/packages/@vuepress/core/lib/node/build/index.js index 912eca8c23..78279026de 100644 --- a/packages/@vuepress/core/lib/node/build/index.js +++ b/packages/@vuepress/core/lib/node/build/index.js @@ -77,9 +77,11 @@ module.exports = class Build extends EventEmitter { }) // pre-render head tags from user config + // filter out meta tags for they will be injected in updateMeta.js this.userHeadTags = (this.context.siteConfig.head || []) + .filter(item => item[0] !== 'meta') .map(renderHeadTag) - .join('\n ') + .join('\n ') // if the user does not have a custom 404.md, generate the theme's default if (!this.context.pages.some(p => p.path === '/404.html')) { @@ -138,14 +140,10 @@ module.exports = class Build extends EventEmitter { readline.cursorTo(process.stdout, 0) process.stdout.write(`Rendering page: ${pagePath}`) - // #565 Avoid duplicate description meta at SSR. - const meta = (page.frontmatter && page.frontmatter.meta || []).filter(item => item.name !== 'description') - const pageMeta = renderPageMeta(meta) - const context = { url: page.path, userHeadTags: this.userHeadTags, - pageMeta, + pageMeta: null, title: 'VuePress', lang: 'en', description: '', @@ -225,24 +223,6 @@ function renderAttrs (attrs = {}) { } } -/** - * Render meta tags - * - * @param {Array} meta - * @returns {Array} - */ - -function renderPageMeta (meta) { - if (!meta) return '' - return meta.map(m => { - let res = ` { - res += ` ${key}="${escape(m[key])}"` - }) - return res + `>` - }).join('') -} - /** * find and remove empty style chunk caused by * https://github.com/webpack-contrib/mini-css-extract-plugin/issues/85 From 0f91886d1e109fd6da982676c65f2fdbac4ed313 Mon Sep 17 00:00:00 2001 From: Sun Haoran Date: Thu, 19 Mar 2020 09:33:54 +0800 Subject: [PATCH 5/8] improve readability from suggestions Co-Authored-By: Franck Abgrall --- .../core/lib/client/root-mixins/updateMeta.js | 10 +++++----- packages/@vuepress/core/lib/node/build/index.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js index 21e3433176..2851199b93 100644 --- a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js +++ b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js @@ -5,14 +5,14 @@ export default { created () { if (this.$ssrContext) { const siteMetaTags = this.$site.headTags - .filter(item => item[0] === 'meta') - .map(item => item[1]) + .filter(([headerType])=> headerType === 'meta') + .map(([_, headerValue])=> headerValue) - const meta = this.getMergedMetaTags(siteMetaTags) + const mergedMetaItems = this.getMergedMetaTags(siteMetaTags) this.$ssrContext.title = this.$title this.$ssrContext.lang = this.$lang - this.$ssrContext.pageMeta = renderPageMeta(meta) + this.$ssrContext.pageMeta = renderPageMeta(mergedMetaItems) } }, // Other life cycles will only be called at client @@ -45,7 +45,7 @@ export default { getMergedMetaTags (siteMeta) { const pageMeta = (this.$page.frontmatter.meta || []).slice(0) // pageMetaTags have higher priority than siteMetaTags - // description needs special attention for it has too many entries + // description needs special attention as it has too many entries return unionBy([{ name: 'description', content: this.$description }], pageMeta, siteMeta, metaIdentifier) } diff --git a/packages/@vuepress/core/lib/node/build/index.js b/packages/@vuepress/core/lib/node/build/index.js index 78279026de..afec955fdd 100644 --- a/packages/@vuepress/core/lib/node/build/index.js +++ b/packages/@vuepress/core/lib/node/build/index.js @@ -79,7 +79,7 @@ module.exports = class Build extends EventEmitter { // pre-render head tags from user config // filter out meta tags for they will be injected in updateMeta.js this.userHeadTags = (this.context.siteConfig.head || []) - .filter(item => item[0] !== 'meta') + .filter(([headTagType]) => headTagType !== 'meta') .map(renderHeadTag) .join('\n ') From 1e77cf3beae1b6564f5fd23eaec3cb068e07cc31 Mon Sep 17 00:00:00 2001 From: ludanxer Date: Thu, 19 Mar 2020 09:44:26 +0800 Subject: [PATCH 6/8] fix: missing spaces --- packages/@vuepress/core/lib/client/root-mixins/updateMeta.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js index 2851199b93..66cdddeccc 100644 --- a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js +++ b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js @@ -5,8 +5,8 @@ export default { created () { if (this.$ssrContext) { const siteMetaTags = this.$site.headTags - .filter(([headerType])=> headerType === 'meta') - .map(([_, headerValue])=> headerValue) + .filter(([headerType]) => headerType === 'meta') + .map(([_, headerValue]) => headerValue) const mergedMetaItems = this.getMergedMetaTags(siteMetaTags) From 257f0ab80fe6f8f2c27d67991bee41a227ec481f Mon Sep 17 00:00:00 2001 From: ludanxer Date: Thu, 19 Mar 2020 10:00:04 +0800 Subject: [PATCH 7/8] refactor: remove unnecessary code --- packages/@vuepress/core/lib/client/root-mixins/updateMeta.js | 2 +- packages/@vuepress/core/lib/node/build/index.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js index 66cdddeccc..39f6ebcaf9 100644 --- a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js +++ b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js @@ -43,7 +43,7 @@ export default { }, getMergedMetaTags (siteMeta) { - const pageMeta = (this.$page.frontmatter.meta || []).slice(0) + const pageMeta = this.$page.frontmatter.meta || [] // pageMetaTags have higher priority than siteMetaTags // description needs special attention as it has too many entries return unionBy([{ name: 'description', content: this.$description }], diff --git a/packages/@vuepress/core/lib/node/build/index.js b/packages/@vuepress/core/lib/node/build/index.js index afec955fdd..c323acae5b 100644 --- a/packages/@vuepress/core/lib/node/build/index.js +++ b/packages/@vuepress/core/lib/node/build/index.js @@ -143,7 +143,6 @@ module.exports = class Build extends EventEmitter { const context = { url: page.path, userHeadTags: this.userHeadTags, - pageMeta: null, title: 'VuePress', lang: 'en', description: '', From a853352c166623500b5a89a8c3bb8fa58e8416e4 Mon Sep 17 00:00:00 2001 From: ludanxer Date: Thu, 19 Mar 2020 12:03:06 +0800 Subject: [PATCH 8/8] fix: siteMetaTags aren't correctly init Previous method will init siteMetaTags with entry page meta tags instead of site meta tags --- .../core/lib/client/root-mixins/updateMeta.js | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js index 39f6ebcaf9..5b5228c138 100644 --- a/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js +++ b/packages/@vuepress/core/lib/client/root-mixins/updateMeta.js @@ -3,12 +3,12 @@ import unionBy from 'lodash/unionBy' export default { // created will be called on both client and ssr created () { - if (this.$ssrContext) { - const siteMetaTags = this.$site.headTags - .filter(([headerType]) => headerType === 'meta') - .map(([_, headerValue]) => headerValue) + this.siteMeta = this.$site.headTags + .filter(([headerType]) => headerType === 'meta') + .map(([_, headerValue]) => headerValue) - const mergedMetaItems = this.getMergedMetaTags(siteMetaTags) + if (this.$ssrContext) { + const mergedMetaItems = this.getMergedMetaTags() this.$ssrContext.title = this.$title this.$ssrContext.lang = this.$lang @@ -20,15 +20,6 @@ export default { // init currentMetaTags from DOM this.currentMetaTags = [...document.querySelectorAll('meta')] - // indirectly init siteMetaTags from DOM - this.siteMetaTags = this.currentMetaTags.map(element => { - const siteMeta = {} - for (const attribute of element.attributes) { - siteMeta[attribute.name] = attribute.value - } - return siteMeta - }) - // update title / meta tags this.updateMeta() }, @@ -38,16 +29,16 @@ export default { document.title = this.$title document.documentElement.lang = this.$lang - const newMetaTags = this.getMergedMetaTags(this.siteMetaTags) + const newMetaTags = this.getMergedMetaTags() this.currentMetaTags = updateMetaTags(newMetaTags, this.currentMetaTags) }, - getMergedMetaTags (siteMeta) { + getMergedMetaTags () { const pageMeta = this.$page.frontmatter.meta || [] // pageMetaTags have higher priority than siteMetaTags // description needs special attention as it has too many entries return unionBy([{ name: 'description', content: this.$description }], - pageMeta, siteMeta, metaIdentifier) + pageMeta, this.siteMeta, metaIdentifier) } },