mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-10 18:02:24 +03:00
chore: add docs site
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
# Preparing the plugin
|
||||
:::tip Note
|
||||
This step is optional if you don't need SSR and `Vue` is available as a global variable. `vue-meta` will install itself in this case.
|
||||
:::
|
||||
|
||||
In order to use this plugin, you first need to pass it to `Vue.use` - if you're not rendering on the server-side, your JS entry file will suffice. If you are rendering on the server, then place it in a file that runs both on the server and on the client before your root instance is mounted. If you're using [`vue-router`](https://github.com/vuejs/vue-router), then your main `router.js` file is a good place:
|
||||
|
||||
**router.js:**
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import Meta from 'vue-meta'
|
||||
|
||||
Vue.use(Router)
|
||||
Vue.use(Meta)
|
||||
|
||||
export default new Router({
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
`vue-meta` allows a few custom options:
|
||||
|
||||
```js
|
||||
Vue.use(Meta, {
|
||||
keyName: 'metaInfo',
|
||||
attribute: 'data-vue-meta',
|
||||
ssrAttribute: 'data-vue-meta-server-rendered',
|
||||
tagIDKeyName: 'vmid',
|
||||
refreshOnceOnNavigation: true
|
||||
})
|
||||
```
|
||||
|
||||
See the [API](/api/#plugin-options) for a description of the available plugin options
|
||||
@@ -0,0 +1,39 @@
|
||||
# Caveats
|
||||
|
||||
## Reactive variables in template functions
|
||||
|
||||
Both [title](/api/#titletemplate) as [meta](/api/#content-templates) support using template function.
|
||||
Due to how Vue.js determines reactivity it is not possible to use reactive variables directly in template function
|
||||
|
||||
```js
|
||||
{
|
||||
// this wont work
|
||||
metaInfo() {
|
||||
return {
|
||||
titleTemplate: chunk => (
|
||||
this.locale === 'nl-NL'
|
||||
? `${chunk} - Welkom`
|
||||
: `${chunk} - Welcome`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You need to assign the reactive variable to a local variable for this to work:
|
||||
|
||||
```js
|
||||
{
|
||||
// this will work
|
||||
metaInfo() {
|
||||
const locale = this.locale
|
||||
return {
|
||||
titleTemplate: chunk => (
|
||||
locale === 'nl-NL'
|
||||
? `${chunk} - Welkom`
|
||||
: `${chunk} - Welcome`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
# Defining `metaInfo`
|
||||
|
||||
You can define a `[keyName]` property in any of your components, by default this is `metaInfo`.
|
||||
|
||||
See the [API](/api) for a list of recognised `metaInfo` properties
|
||||
|
||||
::: tip Note
|
||||
Altough we talk about the `metaInfo` variable on this page, please note that the keyName is [configurable](/api/#keyname) and could be different in your case. E.g. [Nuxt.js](https://nuxtjs.org/api/pages-head#the-head-method) uses `head` as keyName
|
||||
:::
|
||||
|
||||
**App.vue:**
|
||||
```html
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App',
|
||||
metaInfo: {
|
||||
// if no subcomponents specify a metaInfo.title, this title will be used
|
||||
title: 'Default Title',
|
||||
// all titles will be injected into this template
|
||||
titleTemplate: '%s | My Awesome Webapp'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**Home.vue**
|
||||
```html
|
||||
<template>
|
||||
<div id="page">
|
||||
<h1>Home Page</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Home',
|
||||
metaInfo: {
|
||||
title: 'My Awesome Webapp',
|
||||
// override the parent template and just use the above title only
|
||||
titleTemplate: null
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**About.vue**
|
||||
```html
|
||||
<template>
|
||||
<div id="page">
|
||||
<h1>About Page</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'About',
|
||||
metaInfo: {
|
||||
// title will be injected into parent titleTemplate
|
||||
title: 'About Us'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
@@ -0,0 +1,108 @@
|
||||
# Special cases
|
||||
|
||||
::: tip Read first
|
||||
Understanding [How is metaInfo resolved?](/faq/#concatenate-metadata) is probably a prerequisite for these cases
|
||||
:::
|
||||
|
||||
## Remove parent property by child
|
||||
|
||||
If a child returns `null` as content value then the parent metaInfo property with the same `vmid` will be ignored
|
||||
|
||||
:::tip Content value
|
||||
With content value we mean the following value of a `metaInfo` property:
|
||||
- the value of a key for `object` types as [`htmlAttrs`](/api/#htmlattrs)
|
||||
- the value of `[contentKeyName]` or `innerHTML` keys for `collection` types as [`meta`](/api/#meta)
|
||||
:::
|
||||
|
||||
The following might be a bit-farfetched, but its just an example
|
||||
```js
|
||||
// parent
|
||||
metaInfo: {
|
||||
style: [{
|
||||
vmid: 'page-load-overlay',
|
||||
innerHTML: `
|
||||
body div.loading {
|
||||
z-index: 999;
|
||||
background-color: #0f0f0f;
|
||||
opacity: 0.9;
|
||||
}
|
||||
`,
|
||||
}]
|
||||
}
|
||||
|
||||
// dynamically loaded child
|
||||
metaInfo() {
|
||||
const style = this.cssTexts
|
||||
return { style }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
this.cssTexts: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.cssTexts.push({
|
||||
vmid: 'page-load-overlay',
|
||||
innerHTML: null
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Use child property conditionally
|
||||
|
||||
If you wish to use a child property conditionally and use the parents' property as default value, make sure the child returns `undefined` as content value
|
||||
|
||||
:::tip Content value
|
||||
With content value we mean the following value of a `metaInfo` property:
|
||||
- the value of a key for `object` types as [`htmlAttrs`](/api/#htmlattrs)
|
||||
- the value of `[contentKeyName]` or `innerHTML` keys for `collection` types as [`meta`](/api/#meta)
|
||||
:::
|
||||
|
||||
The below example will still show a description when the GET in the child fails
|
||||
```js
|
||||
// parent
|
||||
metaInfo: {
|
||||
meta: [{
|
||||
vmid: 'description',
|
||||
name: 'description',
|
||||
content: 'my standard description',
|
||||
}]
|
||||
}
|
||||
|
||||
// child
|
||||
metaInfo() {
|
||||
return {
|
||||
meta: [{
|
||||
vmid: 'description',
|
||||
name: 'description',
|
||||
content: this.description,
|
||||
}]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
description: undefined
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getDescription() {
|
||||
this.description = this.$axios.get()
|
||||
if (!this.description) {
|
||||
// if GET request failed or returned empty,
|
||||
// explicitly set to undefined so the parents'
|
||||
// default description is used
|
||||
this.description = undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Boolean attributes
|
||||
|
||||
`vue-meta` maintains a [list](https://github.com/nuxt/vue-meta/blob/master/src/shared/constants.js) of attributes which are boolean attributes according to the HTML specs (and some extra). Whatever value you will pass to these attributes, they will be rendered as a boolean attribute.<sup>*</sup>
|
||||
|
||||
<sup>*</sup><small>Except for the special values `undefined` and `null`, see above</small>
|
||||
|
||||
:::tip Note
|
||||
Prior to `v2.0` any attribute key with `undefined` as value was rendered as boolean attribute. This has been removed as packagers often remove object properties with an `undefined` value as given `a = {}` then `a.a === undefined`
|
||||
:::
|
||||
@@ -0,0 +1,117 @@
|
||||
# Server Side Rendering
|
||||
|
||||
If you have an isomorphic/universal webapp, you'll likely want to render your metadata on the server side as well. Here's how.
|
||||
|
||||
## Add `vue-meta` to the context
|
||||
|
||||
You'll need to expose the results of the `$meta` method that `vue-meta` adds to the Vue instance to the bundle render context before you can begin injecting your meta information. You'll need to do this in your server entry file:
|
||||
|
||||
**server-entry.js:**
|
||||
```js
|
||||
import app from './app'
|
||||
|
||||
const router = app.$router
|
||||
const meta = app.$meta() // here
|
||||
|
||||
export default (context) => {
|
||||
router.push(context.url)
|
||||
context.meta = meta // and here
|
||||
return app
|
||||
}
|
||||
```
|
||||
|
||||
## Inject metadata into page string
|
||||
|
||||
Probably the easiest method to wrap your head around is if your Vue server markup is rendered out as a string using `renderToString`:
|
||||
|
||||
**server.js:**
|
||||
|
||||
```js
|
||||
app.get('*', (req, res) => {
|
||||
const context = { url: req.url }
|
||||
renderer.renderToString(context, (error, html) => {
|
||||
if (error) return res.send(error.stack)
|
||||
const {
|
||||
title, htmlAttrs, headAttrs, bodyAttrs, link,
|
||||
style, script, noscript, meta
|
||||
} = context.meta.inject()
|
||||
return res.send(`
|
||||
<!doctype html>
|
||||
<html data-vue-meta-server-rendered ${htmlAttrs.text()}>
|
||||
<head ${headAttrs.text()}>
|
||||
${meta.text()}
|
||||
${title.text()}
|
||||
${link.text()}
|
||||
${style.text()}
|
||||
${script.text()}
|
||||
${noscript.text()}
|
||||
</head>
|
||||
<body ${bodyAttrs.text()}>
|
||||
${html}
|
||||
<script src="/assets/vendor.bundle.js"></script>
|
||||
<script src="/assets/client.bundle.js"></script>
|
||||
${script.text({ body: true })}
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
If you are using a separate template file, edit your head tag with
|
||||
|
||||
```html
|
||||
<head>
|
||||
{{{ meta.inject().title.text() }}}
|
||||
{{{ meta.inject().meta.text() }}}
|
||||
</head>
|
||||
```
|
||||
|
||||
Notice the use of `{{{` to avoid double escaping. Be extremely cautious when you use `{{{` with [`__dangerouslyDisableSanitizersByTagID`](/api/#dangerouslydisablesanitizersbytagid).
|
||||
|
||||
## Inject metadata into page stream
|
||||
|
||||
|
||||
A little more complex, but well worth it, is to instead stream your response. `vue-meta` supports streaming with no effort (on it's part :stuck_out_tongue_winking_eye:) thanks to Vue's clever `bundleRenderer` context injection:
|
||||
|
||||
**server.js**
|
||||
```js
|
||||
app.get('*', (req, res) => {
|
||||
const context = { url: req.url }
|
||||
const renderStream = renderer.renderToStream(context)
|
||||
renderStream.once('data', () => {
|
||||
const {
|
||||
title, htmlAttrs, headAttrs, bodyAttrs, link,
|
||||
style, script, noscript, meta
|
||||
} = context.meta.inject()
|
||||
res.write(`
|
||||
<!doctype html>
|
||||
<html data-vue-meta-server-rendered ${htmlAttrs.text()}>
|
||||
<head ${headAttrs.text()}>
|
||||
${meta.text()}
|
||||
${title.text()}
|
||||
${link.text()}
|
||||
${style.text()}
|
||||
${script.text()}
|
||||
${noscript.text()}
|
||||
</head>
|
||||
<body ${bodyAttrs.text()}>
|
||||
`)
|
||||
})
|
||||
renderStream.on('data', (chunk) => {
|
||||
res.write(chunk)
|
||||
})
|
||||
renderStream.on('end', () => {
|
||||
res.end(`
|
||||
<script src="/assets/vendor.bundle.js"></script>
|
||||
<script src="/assets/client.bundle.js"></script>
|
||||
${script.text({ body: true })}
|
||||
</body>
|
||||
</html>
|
||||
`)
|
||||
})
|
||||
renderStream.on('error', (error) => {
|
||||
res.status(500).end(`<pre>${error.stack}</pre>`)
|
||||
})
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user