Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for global inject options #568

Merged
merged 2 commits into from
Jun 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion docs/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

### $meta().inject
- arguments
- injectOptions (type: `object`) <Badge text="v2.4+"/>
- returns [`metaInfo`](/api/#metaInfo-properties)

:::tip SSR only
`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

See [Rendering with renderToString](/guide/ssr.html#simple-rendering-with-rendertostring) for an example
Expand Down Expand Up @@ -809,7 +813,9 @@ See the [SSR guide](/guide/ssr.html#inject-metadata-into-page-string) for more i
### script.text
### noscript.text
- 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)

Expand Down
30 changes: 20 additions & 10 deletions src/server/generateServerInjector.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { titleGenerator, attributeGenerator, tagGenerator } from './generators'
* @return {Object} - the new injector
*/

export default function generateServerInjector (options, metaInfo) {
export default function generateServerInjector (options, metaInfo, globalInjectOptions) {
const serverInjector = {
data: metaInfo,
extraData: undefined,
Expand All @@ -23,15 +23,16 @@ export default function generateServerInjector (options, metaInfo) {
// only call title for the head
return (opts.body || opts.pbody ? '' : m.title.text(opts)) +
m.meta.text(opts) +
m.base.text(opts) +
m.link.text(opts) +
m.style.text(opts) +
m.script.text(opts) +
m.noscript.text(opts)
},
injectors: {
head: ln => serverInjector.callInjectors({ ln }),
bodyPrepend: ln => serverInjector.callInjectors({ ln, pbody: true }),
bodyAppend: ln => serverInjector.callInjectors({ ln, body: true })
head: ln => serverInjector.callInjectors({ ...globalInjectOptions, ln }),
bodyPrepend: ln => serverInjector.callInjectors({ ...globalInjectOptions, ln, pbody: true }),
bodyAppend: ln => serverInjector.callInjectors({ ...globalInjectOptions, ln, body: true })
}
}

Expand All @@ -41,19 +42,28 @@ export default function generateServerInjector (options, metaInfo) {
}

serverInjector.injectors[type] = {
text (arg) {
text (injectOptions) {
const addSsrAttribute = injectOptions === true

injectOptions = {
addSsrAttribute,
...globalInjectOptions,
...injectOptions
}

if (type === 'title') {
return titleGenerator(options, type, serverInjector.data[type], arg)
return titleGenerator(options, type, serverInjector.data[type], injectOptions)
}

if (metaInfoAttributeKeys.includes(type)) {
const attributeData = {}

const data = serverInjector.data[type]
if (data) {
const appId = injectOptions.isSSR === false ? '1' : options.ssrAppId
for (const attr in data) {
attributeData[attr] = {
[options.ssrAppId]: data[attr]
[appId]: data[attr]
}
}
}
Expand All @@ -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) {
for (const appId in serverInjector.extraData) {
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}`
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/generators/attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { booleanHtmlAttributes } from '../../shared/constants'
* @param {Object} data - the attributes to generate
* @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 || {}
let attributeStr = ''

Expand All @@ -32,7 +32,7 @@ export default function attributeGenerator (options, type, data, addSrrAttribute
attributeStr += `${attribute}="${encodeURI(JSON.stringify(data))}"`
}

if (type === 'htmlAttrs' && addSrrAttribute) {
if (type === 'htmlAttrs' && addSsrAttribute) {
return `${ssrAttribute}${attributeStr ? ' ' : ''}${attributeStr}`
}

Expand Down
4 changes: 2 additions & 2 deletions src/server/generators/tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
*/
export default function tagGenerator (options, type, tags, generatorOptions) {
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]

Expand All @@ -40,7 +40,7 @@ export default function tagGenerator (options, type, tags, generatorOptions) {
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
for (const attr in tag) {
Expand Down
4 changes: 2 additions & 2 deletions src/server/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import generateServerInjector from './generateServerInjector'
* @vm {Object} - Vue instance - ideally the root component
* @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
if (!rootVm[rootConfigKey]) {
showWarningNotSupported()
Expand All @@ -26,7 +26,7 @@ export default function inject (rootVm, options) {
const metaInfo = getMetaInfo(options, rawInfo, serverSequences, rootVm)

// generate server injector
const serverInjector = generateServerInjector(options, metaInfo)
const serverInjector = generateServerInjector(options, metaInfo, injectOptions)

// add meta info from additional apps
const appsMetaInfo = getAppsMetaInfo()
Expand Down
2 changes: 1 addition & 1 deletion src/shared/$meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function $meta (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),
resume: () => resume($root),
addApp: appId => addApp($root, appId, options)
Expand Down
11 changes: 10 additions & 1 deletion test/unit/components.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,20 @@ describe('components', () => {
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 metaInfo = wrapper.vm.$meta().inject()
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', () => {
Expand Down
2 changes: 1 addition & 1 deletion test/unit/generators.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.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"')
})
})