vue-meta

Manage page meta info in Vue 2.0 components. SSR + Streaming supported. Inspired by react-helmet.

Standard - JavaScript Style

github release npm version Build Status codecov
dependencies Status devDependencies Status
npm downloads Gitter

```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 ``` **About.vue** ```html ``` ### Recognized `metaInfo` Properties #### `title` (String) Maps to the inner-text value of the `` element. ```js { metaInfo: { title: 'Foo Bar' } } ``` ```html <title>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 `