Skip to content

Commit

Permalink
refactor: ♻️ refactor plugin-navigation-breadcrumbs
Browse files Browse the repository at this point in the history
  • Loading branch information
gingerbenw committed Nov 12, 2024
1 parent 7af45db commit edd8ffb
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 19 deletions.
13 changes: 13 additions & 0 deletions packages/plugin-navigation-breadcrumbs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
"name": "@bugsnag/plugin-navigation-breadcrumbs",
"version": "8.1.1",
"main": "navigation-breadcrumbs.js",
"types": "dist/types/navigation-breadcrumbs.d.ts",
"exports": {
".": {
"types": "./dist/types/navigation-breadcrumbs.d.ts",
"default": "./dist/navigation-breadcrumbs.js",
"import": "./dist/navigation-breadcrumbs.mjs"
}
},
"description": "@bugsnag/js plugin to record browser navigation as breadcrumbs",
"homepage": "https://www.bugsnag.com/",
"repository": {
Expand All @@ -14,6 +22,11 @@
"files": [
"*.js"
],
"scripts": {
"build": "npm run build:npm",
"build:npm": "rollup --config rollup.config.npm.mjs",
"clean": "rm -rf dist/*"
},
"author": "Bugsnag",
"license": "MIT",
"devDependencies": {
Expand Down
5 changes: 5 additions & 0 deletions packages/plugin-navigation-breadcrumbs/rollup.config.npm.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import createRollupConfig from '../../.rollup/index.mjs'

export default createRollupConfig({
input: 'src/navigation-breadcrumbs.ts'
})
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import { Client, Plugin } from 'packages/core/types'

interface PluginClient extends Client {
_isBreadcrumbTypeEnabled: (type: string) => boolean
}

type ExtendedHistory = History & {
replaceState: History['replaceState'] & { _restore?: () => void }
pushState: History['pushState'] & { _restore?: () => void }
}

type ExtendedWindow = Window & {
history: ExtendedHistory
}

/*
* Leaves breadcrumbs when navigation methods are called or events are emitted
*/
module.exports = (win = window) => {
const plugin = {
export default (win = window): Plugin => {
const plugin: Plugin = {
load: (client) => {
if (!('addEventListener' in win)) return
if (!client._isBreadcrumbTypeEnabled('navigation')) return
if (!(client as PluginClient)._isBreadcrumbTypeEnabled('navigation')) return

// returns a function that will drop a breadcrumb with a given name
const drop = name => () => client.leaveBreadcrumb(name, {}, 'navigation')
const drop = (name: string) => () => client.leaveBreadcrumb(name, {}, 'navigation')

// simple drops – just names, no meta
win.addEventListener('pagehide', drop('Page hidden'), true)
Expand All @@ -27,57 +42,58 @@ module.exports = (win = window) => {
}, true)

// the only way to know about replaceState/pushState is to wrap them… >_<
if (win.history.pushState) wrapHistoryFn(client, win.history, 'pushState', win, true)
if (win.history.replaceState) wrapHistoryFn(client, win.history, 'replaceState', win)
if (typeof win.history.pushState === 'function') wrapHistoryFn(client, win.history, 'pushState', win, true)
if (typeof win.history.replaceState === 'function') wrapHistoryFn(client, win.history, 'replaceState', win)
}
}

if (process.env.NODE_ENV !== 'production') {
plugin.destroy = (win = window) => {
win.history.replaceState._restore()
win.history.pushState._restore()
plugin.destroy = (win: ExtendedWindow = window) => {
if (win.history.replaceState._restore) win.history.replaceState._restore()
if (win.history.pushState._restore) win.history.pushState._restore()
}
}

return plugin
}

if (process.env.NODE_ENV !== 'production') {
exports.destroy = (win = window) => {
win.history.replaceState._restore()
win.history.pushState._restore()
exports.destroy = (win: ExtendedWindow = window) => {
if (win.history.replaceState._restore) win.history.replaceState._restore()
if (win.history.pushState._restore) win.history.pushState._restore()
}
}

// takes a full url like http://foo.com:1234/pages/01.html?yes=no#section-2 and returns
// just the path and hash parts, e.g. /pages/01.html?yes=no#section-2
const relativeLocation = (url, win) => {
const a = win.document.createElement('A')
const relativeLocation = (url: string, win: Window) => {
const a = win.document.createElement('a')
a.href = url
return `${a.pathname}${a.search}${a.hash}`
}

const stateChangeToMetadata = (win, state, title, url) => {
const stateChangeToMetadata = (win: Window, state: string, title: string, url?: string | URL | null) => {
const currentPath = relativeLocation(win.location.href, win)
return { title, state, prevState: getCurrentState(win), to: url || currentPath, from: currentPath }
}

const wrapHistoryFn = (client, target, fn, win, resetEventCount = false) => {
type HistoryMethods = 'pushState' | 'replaceState'
const wrapHistoryFn = (client: Client, target: ExtendedHistory, fn: HistoryMethods, win: Window, resetEventCount = false) => {
const orig = target[fn]
target[fn] = (state, title, url) => {
client.leaveBreadcrumb(`History ${fn}`, stateChangeToMetadata(win, state, title, url), 'navigation')
// if throttle plugin is in use, reset the event sent count
if (resetEventCount && typeof client.resetEventCount === 'function') client.resetEventCount()
// Internet Explorer will convert `undefined` to a string when passed, causing an unintended redirect
// to '/undefined'. therefore we only pass the url if it's not undefined.
orig.apply(target, [state, title].concat(url !== undefined ? url : []))
orig.apply(target, [state, title].concat(url !== undefined ? url : []) as Parameters<History[HistoryMethods]>)
}
if (process.env.NODE_ENV !== 'production') {
target[fn]._restore = () => { target[fn] = orig }
}
}

const getCurrentState = (win) => {
const getCurrentState = (win: Window) => {
try {
return win.history.state
} catch (e) {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import plugin from '../navigation-breadcrumbs'
import plugin from '../src/navigation-breadcrumbs'

import Client from '@bugsnag/core/client'

Expand Down
8 changes: 8 additions & 0 deletions packages/plugin-navigation-breadcrumbs/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*.ts"],
"compilerOptions": {
"types": ["node"]
}
}

0 comments on commit edd8ffb

Please sign in to comment.