2
0
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:
pimlie
2019-03-10 21:58:13 +01:00
parent 3db250dfea
commit 5aa94ceea3
17 changed files with 6173 additions and 92 deletions
+36
View File
@@ -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
+39
View File
@@ -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`
)
}
}
}
```
+69
View File
@@ -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>
```
+108
View File
@@ -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`
:::
+117
View File
@@ -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>`)
})
})
```