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

Added PerformanceObserver #1293

Merged
merged 4 commits into from
Jul 16, 2024
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
145 changes: 26 additions & 119 deletions packages/child/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import {
BASE,
HEIGHT_EDGE,
SINGLE,
SIZE_ATTR,
VERSION,
WIDTH_EDGE,
} from '../common/consts'
import formatAdvise from '../common/format-advise'
import { addEventListener, removeEventListener } from '../common/listeners'
import { getModeData } from '../common/mode'
import { id, once } from '../common/utils'
import {
advise,
adviser,
capitalizeFirstLetter,
getElementName,
// eslint-disable-next-line no-unused-vars
info,
Dismissed Show dismissed Hide dismissed
log,
setLogOptions,
warn,
} from './log'
import {
getOverflowedElements,
isOverflowed,
overflowObserver,
} from './overflow'
import { PREF_END, PREF_START, setPerfEl } from './perf'

function iframeResizerChild() {
const PERF_TIME_LIMIT = 4
const PERF_MIN_ELEMENTS = 99

const checkVisibilityOptions = {
contentVisibilityAuto: true,
opacityProperty: true,
Expand Down Expand Up @@ -80,7 +87,6 @@ function iframeResizerChild() {
let initLock = true
let initMsg = ''
let inPageLinks = {}
let isInit = true
let logging = false
let licenseKey = '' // eslint-disable-line no-unused-vars
let mode = 0
Expand Down Expand Up @@ -109,71 +115,14 @@ function iframeResizerChild() {
let onPageInfo = null
let onParentInfo = null

const capitalizeFirstLetter = (string) =>
string.charAt(0).toUpperCase() + string.slice(1)

const isDef = (value) => `${value}` !== '' && value !== undefined

const usedTags = new WeakSet()
const addUsedTag = (el) => typeof el === 'object' && usedTags.add(el)

function getElementName(el) {
switch (true) {
case !isDef(el):
return ''

case isDef(el.id):
return `${el.nodeName.toUpperCase()}#${el.id}`

case isDef(el.name):
return `${el.nodeName.toUpperCase()} (${el.name})`

default:
return (
el.nodeName.toUpperCase() +
(isDef(el.className) ? `.${el.className}` : '')
)
}
}

function elementSnippet(el, maxChars = 30) {
const outer = el?.outerHTML?.toString()

if (!outer) return el

return outer.length < maxChars
? outer
: `${outer.slice(0, maxChars).replaceAll('\n', ' ')}...`
}

// TODO: remove .join(' '), requires major test updates
const formatLogMsg = (...msg) =>
[`[iframe-resizer][${myID}]`, ...msg].join(' ')

const log = (...msg) =>
// eslint-disable-next-line no-console
logging && console?.log(formatLogMsg(...msg))

const info = (...msg) =>
// eslint-disable-next-line no-console
console?.info(`[iframe-resizer][${myID}]`, ...msg)

const warn = (...msg) =>
// eslint-disable-next-line no-console
console?.warn(formatLogMsg(...msg))

const advise = (...msg) =>
// eslint-disable-next-line no-console
console?.warn(formatAdvise(formatLogMsg)(...msg))

const adviser = (msg) => advise(msg)

function init() {
readDataFromParent()
readDataFromPage()

log(`Initialising iFrame v${VERSION} (${window.location.href})`)

setLogOptions({ id: myID, logging })

checkCrossDomain()
checkMode()
checkVersion()
Expand All @@ -187,9 +136,6 @@ function iframeResizerChild() {
setupMouseEvents()
inPageLinks = setupInPageLinks()

addUsedTag(document.documentElement)
addUsedTag(document.body)

setMargin()
setBodyStyle('background', bodyBackground)
setBodyStyle('padding', bodyPadding)
Expand All @@ -211,7 +157,7 @@ function iframeResizerChild() {
sendTitle()
initEventListeners()
onReady()
isInit = false

log('Initialization complete')
log('---')
}
Expand Down Expand Up @@ -450,12 +396,6 @@ Parent page: ${version} - Child page: ${VERSION}.
eventType: 'Ready State Change',
eventName: 'readystatechange',
})

// manageTriggerEvent({
// method: method,
// eventType: 'Orientation Change',
// eventName: 'orientationchange'
// })
}

function checkDeprecatedAttrs() {
Expand Down Expand Up @@ -896,23 +836,6 @@ The <b>size()</> method has been deprecated and replaced with <b>resize()</>. U
bodyObserver = setupBodyMutationObserver()
}

let lastEl = null

function usedEl(el, Side, time, len) {
if (usedTags.has(el) || lastEl === el || (hasTags && len <= 1)) return
// addUsedTag(el)
lastEl = el

info(
`\n${Side} position calculated from:\n`,
el,
`\nParsed ${len} ${hasTags ? 'tagged' : 'potentially overflowing'} elements in ${time}ms`, // ${getElementName(el)} (${elementSnippet(el)})
)
}

let perfWarned = PERF_TIME_LIMIT
let lastTimer = PERF_TIME_LIMIT

function getMaxElement(side) {
const Side = capitalizeFirstLetter(side)

Expand All @@ -921,7 +844,8 @@ The <b>size()</> method has been deprecated and replaced with <b>resize()</>. U
let maxVal = hasTags
? 0
: document.documentElement.getBoundingClientRect().bottom
let timer = performance.now()

performance.mark(PREF_START)

const targetElements =
!hasTags && isOverflowed() ? getOverflowedElements() : calcElements
Expand All @@ -948,33 +872,16 @@ The <b>size()</> method has been deprecated and replaced with <b>resize()</>. U
}
})

timer = (performance.now() - timer).toPrecision(1)

usedEl(maxEl, Side, timer, len)

const logMsg = `
Parsed ${len} element${len === SINGLE ? '' : 's'} in ${timer}ms
${Side} ${hasTags ? 'tagged ' : ''}element found at: ${maxVal}px
Position calculated from HTML element: ${getElementName(maxEl)} (${elementSnippet(maxEl, 100)})`

if (
timer < PERF_TIME_LIMIT ||
len < PERF_MIN_ELEMENTS ||
hasTags ||
isInit
) {
log(logMsg)
} else if (perfWarned < timer && perfWarned < lastTimer) {
perfWarned = timer * 1.2
advise(
`<rb>Performance Warning</>

Calculating the page size took an excessive amount of time. To improve performance add the <b>data-iframe-size</> attribute to the ${side} most element on the page.
${logMsg}`,
)
}
setPerfEl(maxEl)
performance.mark(PREF_END, {
detail: {
Side,
len,
hasTags,
logging,
},
})

lastTimer = timer
return maxVal
}

Expand Down
65 changes: 65 additions & 0 deletions packages/child/log.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import formatAdvise from '../common/format-advise'

let id = ''
let logging = false

export const setLogOptions = (options) => {
id = options.id
logging = options.logging
}

export const capitalizeFirstLetter = (string) =>
string.charAt(0).toUpperCase() + string.slice(1)

const isDef = (value) => `${value}` !== '' && value !== undefined

export function getElementName(el) {
switch (true) {
case !isDef(el):
return ''

case isDef(el.id):
return `${el.nodeName.toUpperCase()}#${el.id}`

case isDef(el.name):
return `${el.nodeName.toUpperCase()} (${el.name})`

default:
return (
el.nodeName.toUpperCase() +
(isDef(el.className) ? `.${el.className}` : '')
)
}
}

// function elementSnippet(el, maxChars = 30) {
// const outer = el?.outerHTML?.toString()

// if (!outer) return el

// return outer.length < maxChars
// ? outer
// : `${outer.slice(0, maxChars).replaceAll('\n', ' ')}...`
// }

// TODO: remove .join(' '), requires major test updates
const formatLogMsg = (...msg) => [`[iframe-resizer][${id}]`, ...msg].join(' ')

export const log = (...msg) =>
// eslint-disable-next-line no-console
logging && console?.log(formatLogMsg(...msg))
Dismissed Show dismissed Hide dismissed

// eslint-disable-next-line no-unused-vars
export const info = (...msg) =>
// eslint-disable-next-line no-console
console?.info(`[iframe-resizer][${id}]`, ...msg)
Dismissed Show dismissed Hide dismissed

export const warn = (...msg) =>
// eslint-disable-next-line no-console
console?.warn(formatLogMsg(...msg))
Dismissed Show dismissed Hide dismissed

export const advise = (...msg) =>
// eslint-disable-next-line no-console
console?.warn(formatAdvise(formatLogMsg)(...msg))
Dismissed Show dismissed Hide dismissed

export const adviser = (msg) => advise(msg)
Loading
Loading