Last active
July 9, 2018 13:52
-
-
Save jaggli/5b2141c60cef3095a51661bac96de183 to your computer and use it in GitHub Desktop.
Styled Components vs Hotjar (Sent to Hotjar support at 27. March 2018)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
const fixHotjar = () => { | |
// add sync style tag to head | |
const syncStyles = document.createElement('style') | |
syncStyles.type = 'text/css' | |
document.head.insertBefore(syncStyles, document.head.children[0]) | |
// start styles sync | |
let lastStyles | |
const updateStyles = () => { | |
const styleNodes = [].slice.call(document.querySelectorAll('head [data-styled-components]')) | |
if (!styleNodes.length) { return } | |
const styles = styleNodes | |
.map(({ sheet }) => [].slice.call(sheet.cssRules) | |
.map(rule => rule.cssText) | |
.join(' ') | |
) | |
.join(' ') | |
if (styles === lastStyles) { return } | |
syncStyles.textContent = styles | |
lastStyles = styles | |
} | |
// start updating interval | |
const startInterval = window.setInterval(() => { | |
if (!window.hj || !window.hj.behaviorData) { return } | |
window.clearInterval(startInterval) | |
window.setInterval(() => { | |
window.requestAnimationFrame(() => { | |
updateStyles() | |
}) | |
}, 500) | |
}, 50) | |
} | |
const HotjarFix = props => ( | |
<script id='hotjar-fix' dangerouslySetInnerHTML={{ | |
__html: `(${fixHotjar.toString()})()` | |
}} /> | |
) | |
export default HotjarFix |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ---------------------------------------------------------------------------- | |
// This is a failed attempt to send fake mutations to hotjar | |
// For documentation reasons, this stays here | |
// ---------------------------------------------------------------------------- | |
// THIS DOESN'T WORK, DON'T USE THIS IN PRODUCTION!!! | |
import React from 'react' | |
var fixHotjar = () => { | |
// add sync style tag to head | |
const syncStyles = document.createElement('style') | |
syncStyles.type = 'text/css' | |
document.head.insertBefore(syncStyles, document.head.children[0]) | |
// style updates helper | |
let lastStyles = '' | |
const getStyleUpdates = () => { | |
const styleNodes = [].slice.call(document.querySelectorAll('head [data-styled-components]')) | |
if (!styleNodes.length) { return } | |
const styles = styleNodes | |
.map(({ sheet }) => [].slice.call(sheet.cssRules) | |
.map(rule => rule.cssText) | |
.join(' ') | |
) | |
.join(' ') | |
if (styles === lastStyles) { return } | |
const ret = { | |
removed: lastStyles, | |
added: styles | |
} | |
lastStyles = styles | |
return ret | |
} | |
// fake classes | |
const NodeList = function (...args) { return new Array(...args) } | |
const MutationRecord = function ({addedNodes, removedNodes}) { | |
this.addedNodes = addedNodes | |
this.attributeName = null | |
this.attributeNamespace = null | |
this.nextSibling = null | |
this.oldValue = null | |
this.previousSibling = null | |
this.removedNodes = removedNodes | |
this.type = 'childList' | |
this.target = syncStyles | |
} | |
// define PromotableObserver | |
const OriginalObserver = | |
window.MutationObserver || | |
window.WebKitMutationObserver || | |
window.MozMutationObserver | |
const PromotableObserver = function (fn) { | |
const _this = this | |
_this._promotedMutations = { | |
list: [], | |
nodeCache: {} | |
} | |
_this._super = new OriginalObserver((mutations, observer) => { | |
const all = [].concat( | |
mutations, | |
_this.takePromotedRecords() | |
) | |
fn.call(window, all, observer) | |
}) | |
console.log('promotable mutation observer initialized') | |
const startInterval = window.setInterval(() => { | |
if (!window.hj || !window.hj.behaviorData) { return } | |
window.clearInterval(startInterval) | |
window.setInterval(() => { | |
window.requestAnimationFrame(() => { | |
const updates = getStyleUpdates() | |
if (!updates) { return } | |
let addedNode | |
if (updates.added) { | |
addedNode = document.createTextNode(updates.added) | |
_this._promotedMutations.nodeCache[updates.added] = addedNode | |
} | |
let removedNode | |
if (updates.removed) { | |
removedNode = _this._promotedMutations.nodeCache[updates.removed] || | |
document.createTextNode(updates.removed) | |
} | |
const record = new MutationRecord({ | |
addedNodes: new NodeList(addedNode || 0), | |
removedNodes: new NodeList(removedNode || 0) | |
}) | |
_this.promoteRecord(record) | |
}) | |
}, 500) | |
}, 50) | |
_this.promoteRecord = function (record) { | |
console.log('promote', record) | |
_this._promotedMutations.list.push(record) | |
window.setTimeout(() => { | |
console.log(_this._promotedMutations.list.length) | |
const promoted = _this.takePromotedRecords() | |
console.log(promoted) | |
if (promoted.length) { | |
// make sure, mutation handler is called, if not already by other modifications | |
fn.call(window, promoted, _this._super) | |
} | |
}, 50) | |
} | |
_this.takePromotedRecords = function () { | |
return _this._promotedMutations.list.splice(0, _this._promotedMutations.list.length) | |
} | |
_this.takeRecords = function () { | |
const allRecords = [].concat( | |
_this._super.takeRecords(), | |
_this.takePromotedRecords() | |
) | |
console.log('take records', allRecords) | |
return allRecords | |
} | |
_this.observe = function (target, options) { | |
return _this._super.observe(target, options) | |
} | |
_this.disconnect = function (target, options) { | |
return _this._super.disconnect(target, options) | |
} | |
} | |
window.MutationObserver = PromotableObserver | |
window.WebKitMutationObserver = PromotableObserver | |
window.MozMutationObserver = PromotableObserver | |
} | |
const HotjarFix = props => ( | |
<script id='hotjar-fix' dangerouslySetInnerHTML={{ | |
__html: `(${fixHotjar.toString()})()` | |
}} /> | |
) | |
export default HotjarFix |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is this script still necessary and works for the new HotJat script version?