2
0
mirror of https://github.com/tenrok/vue-meta.git synced 2026-06-24 02:40:33 +03:00

feat: add support for global inject options (#568)

* feat: add support for global inject options

* feat: use isSSR instead of isSpa
This commit is contained in:
Pim
2020-06-07 13:51:59 +02:00
committed by GitHub
parent 92350d5f7d
commit 8b02eb2ac6
8 changed files with 45 additions and 20 deletions
+7 -1
View File
@@ -190,12 +190,16 @@ Updates the current metadata with new metadata.
Useful when updating metadata as the result of an asynchronous action that resolves after the initial render takes place. Useful when updating metadata as the result of an asynchronous action that resolves after the initial render takes place.
### $meta().inject ### $meta().inject
- arguments
- injectOptions (type: `object`) <Badge text="v2.4+"/>
- returns [`metaInfo`](/api/#metaInfo-properties) - returns [`metaInfo`](/api/#metaInfo-properties)
:::tip SSR only :::tip SSR only
`inject` is available in the server plugin only and is not available on the client `inject` is available in the server plugin only and is not available on the client
::: :::
You can pass an object to inject with global inject options. See [SSR injection method arguments](/api/#noscript-text) for a list of available options.
It returns a special `metaInfo` object where all keys have an object as value which contains a `text()` method for returning html code It returns a special `metaInfo` object where all keys have an object as value which contains a `text()` method for returning html code
See [Rendering with renderToString](/guide/ssr.html#simple-rendering-with-rendertostring) for an example See [Rendering with renderToString](/guide/ssr.html#simple-rendering-with-rendertostring) for an example
@@ -809,7 +813,9 @@ See the [SSR guide](/guide/ssr.html#inject-metadata-into-page-string) for more i
### script.text ### script.text
### noscript.text ### noscript.text
- arguments - arguments
- options (type: `object`, default: `{ ln: false , body: false, pbody: false }`) - options (type: `object`, default: `{ isSSR: true, ln: false , body: false, pbody: false }`)
Set `isSSR: false` if you generate a SPA on server side and want to use the default appId `1` instead of [ssrAppId](/api/#ssrappid)
The `body` and `pbody` props can be used to support positioning of elements in your template, see [SSR Support](#ssr-support) The `body` and `pbody` props can be used to support positioning of elements in your template, see [SSR Support](#ssr-support)
+20 -10
View File
@@ -9,7 +9,7 @@ import { titleGenerator, attributeGenerator, tagGenerator } from './generators'
* @return {Object} - the new injector * @return {Object} - the new injector
*/ */
export default function generateServerInjector (options, metaInfo) { export default function generateServerInjector (options, metaInfo, globalInjectOptions) {
const serverInjector = { const serverInjector = {
data: metaInfo, data: metaInfo,
extraData: undefined, extraData: undefined,
@@ -23,15 +23,16 @@ export default function generateServerInjector (options, metaInfo) {
// only call title for the head // only call title for the head
return (opts.body || opts.pbody ? '' : m.title.text(opts)) + return (opts.body || opts.pbody ? '' : m.title.text(opts)) +
m.meta.text(opts) + m.meta.text(opts) +
m.base.text(opts) +
m.link.text(opts) + m.link.text(opts) +
m.style.text(opts) + m.style.text(opts) +
m.script.text(opts) + m.script.text(opts) +
m.noscript.text(opts) m.noscript.text(opts)
}, },
injectors: { injectors: {
head: ln => serverInjector.callInjectors({ ln }), head: ln => serverInjector.callInjectors({ ...globalInjectOptions, ln }),
bodyPrepend: ln => serverInjector.callInjectors({ ln, pbody: true }), bodyPrepend: ln => serverInjector.callInjectors({ ...globalInjectOptions, ln, pbody: true }),
bodyAppend: ln => serverInjector.callInjectors({ ln, body: true }) bodyAppend: ln => serverInjector.callInjectors({ ...globalInjectOptions, ln, body: true })
} }
} }
@@ -41,9 +42,17 @@ export default function generateServerInjector (options, metaInfo) {
} }
serverInjector.injectors[type] = { serverInjector.injectors[type] = {
text (arg) { text (injectOptions) {
const addSsrAttribute = injectOptions === true
injectOptions = {
addSsrAttribute,
...globalInjectOptions,
...injectOptions
}
if (type === 'title') { if (type === 'title') {
return titleGenerator(options, type, serverInjector.data[type], arg) return titleGenerator(options, type, serverInjector.data[type], injectOptions)
} }
if (metaInfoAttributeKeys.includes(type)) { if (metaInfoAttributeKeys.includes(type)) {
@@ -51,9 +60,10 @@ export default function generateServerInjector (options, metaInfo) {
const data = serverInjector.data[type] const data = serverInjector.data[type]
if (data) { if (data) {
const appId = injectOptions.isSSR === false ? '1' : options.ssrAppId
for (const attr in data) { for (const attr in data) {
attributeData[attr] = { attributeData[attr] = {
[options.ssrAppId]: data[attr] [appId]: data[attr]
} }
} }
} }
@@ -72,15 +82,15 @@ export default function generateServerInjector (options, metaInfo) {
} }
} }
return attributeGenerator(options, type, attributeData, arg) return attributeGenerator(options, type, attributeData, injectOptions)
} }
let str = tagGenerator(options, type, serverInjector.data[type], arg) let str = tagGenerator(options, type, serverInjector.data[type], injectOptions)
if (serverInjector.extraData) { if (serverInjector.extraData) {
for (const appId in serverInjector.extraData) { for (const appId in serverInjector.extraData) {
const data = serverInjector.extraData[appId][type] const data = serverInjector.extraData[appId][type]
const extraStr = tagGenerator(options, type, data, { appId, ...arg }) const extraStr = tagGenerator(options, type, data, { appId, ...injectOptions })
str = `${str}${extraStr}` str = `${str}${extraStr}`
} }
} }
+2 -2
View File
@@ -7,7 +7,7 @@ import { booleanHtmlAttributes } from '../../shared/constants'
* @param {Object} data - the attributes to generate * @param {Object} data - the attributes to generate
* @return {Object} - the attribute generator * @return {Object} - the attribute generator
*/ */
export default function attributeGenerator (options, type, data, addSrrAttribute) { export default function attributeGenerator (options, type, data, { addSsrAttribute }) {
const { attribute, ssrAttribute } = options || {} const { attribute, ssrAttribute } = options || {}
let attributeStr = '' let attributeStr = ''
@@ -32,7 +32,7 @@ export default function attributeGenerator (options, type, data, addSrrAttribute
attributeStr += `${attribute}="${encodeURI(JSON.stringify(data))}"` attributeStr += `${attribute}="${encodeURI(JSON.stringify(data))}"`
} }
if (type === 'htmlAttrs' && addSrrAttribute) { if (type === 'htmlAttrs' && addSsrAttribute) {
return `${ssrAttribute}${attributeStr ? ' ' : ''}${attributeStr}` return `${ssrAttribute}${attributeStr ? ' ' : ''}${attributeStr}`
} }
+2 -2
View File
@@ -16,7 +16,7 @@ import {
*/ */
export default function tagGenerator (options, type, tags, generatorOptions) { export default function tagGenerator (options, type, tags, generatorOptions) {
const { ssrAppId, attribute, tagIDKeyName } = options || {} const { ssrAppId, attribute, tagIDKeyName } = options || {}
const { appId, body = false, pbody = false, ln = false } = generatorOptions || {} const { appId, isSSR = true, body = false, pbody = false, ln = false } = generatorOptions || {}
const dataAttributes = [tagIDKeyName, ...commonDataAttributes] const dataAttributes = [tagIDKeyName, ...commonDataAttributes]
@@ -40,7 +40,7 @@ export default function tagGenerator (options, type, tags, generatorOptions) {
return tagsStr return tagsStr
} }
let attrs = tag.once ? '' : ` ${attribute}="${appId || ssrAppId}"` let attrs = tag.once ? '' : ` ${attribute}="${appId || (isSSR === false ? '1' : ssrAppId)}"`
// build a string containing all attributes of this tag // build a string containing all attributes of this tag
for (const attr in tag) { for (const attr in tag) {
+2 -2
View File
@@ -13,7 +13,7 @@ import generateServerInjector from './generateServerInjector'
* @vm {Object} - Vue instance - ideally the root component * @vm {Object} - Vue instance - ideally the root component
* @return {Object} - server meta info with `toString` methods * @return {Object} - server meta info with `toString` methods
*/ */
export default function inject (rootVm, options) { export default function inject (rootVm, options, injectOptions) {
// make sure vue-meta was initiated // make sure vue-meta was initiated
if (!rootVm[rootConfigKey]) { if (!rootVm[rootConfigKey]) {
showWarningNotSupported() showWarningNotSupported()
@@ -26,7 +26,7 @@ export default function inject (rootVm, options) {
const metaInfo = getMetaInfo(options, rawInfo, serverSequences, rootVm) const metaInfo = getMetaInfo(options, rawInfo, serverSequences, rootVm)
// generate server injector // generate server injector
const serverInjector = generateServerInjector(options, metaInfo) const serverInjector = generateServerInjector(options, metaInfo, injectOptions)
// add meta info from additional apps // add meta info from additional apps
const appsMetaInfo = getAppsMetaInfo() const appsMetaInfo = getAppsMetaInfo()
+1 -1
View File
@@ -38,7 +38,7 @@ export default function $meta (options) {
} }
}, },
refresh: () => refresh($root, options), refresh: () => refresh($root, options),
inject: () => process.server ? inject($root, options) : showWarningNotSupportedInBrowserBundle('inject'), inject: injectOptions => process.server ? inject($root, options, injectOptions) : showWarningNotSupportedInBrowserBundle('inject'),
pause: () => pause($root), pause: () => pause($root),
resume: () => resume($root), resume: () => resume($root),
addApp: appId => addApp($root, appId, options) addApp: appId => addApp($root, appId, options)
+10 -1
View File
@@ -139,11 +139,20 @@ describe('components', () => {
warn.mockRestore() warn.mockRestore()
}) })
test('meta-info can be rendered with inject', () => { test('meta-info can be rendered with inject (ssr)', () => {
const wrapper = mount(HelloWorld, { localVue: Vue }) const wrapper = mount(HelloWorld, { localVue: Vue })
const metaInfo = wrapper.vm.$meta().inject() const metaInfo = wrapper.vm.$meta().inject()
expect(metaInfo.title.text()).toEqual('<title>Hello World</title>') expect(metaInfo.title.text()).toEqual('<title>Hello World</title>')
expect(metaInfo.meta.text()).toContain('<meta data-vue-meta="ssr" charset="utf-8">')
})
test('meta-info can be rendered with inject (spa)', () => {
const wrapper = mount(HelloWorld, { localVue: Vue })
const metaInfo = wrapper.vm.$meta().inject({ isSSR: false, ln: true })
expect(metaInfo.title.text()).toEqual('<title>Hello World</title>\n')
expect(metaInfo.meta.text()).toContain('<meta data-vue-meta="1" charset="utf-8">\n')
}) })
test('inject also renders additional app info', () => { test('inject also renders additional app info', () => {
+1 -1
View File
@@ -135,7 +135,7 @@ describe('extra tests', () => {
expect(meta.bodyPrepend(true)).toBe('<script data-vue-meta="test-app" src="/script.js" data-pbody="true"></script>\n') expect(meta.bodyPrepend(true)).toBe('<script data-vue-meta="test-app" src="/script.js" data-pbody="true"></script>\n')
expect(meta.bodyAppend()).toBe('<script data-vue-meta="ssr" src="/script.js" data-body="true"></script>') expect(meta.bodyAppend()).toBe('<script data-vue-meta="ssr" src="/script.js" data-body="true"></script>')
expect(meta.htmlAttrs.text()).toBe('lang="en" data-vue-meta="%7B%22lang%22:%7B%22ssr%22:%22en%22%7D%7D"') expect(meta.htmlAttrs.text({ ln: true })).toBe('lang="en" data-vue-meta="%7B%22lang%22:%7B%22ssr%22:%22en%22%7D%7D"')
expect(meta.bodyAttrs.text()).toBe('class="base-class extra-class" data-vue-meta="%7B%22class%22:%7B%22ssr%22:%22base-class%22,%22test-app%22:%22extra-class%22%7D%7D"') expect(meta.bodyAttrs.text()).toBe('class="base-class extra-class" data-vue-meta="%7B%22class%22:%7B%22ssr%22:%22base-class%22,%22test-app%22:%22extra-class%22%7D%7D"')
}) })
}) })