Skip to content

Commit

Permalink
feat: add es build
Browse files Browse the repository at this point in the history
fix: add global window detection

chore: update deps
  • Loading branch information
pimlie committed Feb 20, 2019
1 parent 1e47a37 commit 56f0b61
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 91 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ package-lock.json

# built code
lib
es

# examples yarn lock
examples/yarn.lock
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"author": "Declan de Wet <declandewet@me.com>",
"bugs": "https://github.com/nuxt/vue-meta/issues",
"scripts": {
"build": "rimraf lib && rollup -c scripts/rollup.config.js",
"build": "scripts/build.sh",
"codecov": "codecov",
"deploy": "npm version",
"dev": "cd examples && npm run dev && cd ..",
Expand All @@ -28,6 +28,7 @@
"vue-hooks": "^0.3.2"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.3.3",
"@babel/node": "^7.2.2",
"@babel/preset-env": "^7.3.1",
Expand Down Expand Up @@ -67,6 +68,7 @@
},
"files": [
"lib",
"es",
"types/index.d.ts",
"types/vue.d.ts"
],
Expand All @@ -88,7 +90,7 @@
"license": "MIT",
"main": "lib/vue-meta.common.js",
"web": "lib/vue-meta.js",
"module": "src/index.js",
"module": "es/index.js",
"typings": "types/index.d.ts",
"repository": {
"url": "git@github.com/nuxt/vue-meta.git",
Expand Down
3 changes: 1 addition & 2 deletions scripts/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ export default [{
output: {
...baseConfig.output,
file: pkg.main,
format: 'cjs',
intro: 'var window'
format: 'cjs'
},
external: Object.keys(pkg.dependencies)
}]
6 changes: 3 additions & 3 deletions src/client/batchUpdate.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { isUndefined } from '../shared/typeof'
import { hasGlobalWindow } from '../shared/window'

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

/**
* Performs a batched update. Uses requestAnimationFrame to prevent
Expand Down
10 changes: 9 additions & 1 deletion src/client/refresh.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ import { isFunction } from '../shared/typeof'
import updateClientMetaInfo from './updateClientMetaInfo'

export default function _refresh(options = {}) {
const escapeSequences = [
[/&/g, '\u0026'],
[/</g, '\u003c'],
[/>/g, '\u003e'],
[/"/g, '\u0022'],
[/'/g, '\u0027']
]

/**
* When called, will update the current meta info with new meta info.
* Useful when updating meta info as the result of an asynchronous
Expand All @@ -14,7 +22,7 @@ export default function _refresh(options = {}) {
* @return {Object} - new meta info
*/
return function refresh() {
const metaInfo = getMetaInfo(options, this.$root)
const metaInfo = getMetaInfo(options, this.$root, escapeSequences)

const tags = updateClientMetaInfo(options, metaInfo)
// emit "event" with new info
Expand Down
11 changes: 9 additions & 2 deletions src/server/inject.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@ import { metaInfoOptionKeys } from '../shared/constants'
import generateServerInjector from './generateServerInjector'

export default function _inject(options = {}) {
const escapeSequences = [
[/&/g, '&amp;'],
[/</g, '&lt;'],
[/>/g, '&gt;'],
[/"/g, '&quot;'],
[/'/g, '&#x27;']
]

/**
* Converts the state of the meta info object such that each item
* can be compiled to a tag string on the server
*
* @this {Object} - Vue instance - ideally the root component
* @return {Object} - server meta info with `toString` methods
*/

return function inject() {
// get meta info with sensible defaults
const metaInfo = getMetaInfo(options, this.$root)
const metaInfo = getMetaInfo(options, this.$root, escapeSequences)

// generate server injectors
for (const key in metaInfo) {
Expand Down
22 changes: 3 additions & 19 deletions src/shared/getMetaInfo.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,9 @@
import deepmerge from 'deepmerge'
import isPlainObject from 'lodash.isplainobject'
import { isUndefined, isFunction, isString } from '../shared/typeof'
import { isFunction, isString } from './typeof'
import isArray from './isArray'
import getComponentOption from './getComponentOption'

const escapeHTML = str => isUndefined(window)
// server-side escape sequence
? String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#x27;')
// client-side escape sequence
: String(str)
.replace(/&/g, '\u0026')
.replace(/</g, '\u003c')
.replace(/>/g, '\u003e')
.replace(/"/g, '\u0022')
.replace(/'/g, '\u0027')

const applyTemplate = (component, template, chunk) =>
isFunction(template) ? template.call(component, chunk) : template.replace(/%s/g, chunk)

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

if (!isDisabled) {
if (isString(val)) {
escaped[key] = escapeHTML(val)
escaped[key] = escapeSequences.reduce((val, [v, r]) => val.replace(v, r), val)
} else if (isPlainObject(val)) {
escaped[key] = escape(val)
} else if (isArray(val)) {
Expand Down
63 changes: 8 additions & 55 deletions src/shared/mixin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import triggerUpdate from '../client/triggerUpdate'
import { isUndefined, isFunction } from '../shared/typeof'
import { ensuredPush } from '../shared/ensure'
import { isUndefined, isFunction } from './typeof'
import { ensuredPush } from './ensure'

export default function createMixin(options) {
// for which Vue lifecycle hooks should the metaInfo be refreshed
Expand Down Expand Up @@ -35,10 +35,6 @@ export default function createMixin(options) {
}
}

updateOnLifecycleHook.forEach((lifecycleHook) => {
ensuredPush(this.$options, lifecycleHook, () => triggerUpdate(this, lifecycleHook))
})

// force an initial refresh on page load and prevent other lifecycleHooks
// to triggerUpdate until this initial refresh is finished
// this is to make sure that when a page is opened in an inactive tab which
Expand All @@ -49,6 +45,7 @@ export default function createMixin(options) {
if (!this.$root._vueMetaInitialized) {
ensuredPush(this.$options, 'mounted', () => {
if (!this.$root._vueMetaInitialized) {
// refresh meta in nextTick so all child components have loaded
this.$nextTick(function () {
this.$root.$meta().refresh()
this.$root._vueMetaInitialized = true
Expand All @@ -60,6 +57,11 @@ export default function createMixin(options) {

// do not trigger refresh on the server side
if (!this.$isServer) {
// no need to add this hooks on server side, there we only need the mounted hook above
updateOnLifecycleHook.forEach((lifecycleHook) => {
ensuredPush(this.$options, lifecycleHook, () => triggerUpdate(this, lifecycleHook))
})

// re-render meta data when returning from a child component to parent
ensuredPush(this.$options, 'destroyed', () => {
// Wait that element is hidden before refreshing meta tags (to support animations)
Expand All @@ -80,54 +82,5 @@ export default function createMixin(options) {
}
}
}
/* Not yet removed
created() {
// if computed $metaInfo exists, watch it for updates & trigger a refresh
// when it changes (i.e. automatically handle async actions that affect metaInfo)
// credit for this suggestion goes to [Sébastien Chopin](https://github.com/Atinux)
if (!this.$isServer && this.$metaInfo) {
this.$watch('$metaInfo', () => triggerUpdate(this))
}
},
activated() {
if (this._hasMetaInfo) {
triggerUpdate(this)
}
},
deactivated() {
if (this._hasMetaInfo) {
triggerUpdate(this)
}
},
beforeMount() {
if (this._hasMetaInfo) {
triggerUpdate(this)
}
},
destroyed() {
// do not trigger refresh on the server side
if (this.$isServer) {
return
}
// re-render meta data when returning from a child component to parent
if (this._hasMetaInfo) {
// Wait that element is hidden before refreshing meta tags (to support animations)
const interval = setInterval(() => {
if (this.$el && this.$el.offsetParent !== null) {
return
}
clearInterval(interval)
if (!this.$parent) {
return
}
triggerUpdate(this)
}, 50)
}
}/**/
}
}
1 change: 0 additions & 1 deletion src/shared/typeof.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

export function isUndefined(arg) {
return typeof arg === 'undefined'
}
Expand Down
9 changes: 6 additions & 3 deletions test/plugin-browser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ describe('plugin', () => {

test('updates can be paused and resumed', async () => {
const _triggerUpdate = jest.requireActual('../src/client/triggerUpdate').default
const _batchUpdate = jest.requireActual('../src/client/batchUpdate').default

const triggerUpdateSpy = triggerUpdate.mockImplementation(_triggerUpdate)
const batchUpdateSpy = batchUpdate.mockImplementation(_batchUpdate)

const Component = Vue.component('test-component', {
metaInfo() {
Expand Down Expand Up @@ -72,7 +75,7 @@ describe('plugin', () => {
expect(wrapper.vm.$root._vueMetaInitialized).toBe(false)
expect(wrapper.vm.$root._vueMetaPaused).toBeFalsy()
expect(triggerUpdateSpy).toHaveBeenCalledTimes(1)
expect(batchUpdate).not.toHaveBeenCalled()
expect(batchUpdateSpy).not.toHaveBeenCalled()
jest.clearAllMocks()
await vmTick(wrapper.vm)

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

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

const metaInfo = wrapper.vm.$meta().resume()
Expand Down
Loading

0 comments on commit 56f0b61

Please sign in to comment.