Skip to content

Commit

Permalink
Log warnings to the console (#84)
Browse files Browse the repository at this point in the history
  • Loading branch information
leonvogt authored Nov 3, 2024
1 parent 04af533 commit dbf610e
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 5 deletions.
14 changes: 11 additions & 3 deletions public/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -154,15 +154,23 @@ <h1 class="title">Hotwire Dev Tools</h1>
<fieldset>
<legend>Console Log</legend>
<form>
<label class="toggle">
<input class="toggle-checkbox" type="checkbox" id="log-warnings" />
<div class="toggle-switch"></div>
<span class="toggle-label">Log Warnings</span>
</label>

<label class="toggle">
<input class="toggle-checkbox" type="checkbox" id="monitor-events" />
<div class="toggle-switch"></div>
<span class="toggle-label">Monitor Events</span>
</label>
<div class="detail-panel-options-control monitor-events-toggle-element">
<button id="monitor-events-select-all">Select all</button>
<div class="monitor-events-collapse">
<div class="detail-panel-options-control monitor-events-toggle-element">
<button id="monitor-events-select-all">Select all</button>
</div>
<div class="detail-panel-options-wrapper monitor-events-toggle-element monitor-events-checkbox-container"></div>
</div>
<div class="detail-panel-options-wrapper monitor-events-toggle-element monitor-events-checkbox-container"></div>
</form>
</fieldset>
</body>
Expand Down
5 changes: 5 additions & 0 deletions public/styles/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ label,
user-select: none;
}

form {
display: flex;
flex-direction: column;
}

fieldset {
margin: 1rem 0;
border: 1px solid #ccc;
Expand Down
14 changes: 12 additions & 2 deletions src/content.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { debounce } from "./utils/utils"
import { turboStreamTargetElements } from "./utils/turbo_utils"
import { addHighlightOverlayToElements, removeHighlightOverlay } from "./utils/highlight"
import { MONITORING_EVENTS } from "./lib/monitoring_events"

import Devtool from "./lib/devtool"
import DetailPanel from "./components/detail_panel"
import DOMScanner from "./utils/dom_scanner"
import DiagnosticsChecker from "./lib/diagnostics_checker"

const LOCATION_ORIGIN = window.location.origin
const devTool = new Devtool(LOCATION_ORIGIN)
const detailPanel = new DetailPanel(devTool)
const diagnosticsChecker = new DiagnosticsChecker(devTool)

const highlightTurboFrames = () => {
const badgeClass = "hotwire-dev-tools-turbo-frame-info-badge"
Expand Down Expand Up @@ -137,7 +140,7 @@ const highlightStimulusControllers = () => {

const injectCustomScript = () => {
const existingScript = document.getElementById("hotwire-dev-tools-inject-script")
if (existingScript || !devTool.shouldRenderDetailPanel()) return
if (existingScript) return

const script = document.createElement("script")
script.src = chrome.runtime.getURL("dist/hotwire_dev_tools_inject_script.js")
Expand Down Expand Up @@ -165,6 +168,12 @@ const consoleLogTurboStream = (event) => {
console.log(message, turboStream)
}

const checkForWarnings = debounce(() => {
if (devTool.options.logWarnings) {
diagnosticsChecker.checkForWarnings()
}
}, 150)

const handleTurboFrameBadgeClick = (event) => {
navigator.clipboard.writeText(event.target.dataset.turboId).then(() => {
event.target.classList.add("copied")
Expand All @@ -189,6 +198,7 @@ const handleWindowMessage = (event) => {
if (event.data.registeredControllers) {
devTool.registeredStimulusControllers = event.data.registeredControllers
renderDetailPanel()
checkForWarnings()
}
break
case "turboDetails":
Expand Down Expand Up @@ -257,7 +267,7 @@ const init = async () => {
highlightTurboFrames()
highlightStimulusControllers()
renderDetailPanel()
console.log(DOMScanner.uniqueStimulusControllerIdentifiers)
checkForWarnings()
}

const events = ["turbolinks:load", "turbo:load", "turbo:frame-load", "hotwire-dev-tools:options-changed"]
Expand Down
1 change: 1 addition & 0 deletions src/lib/devtool.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ export default class Devtool {
monitor: {
events: [],
},
logWarnings: true,
}
}
}
78 changes: 78 additions & 0 deletions src/lib/diagnostics_checker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import DOMScanner from "../utils/dom_scanner"

export default class DiagnosticsChecker {
constructor(devTool) {
this.devTool = devTool
this.printedWarnings = []
this.logger = console
}

printWarning = (message, once = true, ...extraArgs) => {
if (once && this.printedWarnings.includes(message)) return

this.logger.warn(`Hotwire Dev Tools: ${message}`, ...extraArgs)
this.printedWarnings.push(message)
}

checkForWarnings = () => {
this._checkForDuplicatedTurboFrames()
this._checkForNonRegisteredStimulusControllers()
this._checkTurboPermanentElements()
this._checkStimulusTargetsNesting()
}

_checkForDuplicatedTurboFrames = () => {
const turboFramesIds = DOMScanner.turboFrameIds
const duplicatedIds = turboFramesIds.filter((id, index) => turboFramesIds.indexOf(id) !== index)

duplicatedIds.forEach((id) => {
this.printWarning(`Multiple Turbo Frames with the same ID '${id}' detected. This can cause unexpected behavior. Ensure that each Turbo Frame has a unique ID.`)
})
}

_checkForNonRegisteredStimulusControllers = () => {
const registeredStimulusControllers = this.devTool.registeredStimulusControllers
if (registeredStimulusControllers.length === 0) return

DOMScanner.uniqueStimulusControllerIdentifiers.forEach((controllerId) => {
const controllerRegistered = registeredStimulusControllers.includes(controllerId)

if (!controllerRegistered) {
this.printWarning(`The Stimulus controller '${controllerId}' does not appear to be registered. Learn more about registering Stimulus controllers here: https://stimulus.hotwired.dev/handbook/installing.`)
}
})
}

_checkStimulusTargetsNesting = () => {
DOMScanner.uniqueStimulusControllerIdentifiers.forEach((controllerId) => {
const dataSelector = `data-${controllerId}-target`
const targetElements = document.querySelectorAll(`[${dataSelector}`)
targetElements.forEach((element) => {
const parent = element.closest(`[data-controller="${controllerId}"]`)
if (!parent) {
const targetName = element.getAttribute(`${dataSelector}`)
this.printWarning(`The Stimulus target '${targetName}' is not inside the Stimulus controller '${controllerId}'`)
}
})
})
}

_checkTurboPermanentElements = () => {
const turboPermanentElements = DOMScanner.turboPermanentElements
if (turboPermanentElements.length === 0) return

turboPermanentElements.forEach((element) => {
const id = element.id
if (id === "") {
const message = `Hotwire Dev Tools: Turbo Permanent Element detected without an ID. Turbo Permanent Elements must have a unique ID to work correctly.`
this.printWarning(message, true, element)
}

const idIsDuplicated = id && document.querySelectorAll(`#${id}`).length > 1
if (idIsDuplicated) {
const message = `Hotwire Dev Tools: Turbo Permanent Element with ID '${id}' doesn't have a unique ID. Turbo Permanent Elements must have a unique ID to work correctly.`
this.printWarning(message, true, element)
}
})
}
}
9 changes: 9 additions & 0 deletions src/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ const monitorEventsToggles = document.querySelectorAll(".monitor-events-toggle-e
const monitorEventsCheckboxContainer = document.querySelector(".monitor-events-checkbox-container")
const monitorEventsSelectAll = document.getElementById("monitor-events-select-all")

const logWarning = document.getElementById("log-warnings")

const toggleInputs = (toggleElements, show) => {
toggleElements.forEach((element) => {
element.classList.toggle("d-none", !show)
Expand Down Expand Up @@ -81,6 +83,8 @@ const initializeForm = async (options) => {

monitorEvents.checked = options.monitor.events.length > 0

logWarning.checked = options.logWarnings

if (devTool.isFirefox) {
// In Firefox the color picker inside an extension popup doesn't really work (See https://github.com/leonvogt/hotwire-dev-tools/issues/20)
// Workaround: Change the input type to text so the user can input the color manually
Expand Down Expand Up @@ -285,6 +289,11 @@ const setupEventListeners = (options) => {
options.monitor.events = allChecked ? [] : MONITORING_EVENTS
saveOptions(options)
})

logWarning.addEventListener("change", (event) => {
options.logWarnings = event.target.checked
saveOptions(options)
})
}

const getCurrentTabOrigin = async () => {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/dom_scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ export default class DOMScanner {
return document.querySelectorAll("turbo-frame")
}

static get turboFrameIds() {
return Array.from(this.turboFrameElements).map((turboFrame) => turboFrame.id)
}

static get turboPermanentElements() {
return document.querySelectorAll("[data-turbo-permanent]")
}

// Stimulus
static get stimulusControllerElements() {
return document.querySelectorAll("[data-controller]")
Expand Down

0 comments on commit dbf610e

Please sign in to comment.