Skip to content

feat($core): introduce vue meta to replace the current meta strategy fix #2153 #2661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/@vuepress/core/lib/client/app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* global VUEPRESS_TEMP_PATH */
import Vue from 'vue'
import VueMeta from 'vue-meta'
import Router from 'vue-router'
import dataMixin from './dataMixin'
import { routes } from '@internal/routes'
Expand Down Expand Up @@ -33,6 +34,7 @@ if (module.hot) {
Vue.config.productionTip = false

Vue.use(Router)
Vue.use(VueMeta, { refreshOnceOnNavigation: true })
Vue.use(VuePress)
// mixin for exposing $site and $page
Vue.mixin(dataMixin(ClientComputedMixin, siteData))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export default {
}
return 'NotFound'
}
},
metaInfo () {
return this.$vuepressMeta
}
}
</script>
8 changes: 3 additions & 5 deletions packages/@vuepress/core/lib/client/index.ssr.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<!DOCTYPE html>
<html lang="{{ lang }}">
<html {{{ meta.inject().htmlAttrs.text(true) }}}>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{{ title }}</title>
<meta name="generator" content="VuePress {{ version }}">
{{{ userHeadTags }}}
{{{ pageMeta }}}
{{{ canonicalLink }}}
{{{ meta.inject().meta.text() }}}
{{{ meta.inject().title.text() }}}
{{{ renderResourceHints() }}}
{{{ renderStyles() }}}
</head>
Expand Down
139 changes: 2 additions & 137 deletions packages/@vuepress/core/lib/client/root-mixins/updateMeta.js
Original file line number Diff line number Diff line change
@@ -1,139 +1,4 @@
import unionBy from 'lodash/unionBy'

export default {
// created will be called on both client and ssr
created () {
this.siteMeta = this.$site.headTags
.filter(([headerType]) => headerType === 'meta')
.map(([_, headerValue]) => headerValue)

if (this.$ssrContext) {
const mergedMetaItems = this.getMergedMetaTags()

this.$ssrContext.title = this.$title
this.$ssrContext.lang = this.$lang
this.$ssrContext.pageMeta = renderPageMeta(mergedMetaItems)
this.$ssrContext.canonicalLink = renderCanonicalLink(this.$canonicalUrl)
}
},
// Other life cycles will only be called at client
mounted () {
// init currentMetaTags from DOM
this.currentMetaTags = [...document.querySelectorAll('meta')]

// update title / meta tags
this.updateMeta()
this.updateCanonicalLink()
},

methods: {
updateMeta () {
document.title = this.$title
document.documentElement.lang = this.$lang

const newMetaTags = this.getMergedMetaTags()
this.currentMetaTags = updateMetaTags(newMetaTags, this.currentMetaTags)
},

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, this.siteMeta, metaIdentifier)
},

updateCanonicalLink () {
removeCanonicalLink()

if (!this.$canonicalUrl) {
return
}

document.head.insertAdjacentHTML('beforeend', renderCanonicalLink(this.$canonicalUrl))
}
},

watch: {
$page () {
this.updateMeta()
this.updateCanonicalLink()
}
},

beforeDestroy () {
updateMetaTags(null, this.currentMetaTags)
removeCanonicalLink()
}
}

function removeCanonicalLink () {
const canonicalEl = document.querySelector("link[rel='canonical']")

if (canonicalEl) {
canonicalEl.remove()
}
}

function renderCanonicalLink (link = '') {
if (!link) {
return ''
}
return `<link href="${link}" rel="canonical" />`
}

/**
* Replace currentMetaTags with newMetaTags
* @param {Array<Object>} newMetaTags
* @param {Array<HTMLElement>} currentMetaTags
* @returns {Array<HTMLElement>}
*/
function updateMetaTags (newMetaTags, currentMetaTags) {
if (currentMetaTags) {
[...currentMetaTags]
.filter(c => c.parentNode === document.head)
.forEach(c => document.head.removeChild(c))
}
if (newMetaTags) {
return newMetaTags.map(m => {
const tag = document.createElement('meta')
Object.keys(m).forEach(key => {
tag.setAttribute(key, m[key])
})
document.head.appendChild(tag)
return tag
})
}
}

/**
* 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)
}

/**
* Render meta tags
*
* @param {Array} meta
* @returns {String}
*/

function renderPageMeta (meta) {
if (!meta) return ''
return meta.map(m => {
let res = `<meta`
Object.keys(m).forEach(key => {
res += ` ${key}="${m[key]}"`
})
return res + `>`
}).join('\n ')
// File shouldn't be needed any longer since we're no relying on vue-meta
// TODO: Remove references to this file since it's no longer used
}
3 changes: 3 additions & 0 deletions packages/@vuepress/core/lib/client/serverEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createApp } from './app'

export default context => new Promise((resolve, reject) => {
createApp(true /* isServer */).then(({ app, router }) => {
const meta = app.$meta()
const { url } = context
const { fullPath } = router.resolve(url).route

Expand All @@ -11,6 +12,8 @@ export default context => new Promise((resolve, reject) => {

// error handled in onReady
router.push(url).catch(() => {})

context.meta = meta
router.onReady(() => resolve(app), reject)
})
})
37 changes: 37 additions & 0 deletions packages/@vuepress/core/lib/node/ClientComputedMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,43 @@ module.exports = siteData => {
return this.$localeConfig.title || this.$site.title || ''
}

get $vuepressMeta () {
const { links, metas } = this.$site.headTags.reduce((acc, [headerType, headerValue]) => {
acc[headerType + 's'].push(headerValue)
return acc
}, { metas: [], links: [] })

let head = {
title: this.$title,
meta: [
...metas
],
link: [
...links
],
htmlAttrs: {
lang: this.$lang
}
}

if (this.$canonicalUrl) {
head.links.push(
{
rel: 'canonical',
href: this.$canonicalUrl
}
)
}

const { vueMeta } = this.$frontmatter

if (vueMeta) {
head = { ...head, ...vueMeta }
}

return head
}

get $canonicalUrl () {
const { canonical } = this.$page.frontmatter

Expand Down
1 change: 1 addition & 0 deletions packages/@vuepress/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"url-loader": "^1.0.1",
"vue": "^2.6.10",
"vue-loader": "^15.7.1",
"vue-meta": "^2.4.0",
"vue-router": "^3.4.5",
"vue-server-renderer": "^2.6.10",
"vue-template-compiler": "^2.6.10",
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4981,6 +4981,11 @@ deepmerge@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-1.5.2.tgz#10499d868844cdad4fee0842df8c7f6f0c95a753"

deepmerge@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==

default-gateway@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
Expand Down Expand Up @@ -13716,6 +13721,13 @@ vue-loader@^15.7.1:
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"

vue-meta@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/vue-meta/-/vue-meta-2.4.0.tgz#a419fb4b4135ce965dab32ec641d1989c2ee4845"
integrity sha512-XEeZUmlVeODclAjCNpWDnjgw+t3WA6gdzs6ENoIAgwO1J1d5p1tezDhtteLUFwcaQaTtayRrsx7GL6oXp/m2Jw==
dependencies:
deepmerge "^4.2.2"

vue-router@^3.4.5:
version "3.4.5"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.4.5.tgz#d396ec037b35931bdd1e9b7edd86f9788dc15175"
Expand Down