Manage page meta info in Vue 2.0 components. SSR + Streaming supported. Inspired by react-helmet.
```html
...
```
# Table of Contents
- [Description](#description)
- [Disclaimer](#disclaimer)
- [Installation](#installation)
- [Yarn](#yarn)
- [NPM](#npm)
- [CDN](#cdn)
- [Usage](#usage)
- [Step 1: Preparing the plugin](#step-1-preparing-the-plugin)
- [Step 2: Server Rendering (Optional)](#step-2-server-rendering-optional)
- [Step 2.1: Exposing `$meta` to `bundleRenderer`](#step-21-exposing-meta-to-bundlerenderer)
- [Step 2.2: Populating the document meta info with `inject()`](#step-22-populating-the-document-meta-info-with-inject)
- [Simple Rendering with `renderToString()`](#simple-rendering-with-rendertostring)
- [Streaming Rendering with `renderToStream()`](#streaming-rendering-with-rendertostream)
- [Step 3: Start defining `metaInfo`](#step-3-start-defining-metainfo)
- [Recognized `metaInfo` Properties](#recognized-metainfo-properties)
- [`title` (String)](#title-string)
- [`titleTemplate` (String)](#titletemplate-string)
- [`htmlAttrs` (Object)](#htmlattrs-object)
- [`bodyAttrs` (Object)](#bodyattrs-object)
- [`base` (Object)](#base-object)
- [`meta` ([Object])](#meta-object)
- [`link` ([Object])](#link-object)
- [`style` ([Object])](#style-object)
- [`script` ([Object])](#script-object)
- [`noscript` ([Object])](#noscript-object)
- [`changed` (Function)](#changed-function)
- [How `metaInfo` is Resolved](#how-metainfo-is-resolved)
- [Lists of Tags](#lists-of-tags)
- [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)
# Description
`vue-meta` is a [Vue 2.0](https://vuejs.org) plugin that allows you to manage your app's meta information, much like [`react-helmet`](https://github.com/nfl/react-helmet) does for React. However, instead of setting your data as props passed to a proprietary component, you simply export it as part of your component's data using the `metaInfo` property.
These properties, when set on a deeply nested component, will cleverly overwrite their parent components' `metaInfo`, thereby enabling custom info for each top-level view as well as coupling meta info directly to deeply nested subcomponents for more maintainable code.
# Disclaimer
**Please note** that this project is still in very early alpha development and is *not* considered to be production ready.
**You have been warned.** There is no sanitization yet, no tests, and you might even find some features are still missing.
# Installation
### Yarn
```sh
$ yarn add vue-meta
```
### NPM
```sh
$ npm install vue-meta --save
```
### CDN
Use the links below - if you want a previous version, check the instructions at https://unpkg.com.
**Uncompressed:**
```html
```
**Minified:**
```html
```
# Usage
## Step 1: Preparing the plugin
> 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({
...
})
```
If you don't care about server-side rendering, you can skip straight to [step 3](#step-3-start-defining-metainfo). Otherwise, continue. :smile:
## Step 2: Server Rendering (Optional)
If you have an isomorphic/universal webapp, you'll likely want to render your metadata on the server side as well. Here's how.
### Step 2.1: Exposing `$meta` to `bundleRenderer`
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
}
```
### Step 2.2: Populating the document meta info with `inject()`
All that's left for you to do now before you can begin using `metaInfo` options in your components is to make sure they work on the server by `inject`-ing them so you can call `text()` on each item to render out the necessary info. You have two methods at your disposal:
#### Simple Rendering with `renderToString()`
Considerably the easiest method to wrap your head around is if your Vue server markup is rendered out as a string:
**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, bodyAttrs, link, style, script, noscript, meta
} = context.meta.inject()
return res.send(`
${meta.text()}
${title.text()}
${link.text()}
${style.text()}
${script.text()}
${noscript.text()}
${html}
`)
})
})
```
#### Streaming Rendering with `renderToStream()`
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, bodyAttrs, link, style, script, noscript, meta
} = context.meta.inject()
res.write(`
${meta.text()}
${title.text()}
${link.text()}
${style.text()}
${script.text()}
${noscript.text()}
`)
})
renderStream.on('data', (chunk) => {
res.write(chunk)
})
renderStream.on('end', () => {
res.end(`
`)
})
renderStream.on('error', (error) => res.status(500).end(`
${error.stack}
`))
})
```
## Step 3: Start defining `metaInfo`
In any of your components, define a `metaInfo` property:
**App.vue:**
```html
```
**Home.vue**
```html
Home Page
```
**About.vue**
```html
About Page
```
### Recognized `metaInfo` Properties
#### `title` (String)
Maps to the inner-text value of the `` element.
```js
{
metaInfo: {
title: 'Foo Bar'
}
}
```
```html
Foo Bar
```
#### `titleTemplate` (String)
The value of `title` will be injected into the `%s` placeholder in `titleTemplate` before being rendered. The original title will be available on `metaInfo.titleChunk`.
```js
{
metaInfo: {
title: 'Foo Bar',
titleTemplate: '%s - Baz'
}
}
```
```html
Foo Bar - Baz
```
#### `htmlAttrs` (Object)
Each **key:value** maps to the equivalent **attribute:value** of the `` element.
```js
{
metaInfo: {
htmlAttrs: {
foo: 'bar',
amp: undefined
}
}
}
```
```html
```
#### `bodyAttrs` (Object)
Each **key:value** maps to the equivalent **attribute:value** of the `` element.
```js
{
metaInfo: {
bodyAttrs: {
bar: 'baz'
}
}
}
```
```html
Foo Bar
```
#### `base` (Object)
Maps to a newly-created `` element, where object properties map to attributes.
```js
{
metaInfo: {
base: { target: '_blank', href: '/' }
}
}
```
```html
```
#### `meta` ([Object])
Each item in the array maps to a newly-created `` element, where object properties map to attributes.
```js
{
metaInfo: {
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
]
}
}
```
```html
```
#### `link` ([Object])
Each item in the array maps to a newly-created `` element, where object properties map to attributes.
```js
{
metaInfo: {
link: [
{ rel: 'stylesheet', src: '/css/index.css' },
{ rel: 'favicon', src: 'favicon.ico' }
]
}
}
```
```html
```
#### `style` ([Object])
Each item in the array maps to a newly-created `
```
#### `script` ([Object])
Each item in the array maps to a newly-created `
```
#### `noscript` ([Object])
Each item in the array maps to a newly-created `