2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-06-10 11:52:25 +03:00

docs: update docs with new features (#416)

This commit is contained in:
Pim
2019-07-24 16:06:50 +02:00
committed by GitHub
parent 253108afac
commit 8f441899ef
8 changed files with 264 additions and 28 deletions
+2
View File
@@ -46,6 +46,7 @@ module.exports = {
'/guide/metainfo',
'/guide/special',
'/guide/caveats',
'/guide/multiple-apps',
]
},
{
@@ -57,6 +58,7 @@ module.exports = {
'/faq/prevent-initial.md',
'/faq/component-props.md',
'/faq/async-action.md',
'/faq/chaining.md',
]
}
]
+157 -22
View File
@@ -30,7 +30,7 @@ See [How to prevent update on page load](/faq/prevent-initial)
- type `string`
- default `ssr`
The app id for a server side rendered app. You shouldnt have to change this normallygit s
The app id for a server side rendered app. You shouldnt have to change this normally
### tagIDKeyName
- type `string`
@@ -89,6 +89,10 @@ It returns a special `metaInfo` object where all keys have an object as value wh
See [Rendering with renderToString](/guide/ssr.html#simple-rendering-with-rendertostring) for an example
#### Passing arguments to `text()`
In some cases you can pass an argument to the text method. E.g. to [automatically add the ssrAttribute on ssr](/faq/prevent-initial.html) or [render properties in the body](/api/#ssr-support)
### $meta().pause
- arguments:
- refresh (type `boolean`, default `false`)
@@ -229,10 +233,12 @@ Since `v1.5.0`, you can now set up meta templates that work similar to the title
meta: [
{ charset: 'utf-8' },
{
'property': 'og:title',
'content': 'Test title',
'template': chunk => `${chunk} - My page`, //or as string template: '%s - My page',
'vmid': 'og:title'
property: 'og:title',
content: 'Test title',
// following template options are identical
// template: '%s - My page',
template: chunk => `${chunk} - My page`,
vmid: 'og:title'
}
]
}
@@ -304,7 +310,37 @@ Each item in the array maps to a newly-created `<script>` element, where object
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" async defer></script>
```
#### Add json or other raw data
#### Add JSON data (since v2.1)
If you wish to use a JSON variable within a script tag (e.g. for JSON-LD), you can directly pass your variable by using the `json` property.
::: tip
When passing an array or object to the `json` property the keys and values of the variable will still be sanitized to prevent XSS
:::
```js
{
metaInfo: {
script: [{
type: 'application/ld+json'
json: {
'@context': 'http://schema.org',
unsafe: '<p>hello</p>'
}
}]
}
}
```
```html
<script type="application/ld+json">
{ "@context": "http://schema.org", "unsafe": "&lt;p&gt;hello&lt;/p&gt;" }
</script>
```
#### Add other raw data
::: warning
You have to disable sanitizers so the content of `innerHTML` won't be escaped. Please see [__dangerouslyDisableSanitizersByTagID](/api/#dangerouslydisablesanitizersbytagid) for more info on related risks
:::
@@ -327,22 +363,6 @@ You have to disable sanitizers so the content of `innerHTML` won't be escaped. P
```html
<script type="application/ld+json">{ "@context": "http://schema.org" }</script>
```
#### Special attribute: `body: true`
If you e.g. wish to force delayed execution of a script or just want the script to be included in the `<body>` of the page, add `body: true`.
Script tags with `body: true` are rendered just before `</body>`
```js
{
metaInfo: {
script: [{
innerHTML: 'console.log("I am in body");',
type: 'text/javascript',
body: true
}]
}
}
```
### noscript
- type `collection`
@@ -474,3 +494,118 @@ The callback receives the following arguments:
}
```
## Special metaInfo attributes
These attributes define specific features when used in a metaInfo property
### once
When adding a metaInfo property that should be added once without reactivity (thus will never be updated) you can add `once: true` to the property.
```js
{
metaInfo: {
link: [{
once: true,
rel: 'stylesheet'
href: 'style.css'
}]
}
}
```
### skip _(since v2.1)_
When a metaInfo property has a `skip` attribute with truthy value it will not be rendered. This attribute helps with e.g. chaining scripts (see [callback attribute](#callback-since-v2-1))
```js
{
metaInfo: {
script: [{
skip: true,
innerHTML: 'console.log("you wont see me")'
}]
}
}
```
### body
### pbody _(since v2.1)_
tags
::: warning
VueMeta supports the body and pbody attributes on all metaInfo properties, but its up to you or your framework to support these attributes during SSR
Using these body attributes without SSR support could result in hydration errors / re-rendering or missing tags.
:::
You can filter tags to be included in the `<body>` instead of the `<head>` to e.g. force delayed execution of a script.
Use `pbody: true` if you wish to prepend the tag to the body (so its rendered just after `<body>`) or use `body: true` to append the tag to the body (the tag is rendered just before `</body>`).
```js
{
metaInfo: {
script: [{
innerHTML: 'console.log("I am in body");',
type: 'text/javascript',
body: true
}]
}
}
```
#### SSR Support
When rendering your template on SSR make sure to pass an object as first argument to the text method of the metaInfo property with either a value `body: true` or `pbody: true`
```html
<head>
<!-- render script tags in HEAD, no argument -->
${script.text()}
</head>
<body>
${script.text({ pbody: true })}
<div id="app"></div>
${script.text({ body: true })}
</body>
```
### callback _(since v2.1)_
:::tip vmid required on SSR
When using SSR it is required to define a [`vmid`](/api/#tagidkeyname) property for the metaInfo property
The vmid is needed to resolve the corresponding callback for that element on hydration
:::
The callback attribute should specificy a function which is called once the corresponding tag has been loaded (i.e. the onload event is triggered). Use this to chain javascript if one depends on the other.
```js
{
metaInfo() {
return {
script: [
{
vmid: 'extscript',
src: '/my-external-script.js',
callback: () => (this.externalLoaded = true)
},
{
skip: !this.externalLoaded,
innerHTML: `
/* this is only added once external script has been loaded */
/* and e.g. window.$externalVar exists */
`
}
]
}
},
data() {
return {
externalLoaded: false
}
}
}
+10
View File
@@ -0,0 +1,10 @@
# How to chain metaInfo which are depending on each other
Since v2.1 you can add a [callback attribute](/api/#callback-since-v2-1) to your metaInfo proerties which you can use to chain loading.
If you e.g. need to load an external script before you can implement functionality based on that external script, you can use the [callback](/api/#callback-since-v2-1) and [skip](/api/#skip-since-v2-1) attributes to implement chaining of those scripts. See the API entry of the callback attribute for an [example](/api/#callback-since-v2-1)
::: tip
The callback / onload event is supported on `link`, `style` and `script` metaInfo properties
:::
+9 -3
View File
@@ -1,9 +1,15 @@
# How to prevent update on page load
Add the `data-vue-meta-server-rendered` attribute to the `<html>` tag on the server-side:
In your template call the text method of `htmlAttrs` with `true` as first argument:
```
<html {{ htmlAttrs.text(true) }}>
...
```
```html
<html data-vue-meta-server-rendered>
Or manually add the [`data-vue-meta-server-rendered`](/api/#ssrattribute) attribute to the `<html>` tag on the server-side:
```
<html data-vue-meta-server-rendered <%= meta.htmlAttrs.text() %>>
...
```
+35
View File
@@ -2,6 +2,8 @@
## Reactive variables in template functions
_Corresponding issue_: [#322](https://github.com/nuxt/vue-meta/issues/322)
Both [title](/api/#titletemplate) as [meta](/api/#content-templates) support using template function.
Due to how Vue determines reactivity it is not possible to use reactive variables directly in template functions
@@ -37,3 +39,36 @@ You need to assign the reactive variable to a local variable first for this to w
}
}
```
## Duplicated tags after hydration with SSR
_Corresponding issue_: [#404](https://github.com/nuxt/vue-meta/issues/404)
:::tip
Please read [Multiple Vue apps support](/guide/multiple-apps.html#ssr) as a prerequisite
:::
To optimize performance, VueMeta will only initialize for a Vue app when it finds a metaInfo property on any of the loaded components. That means if you render all your components by passing the component instance directly to the render function, Vue will only know of these components once the app gets mounted (see snippet below). And this means VueMeta is unable to find any metaInfo when it looks if its need to initialize in the `beforeCreate` hook and the appId will not be changed to the [ssrAppId](/api#ssrappid)
```js
/* this is an example of when metaInfo will only become available once the
* app is mounted and VueMeta will not correctly initialize the SSR app
*/
const myComponent = {
metaInfo: {
title: 'title'
}
}
export default App {
name: 'myApp',
render(h) {
return h(myComponent)
}
};
```
This will result in all the metaInfo properties of your ssr app to be rendered twice, once with [ssrAppId](/api#ssrappid) and once with appId `1`.
To prevent this, either make sure there is any metaInfo configured (on any component) when the `beforeCreate` hook runs. Alternative (but not recommended) you could set [ssrAppId](/api#ssrappid) to `1` as well.
+37
View File
@@ -0,0 +1,37 @@
# Multiple Vue apps support
VueMeta includes basic support for using multiple Vue-apps which each adds their own metaInfo properties to the same html page.
To keep track of which tag has been added by which Vue app, VueMeta stores an unique `appId` in the [data-vue-meta](/api/#attribute) attribute.
::: danger
Currently VueMeta only supports adding tags for multiple apps.
Adding [html](/api/#htmlattrs), [head](/api/#headattrs) or [body](/api/#bodyattrs) attributes is **not** supported. These will always be set to the values of the last app which triggered a metaInfo update.
Therefore it is recommended you should only set those attributes from one of your Vue apps
:::
## Client
On the client side the `appId` starts at `1` and is incremented by one for each subsequent Vue app
## SSR
For an SSR app which is served by a Node.js server, the appId would change for each request if we would increment it as on the client. Therefore we use the special [ssrAppId](/api#ssrappid) so the `appId` is constant for every request.
On hydration VueMeta will check if the Vue app was server-rendered and if so set it's appId to [ssrAppId](/api#ssrappid) as well.
## `vmid` support
::: warning
Support for cross-app vmid's might be insufficient for real world applications.
:::
It is possible to use cross app [vmid](/api/#tagidkeyname)'s with two important caveats:
- _The value of the last updated app is used_<br/>
Cross app vmid's only work on the client. This is implemented through the use of querySelectors, not by merging metaInfo objects. This means the last app which was refreshed determines the value that is used
- _There is no fallback to use the vmid of a previous app_<br/>
Given app1 and app2 both with a metaInfo property with vmid1, then when app2 removes its value for vmid1 there is no way to retrieve app1's value for vmid1 which means the element is removed
+13 -2
View File
@@ -37,7 +37,7 @@ app.get('*', (req, res) => {
} = context.meta.inject()
return res.send(`
<!doctype html>
<html data-vue-meta-server-rendered ${htmlAttrs.text()}>
<html ${htmlAttrs.text(true)}>
<head ${headAttrs.text()}>
${meta.text()}
${title.text()}
@@ -47,10 +47,22 @@ app.get('*', (req, res) => {
${noscript.text()}
</head>
<body ${bodyAttrs.text()}>
<!-- prepended metaInfo properties -->
${style.text({ pbody: true })}
${script.text({ pbody: true })}
${noscript.text({ pbody: true })}
<!-- app -->
${html}
<!-- webpack assets -->
<script src="/assets/vendor.bundle.js"></script>
<script src="/assets/client.bundle.js"></script>
<!-- appended metaInfo properties -->
${style.text({ body: true })}
${script.text({ body: true })}
${noscript.text({ body: true })}
</body>
</html>
`)
@@ -71,7 +83,6 @@ Notice the use of `{{{` to avoid double escaping. Be extremely cautious when you
## 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**
+1 -1
View File
@@ -1,5 +1,5 @@
<!doctype html>
<html data-vue-meta-server-rendered {{ htmlAttrs.text() }}>
<html {{ htmlAttrs.text(true) }}>
<head {{ headAttrs.text() }}>
{{ meta.text() }}
{{ title.text() }}