From a7a987e858a50892befcd8dd18b391ca15e188d5 Mon Sep 17 00:00:00 2001 From: Declan de Wet Date: Wed, 2 Nov 2016 20:15:51 +0200 Subject: [PATCH] update readme --- README.md | 214 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 131 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 306b164..35b5140 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

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

@@ -54,6 +54,12 @@ - [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) + - [How `metaInfo` is Resolved](#how-metainfo-is-resolved) - [Performance](#performance) - [How to prevent the update on the initial page render](#how-to-prevent-the-update-on-the-initial-page-render) - [FAQ](#faq) @@ -120,29 +126,18 @@ You'll need to expose the results of the `$meta` method that `vue-meta` adds to import app from './app' const router = app.$router -const store = app.$store const meta = app.$meta() // here export default (context) => { router.push(context.url) - return Promise.all( - router.getMatchedComponents().map( - (component) => component.preFetch - ? component.preFetch(store) - : component - ) - ) - .then(() => { - context.initialState = store.state - context.meta = meta // and here - return app - }) + 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. You have two methods at your disposal: +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()` @@ -151,40 +146,27 @@ Considerably the easiest method to wrap your head around is if your Vue server m **server.js:** ```js -... -app.get('*', (request, response) => { - const context = { url: request.url } - +app.get('*', (req, res) => { + const context = { url: req.url } renderer.renderToString(context, (error, html) => { - if (error) { - ... - } else { - const { initialState, meta } = context - const metaInfo = meta.inject() - - response.send(` - - - - ${metaInfo.title.toString()} - - - - ${html} - - - - - `) - } + if (error) return res.send(error.stack) + const { meta } = context + const { title, htmlAttrs, bodyAttrs } = meta.inject() + return res.send(` + + + + ${title.text()} + + + ${html} + + + + + `) }) }) -... ``` #### Streaming Rendering with `renderToStream()` @@ -193,53 +175,35 @@ A little more complex, but well worth it, is to instead stream your response. `v **server.js** ```js -app.get('*', (request, response) => { - const context = { url: request.url } +app.get('*', (req, res) => { + const context = { url: req.url } const renderStream = renderer.renderToStream(context) let firstChunk = true - - response.write('') - renderStream.on('data', (chunk) => { if (firstChunk) { - const metaInfo = context.meta.inject() - - if (metaInfo.htmlAttrs) { - response.write(``) - } - - response.write('') - - if (metaInfo.title) { - response.write(metaInfo.title.toString()) - } - - response.write('') - - if (context.initialState) { - response.write( - `` - ) - } - firstChunk = false + const { meta } = context + const { title, htmlAttrs, bodyAttrs } = meta.inject() + res.write(` + + + + ${title.text()} + + + `) } - response.write(chunk) + res.write(chunk) }) - renderStream.on('end', () => { - response.end(` - - - + res.end(` + + + + `) }) - - renderStream.on('error', (error) => { - response.status(500).end(`

${error.stack}
`) - }) + renderStream.on('error', (error) => res.status(500).end(`
${error.stack}
`)) }) ``` @@ -307,6 +271,90 @@ In any of your components, define a `metaInfo` property: ``` +### 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. + +```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 +``` + +### How `metaInfo` is Resolved + +You can define a `metaInfo` property on any component in the tree. Child components that have `metaInfo` will recursively merge their `metaInfo` into the parent context, overwriting any duplicate properties. To better illustrate, consider this component heirarchy: + +```html + + + +``` + +If both `` _and_ `` define a `title` property inside `metaInfo`, then the `title` that gets rendered will resolve to the `title` defined inside ``. + # Performance On the client, `vue-meta` batches DOM updates using [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame). It needs to do this because it registers a Vue mixin that subscribes to the [`beforeMount`](https://vuejs.org/api/#beforeMount) lifecycle hook on all components in order to be notified that renders have occurred and data is ready. If `vue-meta` did not batch updates, the DOM meta info would be re-calculated and re-updated for every component on the page in quick-succession.