Skip to content

Commit 56f0b61

Browse files
committed
feat: add es build
fix: add global window detection chore: update deps
1 parent 1e47a37 commit 56f0b61

File tree

11 files changed

+165
-91
lines changed

11 files changed

+165
-91
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ package-lock.json
3939

4040
# built code
4141
lib
42+
es
4243

4344
# examples yarn lock
4445
examples/yarn.lock

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"author": "Declan de Wet <[email protected]>",
66
"bugs": "https://github.com/nuxt/vue-meta/issues",
77
"scripts": {
8-
"build": "rimraf lib && rollup -c scripts/rollup.config.js",
8+
"build": "scripts/build.sh",
99
"codecov": "codecov",
1010
"deploy": "npm version",
1111
"dev": "cd examples && npm run dev && cd ..",
@@ -28,6 +28,7 @@
2828
"vue-hooks": "^0.3.2"
2929
},
3030
"devDependencies": {
31+
"@babel/cli": "^7.2.3",
3132
"@babel/core": "^7.3.3",
3233
"@babel/node": "^7.2.2",
3334
"@babel/preset-env": "^7.3.1",
@@ -67,6 +68,7 @@
6768
},
6869
"files": [
6970
"lib",
71+
"es",
7072
"types/index.d.ts",
7173
"types/vue.d.ts"
7274
],
@@ -88,7 +90,7 @@
8890
"license": "MIT",
8991
"main": "lib/vue-meta.common.js",
9092
"web": "lib/vue-meta.js",
91-
"module": "src/index.js",
93+
"module": "es/index.js",
9294
"typings": "types/index.d.ts",
9395
"repository": {
9496
"url": "[email protected]/nuxt/vue-meta.git",

scripts/rollup.config.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ export default [{
4848
output: {
4949
...baseConfig.output,
5050
file: pkg.main,
51-
format: 'cjs',
52-
intro: 'var window'
51+
format: 'cjs'
5352
},
5453
external: Object.keys(pkg.dependencies)
5554
}]

src/client/batchUpdate.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import { isUndefined } from '../shared/typeof'
1+
import { hasGlobalWindow } from '../shared/window'
22

33
// fallback to timers if rAF not present
4-
const stopUpdate = (!isUndefined(window) ? window.cancelAnimationFrame : null) || clearTimeout
5-
const startUpdate = (!isUndefined(window) ? window.requestAnimationFrame : null) || (cb => setTimeout(cb, 0))
4+
const stopUpdate = (hasGlobalWindow ? window.cancelAnimationFrame : null) || clearTimeout
5+
const startUpdate = (hasGlobalWindow ? window.requestAnimationFrame : null) || (cb => setTimeout(cb, 0))
66

77
/**
88
* Performs a batched update. Uses requestAnimationFrame to prevent

src/client/refresh.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import { isFunction } from '../shared/typeof'
33
import updateClientMetaInfo from './updateClientMetaInfo'
44

55
export default function _refresh(options = {}) {
6+
const escapeSequences = [
7+
[/&/g, '\u0026'],
8+
[/</g, '\u003c'],
9+
[/>/g, '\u003e'],
10+
[/"/g, '\u0022'],
11+
[/'/g, '\u0027']
12+
]
13+
614
/**
715
* When called, will update the current meta info with new meta info.
816
* Useful when updating meta info as the result of an asynchronous
@@ -14,7 +22,7 @@ export default function _refresh(options = {}) {
1422
* @return {Object} - new meta info
1523
*/
1624
return function refresh() {
17-
const metaInfo = getMetaInfo(options, this.$root)
25+
const metaInfo = getMetaInfo(options, this.$root, escapeSequences)
1826

1927
const tags = updateClientMetaInfo(options, metaInfo)
2028
// emit "event" with new info

src/server/inject.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,24 @@ import { metaInfoOptionKeys } from '../shared/constants'
33
import generateServerInjector from './generateServerInjector'
44

55
export default function _inject(options = {}) {
6+
const escapeSequences = [
7+
[/&/g, '&amp;'],
8+
[/</g, '&lt;'],
9+
[/>/g, '&gt;'],
10+
[/"/g, '&quot;'],
11+
[/'/g, '&#x27;']
12+
]
13+
614
/**
715
* Converts the state of the meta info object such that each item
816
* can be compiled to a tag string on the server
917
*
1018
* @this {Object} - Vue instance - ideally the root component
1119
* @return {Object} - server meta info with `toString` methods
1220
*/
13-
1421
return function inject() {
1522
// get meta info with sensible defaults
16-
const metaInfo = getMetaInfo(options, this.$root)
23+
const metaInfo = getMetaInfo(options, this.$root, escapeSequences)
1724

1825
// generate server injectors
1926
for (const key in metaInfo) {

src/shared/getMetaInfo.js

+3-19
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,9 @@
11
import deepmerge from 'deepmerge'
22
import isPlainObject from 'lodash.isplainobject'
3-
import { isUndefined, isFunction, isString } from '../shared/typeof'
3+
import { isFunction, isString } from './typeof'
44
import isArray from './isArray'
55
import getComponentOption from './getComponentOption'
66

7-
const escapeHTML = str => isUndefined(window)
8-
// server-side escape sequence
9-
? String(str)
10-
.replace(/&/g, '&amp;')
11-
.replace(/</g, '&lt;')
12-
.replace(/>/g, '&gt;')
13-
.replace(/"/g, '&quot;')
14-
.replace(/'/g, '&#x27;')
15-
// client-side escape sequence
16-
: String(str)
17-
.replace(/&/g, '\u0026')
18-
.replace(/</g, '\u003c')
19-
.replace(/>/g, '\u003e')
20-
.replace(/"/g, '\u0022')
21-
.replace(/'/g, '\u0027')
22-
237
const applyTemplate = (component, template, chunk) =>
248
isFunction(template) ? template.call(component, chunk) : template.replace(/%s/g, chunk)
259

@@ -30,7 +14,7 @@ const applyTemplate = (component, template, chunk) =>
3014
* @param {Object} component - the Vue instance to get meta info from
3115
* @return {Object} - returned meta info
3216
*/
33-
export default function getMetaInfo({ keyName, tagIDKeyName, metaTemplateKeyName, contentKeyName } = {}, component) {
17+
export default function getMetaInfo({ keyName, tagIDKeyName, metaTemplateKeyName, contentKeyName } = {}, component, escapeSequences = []) {
3418
// set some sane defaults
3519
const defaultInfo = {
3620
title: '',
@@ -139,7 +123,7 @@ export default function getMetaInfo({ keyName, tagIDKeyName, metaTemplateKeyName
139123

140124
if (!isDisabled) {
141125
if (isString(val)) {
142-
escaped[key] = escapeHTML(val)
126+
escaped[key] = escapeSequences.reduce((val, [v, r]) => val.replace(v, r), val)
143127
} else if (isPlainObject(val)) {
144128
escaped[key] = escape(val)
145129
} else if (isArray(val)) {

src/shared/mixin.js

+8-55
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import triggerUpdate from '../client/triggerUpdate'
2-
import { isUndefined, isFunction } from '../shared/typeof'
3-
import { ensuredPush } from '../shared/ensure'
2+
import { isUndefined, isFunction } from './typeof'
3+
import { ensuredPush } from './ensure'
44

55
export default function createMixin(options) {
66
// for which Vue lifecycle hooks should the metaInfo be refreshed
@@ -35,10 +35,6 @@ export default function createMixin(options) {
3535
}
3636
}
3737

38-
updateOnLifecycleHook.forEach((lifecycleHook) => {
39-
ensuredPush(this.$options, lifecycleHook, () => triggerUpdate(this, lifecycleHook))
40-
})
41-
4238
// force an initial refresh on page load and prevent other lifecycleHooks
4339
// to triggerUpdate until this initial refresh is finished
4440
// this is to make sure that when a page is opened in an inactive tab which
@@ -49,6 +45,7 @@ export default function createMixin(options) {
4945
if (!this.$root._vueMetaInitialized) {
5046
ensuredPush(this.$options, 'mounted', () => {
5147
if (!this.$root._vueMetaInitialized) {
48+
// refresh meta in nextTick so all child components have loaded
5249
this.$nextTick(function () {
5350
this.$root.$meta().refresh()
5451
this.$root._vueMetaInitialized = true
@@ -60,6 +57,11 @@ export default function createMixin(options) {
6057

6158
// do not trigger refresh on the server side
6259
if (!this.$isServer) {
60+
// no need to add this hooks on server side, there we only need the mounted hook above
61+
updateOnLifecycleHook.forEach((lifecycleHook) => {
62+
ensuredPush(this.$options, lifecycleHook, () => triggerUpdate(this, lifecycleHook))
63+
})
64+
6365
// re-render meta data when returning from a child component to parent
6466
ensuredPush(this.$options, 'destroyed', () => {
6567
// Wait that element is hidden before refreshing meta tags (to support animations)
@@ -80,54 +82,5 @@ export default function createMixin(options) {
8082
}
8183
}
8284
}
83-
/* Not yet removed
84-
created() {
85-
// if computed $metaInfo exists, watch it for updates & trigger a refresh
86-
// when it changes (i.e. automatically handle async actions that affect metaInfo)
87-
// credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
88-
if (!this.$isServer && this.$metaInfo) {
89-
this.$watch('$metaInfo', () => triggerUpdate(this))
90-
}
91-
92-
},
93-
activated() {
94-
if (this._hasMetaInfo) {
95-
triggerUpdate(this)
96-
}
97-
},
98-
deactivated() {
99-
if (this._hasMetaInfo) {
100-
triggerUpdate(this)
101-
}
102-
},
103-
beforeMount() {
104-
if (this._hasMetaInfo) {
105-
triggerUpdate(this)
106-
}
107-
},
108-
destroyed() {
109-
// do not trigger refresh on the server side
110-
if (this.$isServer) {
111-
return
112-
}
113-
114-
// re-render meta data when returning from a child component to parent
115-
if (this._hasMetaInfo) {
116-
// Wait that element is hidden before refreshing meta tags (to support animations)
117-
const interval = setInterval(() => {
118-
if (this.$el && this.$el.offsetParent !== null) {
119-
return
120-
}
121-
122-
clearInterval(interval)
123-
124-
if (!this.$parent) {
125-
return
126-
}
127-
128-
triggerUpdate(this)
129-
}, 50)
130-
}
131-
}/**/
13285
}
13386
}

src/shared/typeof.js

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
export function isUndefined(arg) {
32
return typeof arg === 'undefined'
43
}

test/plugin-browser.test.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ describe('plugin', () => {
4343

4444
test('updates can be paused and resumed', async () => {
4545
const _triggerUpdate = jest.requireActual('../src/client/triggerUpdate').default
46+
const _batchUpdate = jest.requireActual('../src/client/batchUpdate').default
47+
4648
const triggerUpdateSpy = triggerUpdate.mockImplementation(_triggerUpdate)
49+
const batchUpdateSpy = batchUpdate.mockImplementation(_batchUpdate)
4750

4851
const Component = Vue.component('test-component', {
4952
metaInfo() {
@@ -72,7 +75,7 @@ describe('plugin', () => {
7275
expect(wrapper.vm.$root._vueMetaInitialized).toBe(false)
7376
expect(wrapper.vm.$root._vueMetaPaused).toBeFalsy()
7477
expect(triggerUpdateSpy).toHaveBeenCalledTimes(1)
75-
expect(batchUpdate).not.toHaveBeenCalled()
78+
expect(batchUpdateSpy).not.toHaveBeenCalled()
7679
jest.clearAllMocks()
7780
await vmTick(wrapper.vm)
7881

@@ -83,7 +86,7 @@ describe('plugin', () => {
8386
expect(wrapper.vm.$root._vueMetaInitialized).toBe(true)
8487
expect(wrapper.vm.$root._vueMetaPaused).toBeFalsy()
8588
expect(triggerUpdateSpy).toHaveBeenCalledTimes(1)
86-
expect(batchUpdate).toHaveBeenCalledTimes(1)
89+
expect(batchUpdateSpy).toHaveBeenCalledTimes(1)
8790
jest.clearAllMocks()
8891

8992
wrapper.vm.$meta().pause()
@@ -94,7 +97,7 @@ describe('plugin', () => {
9497
expect(wrapper.vm.$root._vueMetaInitialized).toBe(true)
9598
expect(wrapper.vm.$root._vueMetaPaused).toBe(true)
9699
expect(triggerUpdateSpy).toHaveBeenCalledTimes(1)
97-
expect(batchUpdate).not.toHaveBeenCalled()
100+
expect(batchUpdateSpy).not.toHaveBeenCalled()
98101
jest.clearAllMocks()
99102

100103
const metaInfo = wrapper.vm.$meta().resume()

0 commit comments

Comments
 (0)