2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-06-08 10:12:27 +03:00

update readme

This commit is contained in:
Declan de Wet
2016-11-02 20:15:51 +02:00
parent 8c7934ba34
commit a7a987e858
+131 -83
View File
@@ -3,7 +3,7 @@
</p>
<h5 align="center">
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 <a href="https://github.com/nfl/react-helmet">react-helmet</a>
</h5>
<p align="center">
@@ -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(`
<!doctype html>
<html data-vue-meta-server-rendered ${metaInfo.htmlAttrs.toString()}>
<head>
${metaInfo.title.toString()}
<script>
window.__INITIAL_STATE__ = ${ !initialState
? '{}'
: serialize(initialState, { isJSON: true })
}
</script>
</head>
<body>
${html}
<script src="/assets/vendor.bundle.js"></script>
<script src="/assets/client.bundle.js"></script>
</body>
</html>
`)
}
if (error) return res.send(error.stack)
const { meta } = context
const { title, htmlAttrs, bodyAttrs } = meta.inject()
return res.send(`
<!doctype html>
<html data-vue-meta-server-rendered ${htmlAttrs.text()}>
<head>
${title.text()}
</head>
<body ${bodyAttrs.text()}>
${html}
<script src="/assets/vendor.bundle.js"></script>
<script src="/assets/client.bundle.js"></script>
</body>
</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('<!doctype html>')
renderStream.on('data', (chunk) => {
if (firstChunk) {
const metaInfo = context.meta.inject()
if (metaInfo.htmlAttrs) {
response.write(`<html data-vue-meta-server-rendered ${metaInfo.htmlAttrs.toString()}>`)
}
response.write('<head>')
if (metaInfo.title) {
response.write(metaInfo.title.toString())
}
response.write('</head><body>')
if (context.initialState) {
response.write(
`<script>window.__INITIAL_STATE__=${
serialize(context.initialState, { isJSON: true })
}</script>`
)
}
firstChunk = false
const { meta } = context
const { title, htmlAttrs, bodyAttrs } = meta.inject()
res.write(`
<!doctype html>
<html data-vue-meta-server-rendered ${htmlAttrs.text()}>
<head>
${title.text()}
</head>
<body ${bodyAttrs.text()}>
`)
}
response.write(chunk)
res.write(chunk)
})
renderStream.on('end', () => {
response.end(`
<script src="/assets/vendor.bundle.js"></script>
<script src="/assets/client.bundle.js"></script>
</body></html>
res.end(`
<script src="/assets/vendor.bundle.js"></script>
<script src="/assets/client.bundle.js"></script>
</body>
</html>
`)
})
renderStream.on('error', (error) => {
response.status(500).end(`<pre>${error.stack}</pre>`)
})
renderStream.on('error', (error) => res.status(500).end(`<pre>${error.stack}</pre>`))
})
```
@@ -307,6 +271,90 @@ In any of your components, define a `metaInfo` property:
</script>
```
### Recognized `metaInfo` Properties
#### `title` (String)
Maps to the inner-text value of the `<title>` element.
```js
{
metaInfo: {
title: 'Foo Bar'
}
}
```
```html
<title>Foo Bar</title>
```
#### `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
<title>Foo Bar - Baz</title>
```
#### `htmlAttrs` (Object)
Each **key:value** maps to the equivalent **attribute:value** of the `<html>` element.
```js
{
metaInfo: {
htmlAttrs: {
foo: 'bar',
amp: undefined
}
}
}
```
```html
<html foo="bar" amp></title>
```
#### `bodyAttrs` (Object)
Each **key:value** maps to the equivalent **attribute:value** of the `<body>` element.
```js
{
metaInfo: {
bodyAttrs: {
bar: 'baz'
}
}
}
```
```html
<body bar="baz">Foo Bar</body>
```
### 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
<parent>
<child></child>
</parent>
```
If both `<parent>` _and_ `<child>` define a `title` property inside `metaInfo`, then the `title` that gets rendered will resolve to the `title` defined inside `<child>`.
# 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.