From cab18cad37168932b3674017577d2b33aa7bfaee Mon Sep 17 00:00:00 2001 From: pimlie Date: Sat, 27 Jul 2019 12:33:40 +0200 Subject: [PATCH 1/5] test: use build/dist for e2e testing to prevent errors due to wrong build configs --- .circleci/config.yml | 2 +- test/fixtures/basic/client.js | 2 +- test/fixtures/basic/server.js | 12 ++++++++---- test/utils/build.js | 23 ++++++++++++++++++++--- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 433275c3..cff98bd3 100755 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -76,7 +76,7 @@ jobs: - attach-project - run: name: E2E SSR Tests - command: yarn test:e2e-ssr + command: yarn build && yarn test:e2e-ssr - persist_to_workspace: root: ~/project paths: diff --git a/test/fixtures/basic/client.js b/test/fixtures/basic/client.js index 96a4f08c..81c88297 100644 --- a/test/fixtures/basic/client.js +++ b/test/fixtures/basic/client.js @@ -1,5 +1,5 @@ import Vue from 'vue' -import VueMeta from '../../../src/browser' +import VueMeta from 'vue-meta' import App from './App.vue' import createRouter from './router' diff --git a/test/fixtures/basic/server.js b/test/fixtures/basic/server.js index 4ddc030c..fe897ffe 100644 --- a/test/fixtures/basic/server.js +++ b/test/fixtures/basic/server.js @@ -1,10 +1,14 @@ import Vue from 'vue' -import VueMeta from '../../../src' +import { _import, getVueMetaPath } from '../../utils/build' import App from './App.vue' import createRouter from './router' -Vue.use(VueMeta) +export default async function createServerApp () { + const VueMeta = await _import(getVueMetaPath()) -App.router = createRouter() + Vue.use(VueMeta) -export default new Vue(App) + App.router = createRouter() + + return new Vue(App) +} diff --git a/test/utils/build.js b/test/utils/build.js index 6da79983..23e62df1 100644 --- a/test/utils/build.js +++ b/test/utils/build.js @@ -5,11 +5,26 @@ import webpack from 'webpack' import CopyWebpackPlugin from 'copy-webpack-plugin' import VueLoaderPlugin from 'vue-loader/lib/plugin' import { createRenderer } from 'vue-server-renderer' +import stdEnv from 'std-env' const renderer = createRenderer() export { default as getPort } from 'get-port' +export function _import (moduleName) { + return import(moduleName).then(m => m.default || m) +} + +export const useDist = stdEnv.test && stdEnv.ci + +export function getVueMetaPath (browser) { + if (useDist) { + return path.resolve(__dirname, `../..`) + } + + return path.resolve(__dirname, `../../src${browser ? '/browser' : ''}`) +} + export function webpackRun (config) { const compiler = webpack(config) @@ -48,7 +63,8 @@ export async function buildFixture (fixture, config = {}) { webpackStats.errors.forEach(e => console.error(e)) // eslint-disable-line no-console webpackStats.warnings.forEach(e => console.warn(e)) // eslint-disable-line no-console - const vueApp = await import(path.resolve(fixturePath, 'server')).then(m => m.default || m) + const createApp = await _import(path.resolve(fixturePath, 'server')) + const vueApp = await createApp() const templateFile = await fs.readFile(path.resolve(fixturePath, '..', 'app.template.html'), { encoding: 'utf8' }) const compiled = template(templateFile, { interpolate: /{{([\s\S]+?)}}/g }) @@ -64,7 +80,7 @@ export async function buildFixture (fixture, config = {}) { .reduce((s, asset) => `${s}\n`, '') const app = await renderer.renderToString(vueApp) - // !!! run inject after renderToString !!! + const metaInfo = vueApp.$meta().inject() const appFile = path.resolve(webpackStats.outputPath, 'index.html') @@ -144,7 +160,8 @@ export function createWebpackConfig (config = {}) { ], resolve: { alias: { - 'vue': 'vue/dist/vue.esm.js' + 'vue': 'vue/dist/vue.esm.js', + 'vue-meta': getVueMetaPath(true) } }, ...config From 7204158089efc6e1c6411dc4208b06d692bc63c4 Mon Sep 17 00:00:00 2001 From: pimlie Date: Sat, 27 Jul 2019 12:40:46 +0200 Subject: [PATCH 2/5] test: use wrong build conf to test the test --- scripts/rollup.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/rollup.config.js b/scripts/rollup.config.js index bb4645a6..b2bebf9b 100644 --- a/scripts/rollup.config.js +++ b/scripts/rollup.config.js @@ -23,8 +23,8 @@ const babelConfig = () => ({ ['@babel/preset-env', { targets: { node: 8, - ie: 9, - safari: '5.1' + /*ie: 9, + safari: '5.1'*/ } }] ] From 3cb2a3c24d2cf1f554b8f5099b3c48fcd3e07ad6 Mon Sep 17 00:00:00 2001 From: pimlie Date: Sat, 27 Jul 2019 12:50:29 +0200 Subject: [PATCH 3/5] test: exclude dist for babel-loader in test build --- test/utils/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/build.js b/test/utils/build.js index 23e62df1..4b3fd7e7 100644 --- a/test/utils/build.js +++ b/test/utils/build.js @@ -113,7 +113,7 @@ export function createWebpackConfig (config = {}) { rules: [ { test: /\.js$/, - exclude: /node_modules/, + exclude: /(node_modules|dist)/, use: { loader: 'babel-loader', options: { From 36d080c70e7ac33464c4b3a628dc68db758eb301 Mon Sep 17 00:00:00 2001 From: pimlie Date: Sat, 27 Jul 2019 16:00:06 +0200 Subject: [PATCH 4/5] chore: optimize more for ie9 prefer not to use language features which needs to be transpiled for ie9. Eg for..of to forEach and no spreads --- scripts/rollup.config.js | 6 ++--- src/client/load.js | 18 ++++++------- src/client/updateClientMetaInfo.js | 4 +-- src/client/updaters/tag.js | 41 ++++++++++++++---------------- src/shared/escaping.js | 8 +++--- src/shared/log.js | 4 +-- test/utils/build.js | 2 +- 7 files changed, 40 insertions(+), 43 deletions(-) diff --git a/scripts/rollup.config.js b/scripts/rollup.config.js index b2bebf9b..69f74638 100644 --- a/scripts/rollup.config.js +++ b/scripts/rollup.config.js @@ -23,8 +23,8 @@ const babelConfig = () => ({ ['@babel/preset-env', { targets: { node: 8, - /*ie: 9, - safari: '5.1'*/ + ie: 9, + safari: '5.1' } }] ] @@ -40,7 +40,7 @@ function rollupConfig({ delimiters: ['', ''], values: { // replaceConfig needs to have some values - 'const polyfill = process.env.NODE_ENV === \'test\'': 'const polyfill = false', + 'const polyfill = process.env.NODE_ENV === \'test\'': 'const polyfill = true', } } diff --git a/src/client/load.js b/src/client/load.js index d24c202d..5f3fa457 100644 --- a/src/client/load.js +++ b/src/client/load.js @@ -30,14 +30,14 @@ export function addCallback (query, callback) { export function addCallbacks ({ tagIDKeyName }, type, tags, autoAddListeners) { let hasAsyncCallback = false - for (const tag of tags) { + tags.forEach((tag) => { if (!tag[tagIDKeyName] || !tag.callback) { - continue + return } hasAsyncCallback = true addCallback(`${type}[data-${tagIDKeyName}="${tag[tagIDKeyName]}"]`, tag.callback) - } + }) if (!autoAddListeners || !hasAsyncCallback) { return hasAsyncCallback @@ -60,7 +60,7 @@ export function addListeners () { } export function applyCallbacks (matchElement) { - for (const [query, callback] of callbacks) { + callbacks.forEach(([query, callback]) => { const selector = `${query}[onload="this.__vm_l=1"]` let elements = [] @@ -72,13 +72,13 @@ export function applyCallbacks (matchElement) { elements = [matchElement] } - for (const element of elements) { + elements.forEach((element) => { /* __vm_cb: whether the load callback has been called * __vm_l: set by onload attribute, whether the element was loaded * __vm_ev: whether the event listener was added or not */ if (element.__vm_cb) { - continue + return } const onload = () => { @@ -105,7 +105,7 @@ export function applyCallbacks (matchElement) { */ if (element.__vm_l) { onload() - continue + return } if (!element.__vm_ev) { @@ -113,6 +113,6 @@ export function applyCallbacks (matchElement) { element.addEventListener('load', onload) } - } - } + }) + }) } diff --git a/src/client/updateClientMetaInfo.js b/src/client/updateClientMetaInfo.js index 330b1525..6376214f 100644 --- a/src/client/updateClientMetaInfo.js +++ b/src/client/updateClientMetaInfo.js @@ -25,11 +25,11 @@ export default function updateClientMetaInfo (appId, options = {}, newInfo) { // add load callbacks if the let addLoadListeners = false - for (const type of tagsSupportingOnload) { + tagsSupportingOnload.forEach((type) => { if (newInfo[type] && addCallbacks(options, type, newInfo[type])) { addLoadListeners = true } - } + }) if (addLoadListeners) { addListeners() diff --git a/src/client/updaters/tag.js b/src/client/updaters/tag.js index c4635e26..abe85507 100644 --- a/src/client/updaters/tag.js +++ b/src/client/updaters/tag.js @@ -13,7 +13,7 @@ import { queryElements, getElementsKey } from '../../utils/elements.js' export default function updateTag (appId, options = {}, type, tags, head, body) { const { attribute, tagIDKeyName } = options - const dataAttributes = [tagIDKeyName, ...commonDataAttributes] + const dataAttributes = commonDataAttributes.slice().push(tagIDKeyName) const newElements = [] const queryOptions = { appId, attribute, type, tagIDKeyName } @@ -37,9 +37,9 @@ export default function updateTag (appId, options = {}, type, tags, head, body) } if (tags.length) { - for (const tag of tags) { + tags.forEach((tag) => { if (tag.skip) { - continue + return } const newElement = document.createElement(type) @@ -48,17 +48,17 @@ export default function updateTag (appId, options = {}, type, tags, head, body) for (const attr in tag) { /* istanbul ignore next */ if (!tag.hasOwnProperty(attr)) { - continue + return } if (attr === 'innerHTML') { newElement.innerHTML = tag.innerHTML - continue + return } if (attr === 'json') { newElement.innerHTML = JSON.stringify(tag.json) - continue + return } if (attr === 'cssText') { @@ -68,12 +68,12 @@ export default function updateTag (appId, options = {}, type, tags, head, body) } else { newElement.appendChild(document.createTextNode(tag.cssText)) } - continue + return } if (attr === 'callback') { newElement.onload = () => tag[attr](newElement) - continue + return } const _attr = includes(dataAttributes, attr) @@ -82,7 +82,7 @@ export default function updateTag (appId, options = {}, type, tags, head, body) const isBooleanAttribute = includes(booleanHtmlAttributes, attr) if (isBooleanAttribute && !tag[attr]) { - continue + return } const value = isBooleanAttribute ? '' : tag[attr] @@ -103,36 +103,33 @@ export default function updateTag (appId, options = {}, type, tags, head, body) } else { newElements.push(newElement) } - } + }) } - let oldElements = [] - for (const current of Object.values(currentElements)) { - oldElements = [ - ...oldElements, - ...current - ] + const oldElements = [] + for (const type in currentElements) { + Array.prototype.push.apply(oldElements, currentElements[type]) } // remove old elements - for (const element of oldElements) { + oldElements.forEach((element) => { element.parentNode.removeChild(element) - } + }) // insert new elements - for (const element of newElements) { + newElements.forEach((element) => { if (element.hasAttribute('data-body')) { body.appendChild(element) - continue + return } if (element.hasAttribute('data-pbody')) { body.insertBefore(element, body.firstChild) - continue + return } head.appendChild(element) - } + }) return { oldTags: oldElements, diff --git a/src/shared/escaping.js b/src/shared/escaping.js index 9afd6770..1c685135 100644 --- a/src/shared/escaping.js +++ b/src/shared/escaping.js @@ -19,9 +19,9 @@ export const clientSequences = [ ] // sanitizes potentially dangerous characters -export function escape (info, options, escapeOptions) { +export function escape (info, options, escapeOptions, escapeKeys) { const { tagIDKeyName } = options - const { doEscape = v => v, escapeKeys } = escapeOptions + const { doEscape = v => v } = escapeOptions const escaped = {} for (const key in info) { @@ -56,13 +56,13 @@ export function escape (info, options, escapeOptions) { } else if (isArray(value)) { escaped[key] = value.map((v) => { if (isPureObject(v)) { - return escape(v, options, { ...escapeOptions, escapeKeys: true }) + return escape(v, options, escapeOptions, true) } return doEscape(v) }) } else if (isPureObject(value)) { - escaped[key] = escape(value, options, { ...escapeOptions, escapeKeys: true }) + escaped[key] = escape(value, options, escapeOptions, true) } else { escaped[key] = value } diff --git a/src/shared/log.js b/src/shared/log.js index 5df54aa2..7bb98244 100644 --- a/src/shared/log.js +++ b/src/shared/log.js @@ -4,13 +4,13 @@ const _global = hasGlobalWindow ? window : global const console = (_global.console = _global.console || {}) -export function warn (...args) { +export function warn (str) { /* istanbul ignore next */ if (!console || !console.warn) { return } - console.warn(...args) + console.warn(str) } export const showWarningNotSupported = () => warn('This vue app/component has no vue-meta configuration') diff --git a/test/utils/build.js b/test/utils/build.js index 4b3fd7e7..532af1ef 100644 --- a/test/utils/build.js +++ b/test/utils/build.js @@ -19,7 +19,7 @@ export const useDist = stdEnv.test && stdEnv.ci export function getVueMetaPath (browser) { if (useDist) { - return path.resolve(__dirname, `../..`) + return path.resolve(__dirname, `../..${browser ? '/dist/vue-meta.js' : ''}`) } return path.resolve(__dirname, `../../src${browser ? '/browser' : ''}`) From 404cacf8ab6729cf40ab32331d41b3ac4e35b36f Mon Sep 17 00:00:00 2001 From: pimlie Date: Sat, 27 Jul 2019 17:11:04 +0200 Subject: [PATCH 5/5] fix: continue --- src/client/updaters/tag.js | 112 ++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/src/client/updaters/tag.js b/src/client/updaters/tag.js index abe85507..341175e4 100644 --- a/src/client/updaters/tag.js +++ b/src/client/updaters/tag.js @@ -13,7 +13,9 @@ import { queryElements, getElementsKey } from '../../utils/elements.js' export default function updateTag (appId, options = {}, type, tags, head, body) { const { attribute, tagIDKeyName } = options - const dataAttributes = commonDataAttributes.slice().push(tagIDKeyName) + const dataAttributes = commonDataAttributes.slice() + dataAttributes.push(tagIDKeyName) + const newElements = [] const queryOptions = { appId, attribute, type, tagIDKeyName } @@ -36,75 +38,73 @@ export default function updateTag (appId, options = {}, type, tags, head, body) }) } - if (tags.length) { - tags.forEach((tag) => { - if (tag.skip) { - return - } - - const newElement = document.createElement(type) - newElement.setAttribute(attribute, appId) + tags.forEach((tag) => { + if (tag.skip) { + return + } - for (const attr in tag) { - /* istanbul ignore next */ - if (!tag.hasOwnProperty(attr)) { - return - } + const newElement = document.createElement(type) + newElement.setAttribute(attribute, appId) - if (attr === 'innerHTML') { - newElement.innerHTML = tag.innerHTML - return - } + for (const attr in tag) { + /* istanbul ignore next */ + if (!tag.hasOwnProperty(attr)) { + continue + } - if (attr === 'json') { - newElement.innerHTML = JSON.stringify(tag.json) - return - } + if (attr === 'innerHTML') { + newElement.innerHTML = tag.innerHTML + continue + } - if (attr === 'cssText') { - if (newElement.styleSheet) { - /* istanbul ignore next */ - newElement.styleSheet.cssText = tag.cssText - } else { - newElement.appendChild(document.createTextNode(tag.cssText)) - } - return - } + if (attr === 'json') { + newElement.innerHTML = JSON.stringify(tag.json) + continue + } - if (attr === 'callback') { - newElement.onload = () => tag[attr](newElement) - return + if (attr === 'cssText') { + if (newElement.styleSheet) { + /* istanbul ignore next */ + newElement.styleSheet.cssText = tag.cssText + } else { + newElement.appendChild(document.createTextNode(tag.cssText)) } + continue + } - const _attr = includes(dataAttributes, attr) - ? `data-${attr}` - : attr + if (attr === 'callback') { + newElement.onload = () => tag[attr](newElement) + continue + } - const isBooleanAttribute = includes(booleanHtmlAttributes, attr) - if (isBooleanAttribute && !tag[attr]) { - return - } + const _attr = includes(dataAttributes, attr) + ? `data-${attr}` + : attr - const value = isBooleanAttribute ? '' : tag[attr] - newElement.setAttribute(_attr, value) + const isBooleanAttribute = includes(booleanHtmlAttributes, attr) + if (isBooleanAttribute && !tag[attr]) { + continue } - const oldElements = currentElements[getElementsKey(tag)] + const value = isBooleanAttribute ? '' : tag[attr] + newElement.setAttribute(_attr, value) + } - // Remove a duplicate tag from domTagstoRemove, so it isn't cleared. - let indexToDelete - const hasEqualElement = oldElements.some((existingTag, index) => { - indexToDelete = index - return newElement.isEqualNode(existingTag) - }) + const oldElements = currentElements[getElementsKey(tag)] - if (hasEqualElement && (indexToDelete || indexToDelete === 0)) { - oldElements.splice(indexToDelete, 1) - } else { - newElements.push(newElement) - } + // Remove a duplicate tag from domTagstoRemove, so it isn't cleared. + let indexToDelete + const hasEqualElement = oldElements.some((existingTag, index) => { + indexToDelete = index + return newElement.isEqualNode(existingTag) }) - } + + if (hasEqualElement && (indexToDelete || indexToDelete === 0)) { + oldElements.splice(indexToDelete, 1) + } else { + newElements.push(newElement) + } + }) const oldElements = [] for (const type in currentElements) {