mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-23 18:20:34 +03:00
feat: add option to refresh once during navigation (possible fix for #320)
chore: add es build chore: global window detection chore: small refactor improvements
This commit is contained in:
@@ -64,6 +64,7 @@
|
|||||||
- [`__dangerouslyDisableSanitizers` ([String])](#__dangerouslydisablesanitizers-string)
|
- [`__dangerouslyDisableSanitizers` ([String])](#__dangerouslydisablesanitizers-string)
|
||||||
- [`__dangerouslyDisableSanitizersByTagID` ({[String]})](#__dangerouslydisablesanitizersbytagid-string)
|
- [`__dangerouslyDisableSanitizersByTagID` ({[String]})](#__dangerouslydisablesanitizersbytagid-string)
|
||||||
- [`changed` (Function)](#changed-function)
|
- [`changed` (Function)](#changed-function)
|
||||||
|
- [`refreshOnceOnNavigation` (Boolean)](#refreshonceonnavigation-boolean)
|
||||||
- [How `metaInfo` is Resolved](#how-metainfo-is-resolved)
|
- [How `metaInfo` is Resolved](#how-metainfo-is-resolved)
|
||||||
- [Lists of Tags](#lists-of-tags)
|
- [Lists of Tags](#lists-of-tags)
|
||||||
- [Performance](#performance)
|
- [Performance](#performance)
|
||||||
@@ -652,6 +653,11 @@ Will be called when the client `metaInfo` updates/changes. Receives the followin
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `refreshOnceOnNavigation` (Boolean)
|
||||||
|
|
||||||
|
Default `false`. If set to `true` then vue-meta will pause updating `metaInfo` during page navigation with vue-router and only refresh once when navigation has finished. It does this by adding a global beforeEach and afterEach navigation guard on the $router instance.
|
||||||
|
|
||||||
|
|
||||||
### How `metaInfo` is Resolved
|
### 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:
|
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:
|
||||||
|
|||||||
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -rf lib es
|
||||||
|
|
||||||
|
echo 'Compile JS...'
|
||||||
|
rollup -c scripts/rollup.config.js
|
||||||
|
echo 'Done.'
|
||||||
|
echo ''
|
||||||
|
|
||||||
|
echo 'Build ES modules...'
|
||||||
|
NODE_ENV=es babel src --out-dir es --ignore 'src/browser.js'
|
||||||
|
echo 'Done.'
|
||||||
|
echo ''
|
||||||
|
|
||||||
|
echo 'Done building assets.'
|
||||||
+5
-2
@@ -2,6 +2,9 @@ import { pause, resume } from '../shared/pausing'
|
|||||||
import refresh from './refresh'
|
import refresh from './refresh'
|
||||||
|
|
||||||
export default function _$meta(options = {}) {
|
export default function _$meta(options = {}) {
|
||||||
|
const _refresh = refresh(options)
|
||||||
|
const inject = () => {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an injector for server-side rendering.
|
* Returns an injector for server-side rendering.
|
||||||
* @this {Object} - the Vue instance (a root component)
|
* @this {Object} - the Vue instance (a root component)
|
||||||
@@ -9,8 +12,8 @@ export default function _$meta(options = {}) {
|
|||||||
*/
|
*/
|
||||||
return function $meta() {
|
return function $meta() {
|
||||||
return {
|
return {
|
||||||
inject: () => {},
|
refresh: _refresh.bind(this),
|
||||||
refresh: refresh(options).bind(this),
|
inject,
|
||||||
pause: pause.bind(this),
|
pause: pause.bind(this),
|
||||||
resume: resume.bind(this)
|
resume: resume.bind(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import batchUpdate from './batchUpdate'
|
||||||
|
|
||||||
|
// store an id to keep track of DOM updates
|
||||||
|
let batchId = null
|
||||||
|
|
||||||
|
export default function triggerUpdate(vm, hookName) {
|
||||||
|
if (vm.$root._vueMetaInitialized && !vm.$root._vueMetaPaused) {
|
||||||
|
// batch potential DOM updates to prevent extraneous re-rendering
|
||||||
|
batchId = batchUpdate(batchId, () => {
|
||||||
|
vm.$meta().refresh()
|
||||||
|
batchId = null
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -3,6 +3,9 @@ import { pause, resume } from '../shared/pausing'
|
|||||||
import inject from './inject'
|
import inject from './inject'
|
||||||
|
|
||||||
export default function _$meta(options = {}) {
|
export default function _$meta(options = {}) {
|
||||||
|
const _refresh = refresh(options)
|
||||||
|
const _inject = inject(options)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an injector for server-side rendering.
|
* Returns an injector for server-side rendering.
|
||||||
* @this {Object} - the Vue instance (a root component)
|
* @this {Object} - the Vue instance (a root component)
|
||||||
@@ -10,8 +13,8 @@ export default function _$meta(options = {}) {
|
|||||||
*/
|
*/
|
||||||
return function $meta() {
|
return function $meta() {
|
||||||
return {
|
return {
|
||||||
inject: inject(options).bind(this),
|
refresh: _refresh.bind(this),
|
||||||
refresh: refresh(options).bind(this),
|
inject: _inject.bind(this),
|
||||||
pause: pause.bind(this),
|
pause: pause.bind(this),
|
||||||
resume: resume.bind(this)
|
resume: resume.bind(this)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import isArray from './isArray'
|
||||||
|
import { isObject } from './typeof'
|
||||||
|
|
||||||
|
export function ensureIsArray(arg, key) {
|
||||||
|
if (key && isObject(arg)) {
|
||||||
|
if (!isArray(arg[key])) {
|
||||||
|
arg[key] = []
|
||||||
|
}
|
||||||
|
return arg
|
||||||
|
} else {
|
||||||
|
return isArray(arg) ? arg : []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ensuredPush(object, key, el) {
|
||||||
|
ensureIsArray(object, key)
|
||||||
|
|
||||||
|
object[key].push(el)
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import deepmerge from 'deepmerge'
|
import deepmerge from 'deepmerge'
|
||||||
import uniqueId from 'lodash.uniqueid'
|
import uniqueId from 'lodash.uniqueid'
|
||||||
import { isUndefined, isFunction, isObject } from '../shared/typeof'
|
import { isUndefined, isFunction, isObject } from './typeof'
|
||||||
import uniqBy from './uniqBy'
|
import uniqBy from './uniqBy'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+15
-1
@@ -43,15 +43,29 @@ export default function createMixin(options) {
|
|||||||
this.$root._vueMetaInitialized = this.$isServer
|
this.$root._vueMetaInitialized = this.$isServer
|
||||||
|
|
||||||
if (!this.$root._vueMetaInitialized) {
|
if (!this.$root._vueMetaInitialized) {
|
||||||
|
const $rootMeta = this.$root.$meta()
|
||||||
|
|
||||||
ensuredPush(this.$options, 'mounted', () => {
|
ensuredPush(this.$options, 'mounted', () => {
|
||||||
if (!this.$root._vueMetaInitialized) {
|
if (!this.$root._vueMetaInitialized) {
|
||||||
// refresh meta in nextTick so all child components have loaded
|
// refresh meta in nextTick so all child components have loaded
|
||||||
this.$nextTick(function () {
|
this.$nextTick(function () {
|
||||||
this.$root.$meta().refresh()
|
$rootMeta.refresh()
|
||||||
this.$root._vueMetaInitialized = true
|
this.$root._vueMetaInitialized = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// add vue-router navigation guard to prevent multiple updates during navigation
|
||||||
|
// only usefull on the client side
|
||||||
|
if (options.refreshOnceOnNavigation && this.$root.$router) {
|
||||||
|
const $router = this.$root.$router
|
||||||
|
$router.beforeEach((to, from, next) => {
|
||||||
|
$rootMeta.pause()
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
$router.afterEach(() => $rootMeta.resume())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { isObject } from '../shared/typeof'
|
import { isObject } from './typeof'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
keyName,
|
keyName,
|
||||||
attribute,
|
attribute,
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export function pause(refresh = true) {
|
||||||
|
this.$root._vueMetaPaused = true
|
||||||
|
|
||||||
|
return () => resume(refresh)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resume(refresh = true) {
|
||||||
|
this.$root._vueMetaPaused = false
|
||||||
|
|
||||||
|
if (refresh) {
|
||||||
|
return this.$root.$meta().refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { isUndefined } from './typeof'
|
||||||
|
|
||||||
|
export function hasGlobalWindowFn() {
|
||||||
|
try {
|
||||||
|
return !isUndefined(window)
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hasGlobalWindow = hasGlobalWindowFn()
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import _getMetaInfo from '../src/shared/getMetaInfo'
|
||||||
|
import { defaultOptions, loadVueMetaPlugin } from './utils'
|
||||||
|
|
||||||
|
const getMetaInfo = (component, escapeSequences) => _getMetaInfo(defaultOptions, component, escapeSequences)
|
||||||
|
|
||||||
|
describe('escaping', () => {
|
||||||
|
let Vue
|
||||||
|
|
||||||
|
beforeAll(() => (Vue = loadVueMetaPlugin()))
|
||||||
|
|
||||||
|
test('special chars are escaped unless disabled', () => {
|
||||||
|
const component = new Vue({
|
||||||
|
metaInfo: {
|
||||||
|
title: 'Hello & Goodbye',
|
||||||
|
script: [{ innerHTML: 'Hello & Goodbye' }],
|
||||||
|
__dangerouslyDisableSanitizers: ['script']
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(getMetaInfo(component, [[/&/g, '&']])).toEqual({
|
||||||
|
title: 'Hello & Goodbye',
|
||||||
|
titleChunk: 'Hello & Goodbye',
|
||||||
|
titleTemplate: '%s',
|
||||||
|
htmlAttrs: {},
|
||||||
|
headAttrs: {},
|
||||||
|
bodyAttrs: {},
|
||||||
|
meta: [],
|
||||||
|
base: [],
|
||||||
|
link: [],
|
||||||
|
style: [],
|
||||||
|
script: [{ innerHTML: 'Hello & Goodbye' }],
|
||||||
|
noscript: [],
|
||||||
|
__dangerouslyDisableSanitizers: ['script'],
|
||||||
|
__dangerouslyDisableSanitizersByTagID: {}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user