0
\$\begingroup\$

My team develops an app with an API using the Laravel framework and the front-end is developed with VueJS. Locally vue-cli-service serve (a wrapper around Webpack) is used to serve the front-end code with Hot-Module-Replacement (HMR) and I've attempted periodically to get the laravel-debugbar to appear and finally got it injected after reading many posts online about it, including this comment on a GH issue How to use this with SPA (Single page applications).

I attempted to use Server-Side Rendering to inject the debugbar but was unsuccessful in that attempt.

Based on that comment by FaranAli9 on the GH issue I created this API route:

<?php

namespace App\Http\Controllers;

class FrontendController extends Controller
{
    public function renderDebugBar()
    {
        $renderer = \Debugbar::getJavascriptRenderer();
        $renderer->setOpenHandlerUrl('http://localhost/_debugbar/open');
        return ['toAppend' => $renderer->renderHead() . $renderer->render()];
    }
}

The calls to $renderer->renderHead() . $renderer->render() typically yield six HTML elements:

<link rel='stylesheet' type='text\/css' property='stylesheet' href='\/_debugbar\/assets\/stylesheets?v=1710323434&theme=auto' data-turbolinks-eval='false' data-turbo-eval='false'>
<script src='\/_debugbar\/assets\/javascript?v=1710323434' data-turbolinks-eval='false' data-turbo-eval='false'><\/script>
<script data-turbo-eval='false'>jQuery.noConflict(true);<\/script>\n
<script> Sfdump = window.Sfdump || (function (doc) { doc.documentElement.classList.add('sf-js-enabled'); var rxEsc = \/([.*+?^${}()|\\[\\]\\\/\\\\])\/g, idRx = \/\\bsf-dump-\\d+-ref[012]\\w+\\b\/, keyHint = 0 <= navigator.platform.toUpperCase().indexOf('MAC') ? 'Cmd' : 'Ctrl', addEventListener = function (e, n, cb) { e.addEventListener(n, cb, false); }; if (!doc.addEventListener) { addEventListener = function (element, eventName, callback) { element.attachEvent('on' + eventName, function (e) { e.preventDefault = function () {e.returnValue = false;}; e.target = e.srcElement; callback(e); }); }; } function toggle(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className, arrow, newClass; if (\/\\bsf-dump-compact\\b\/.test(oldClass)) { arrow = '\u25bc'; newClass = 'sf-dump-expanded'; } else if (\/\\bsf-dump-expanded\\b\/.test(oldClass)) { arrow = '\u25b6'; newClass = 'sf-dump-compact'; } else { return false; } if (doc.createEvent && s.dispatchEvent) { var event = doc.createEvent('Event'); event.initEvent('sf-dump-expanded' === newClass ? 'sfbeforedumpexpand' : 'sfbeforedumpcollapse', true, false); s.dispatchEvent(event); } a.lastChild.innerHTML = arrow; s.className = s.className.replace(\/\\bsf-dump-(compact|expanded)\\b\/, newClass); if (recursive) { try { a = s.querySelectorAll('.'+oldClass); for (s = 0; s < a.length; ++s) { if (-1 == a[s].className.indexOf(newClass)) { a[s].className = newClass; a[s].previousSibling.lastChild.innerHTML = arrow; } } } catch (e) { } } return true; }; function collapse(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className; if (\/\\bsf-dump-expanded\\b\/.test(oldClass)) { toggle(a, recursive); return true; } return false; }; function expand(a, recursive) { var s = a.nextSibling || {}, oldClass = s.className; if (\/\\bsf-dump-compact\\b\/.test(oldClass)) { toggle(a, recursive); return true; } return false; }; function collapseAll(root) { var a = root.querySelector('a.sf-dump-toggle'); if (a) { collapse(a, true); expand(a); return true; } return false; } function reveal(node) { var previous, parents = []; while ((node = node.parentNode || {}) && (previous = node.previousSibling) && 'A' === previous.tagName) { parents.push(previous); } if (0 !== parents.length) { parents.forEach(function (parent) { expand(parent); }); return true; } return false; } function highlight(root, activeNode, nodes) { resetHighlightedNodes(root); Array.from(nodes||[]).forEach(function (node) { if (!\/\\bsf-dump-highlight\\b\/.test(node.className)) { node.className = node.className + ' sf-dump-highlight'; } }); if (!\/\\bsf-dump-highlight-active\\b\/.test(activeNode.className)) { activeNode.className = activeNode.className + ' sf-dump-highlight-active'; } } function resetHighlightedNodes(root) { Array.from(root.querySelectorAll('.sf-dump-str, .sf-dump-key, .sf-dump-public, .sf-dump-protected, .sf-dump-private')).forEach(function (strNode) { strNode.className = strNode.className.replace(\/\\bsf-dump-highlight\\b\/, ''); strNode.className = strNode.className.replace(\/\\bsf-dump-highlight-active\\b\/, ''); }); } return function (root, x) { root = doc.getElementById(root); var indentRx = new RegExp('^('+(root.getAttribute('data-indent-pad') || ' ').replace(rxEsc, '\\\\$1')+')+', 'm'), options = {\"maxDepth\":1,\"maxStringLength\":160,\"fileLinkFormat\":false}, elt = root.getElementsByTagName('A'), len = elt.length, i = 0, s, h, t = []; while (i < len) t.push(elt[i++]); for (i in x) { options[i] = x[i]; } function a(e, f) { addEventListener(root, e, function (e, n) { if ('A' == e.target.tagName) { f(e.target, e); } else if ('A' == e.target.parentNode.tagName) { f(e.target.parentNode, e); } else { n = \/\\bsf-dump-ellipsis\\b\/.test(e.target.className) ? e.target.parentNode : e.target; if ((n = n.nextElementSibling) && 'A' == n.tagName) { if (!\/\\bsf-dump-toggle\\b\/.test(n.className)) { n = n.nextElementSibling || n; } f(n, e, true); } } }); }; function isCtrlKey(e) { return e.ctrlKey || e.metaKey; } function xpathString(str) { var parts = str.match(\/[^'\"]+|['\"]\/g).map(function (part) { if (\"'\" == part) { return '\"\\'\"'; } if ('\"' == part) { return \"'\\\"'\"; } return \"'\" + part + \"'\"; }); return \"concat(\" + parts.join(\",\") + \", '')\"; } function xpathHasClass(className) { return \"contains(concat(' ', normalize-space(@class), ' '), ' \" + className +\" ')\"; } a('mouseover', function (a, e, c) { if (c) { e.target.style.cursor = \"pointer\"; } }); a('click', function (a, e, c) { if (\/\\bsf-dump-toggle\\b\/.test(a.className)) { e.preventDefault(); if (!toggle(a, isCtrlKey(e))) { var r = doc.getElementById(a.getAttribute('href').slice(1)), s = r.previousSibling, f = r.parentNode, t = a.parentNode; t.replaceChild(r, a); f.replaceChild(a, s); t.insertBefore(s, r); f = f.firstChild.nodeValue.match(indentRx); t = t.firstChild.nodeValue.match(indentRx); if (f && t && f[0] !== t[0]) { r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\\\$1'), 'mg'), t[0]); } if (\/\\bsf-dump-compact\\b\/.test(r.className)) { toggle(s, isCtrlKey(e)); } } if (c) { } else if (doc.getSelection) { try { doc.getSelection().removeAllRanges(); } catch (e) { doc.getSelection().empty(); } } else { doc.selection.empty(); } } else if (\/\\bsf-dump-str-toggle\\b\/.test(a.className)) { e.preventDefault(); e = a.parentNode.parentNode; e.className = e.className.replace(\/\\bsf-dump-str-(expand|collapse)\\b\/, a.parentNode.className); } }); elt = root.getElementsByTagName('SAMP'); len = elt.length; i = 0; while (i < len) t.push(elt[i++]); len = t.length; for (i = 0; i < len; ++i) { elt = t[i]; if ('SAMP' == elt.tagName) { a = elt.previousSibling || {}; if ('A' != a.tagName) { a = doc.createElement('A'); a.className = 'sf-dump-ref'; elt.parentNode.insertBefore(a, elt); } else { a.innerHTML += ' '; } a.title = (a.title ? a.title+'\\n[' : '[')+keyHint+'+click] Expand all children'; a.innerHTML += elt.className == 'sf-dump-compact' ? '<span>\u25b6<\/span>' : '<span>\u25bc<\/span>'; a.className += ' sf-dump-toggle'; x = 1; if ('sf-dump' != elt.parentNode.className) { x += elt.parentNode.getAttribute('data-depth')\/1; } } else if (\/\\bsf-dump-ref\\b\/.test(elt.className) && (a = elt.getAttribute('href'))) { a = a.slice(1); elt.className += ' sf-dump-hover'; elt.className += ' '+a; if (\/[\\[{]$\/.test(elt.previousSibling.nodeValue)) { a = a != elt.nextSibling.id && doc.getElementById(a); try { s = a.nextSibling; elt.appendChild(a); s.parentNode.insertBefore(a, s); if (\/^[@#]\/.test(elt.innerHTML)) { elt.innerHTML += ' <span>\u25b6<\/span>'; } else { elt.innerHTML = '<span>\u25b6<\/span>'; elt.className = 'sf-dump-ref'; } elt.className += ' sf-dump-toggle'; } catch (e) { if ('&' == elt.innerHTML.charAt(0)) { elt.innerHTML = '\u2026'; elt.className = 'sf-dump-ref'; } } } } } if (doc.evaluate && Array.from && root.children.length > 1) { root.setAttribute('tabindex', 0); SearchState = function () { this.nodes = []; this.idx = 0; }; SearchState.prototype = { next: function () { if (this.isEmpty()) { return this.current(); } this.idx = this.idx < (this.nodes.length - 1) ? this.idx + 1 : 0; return this.current(); }, previous: function () { if (this.isEmpty()) { return this.current(); } this.idx = this.idx > 0 ? this.idx - 1 : (this.nodes.length - 1); return this.current(); }, isEmpty: function () { return 0 === this.count(); }, current: function () { if (this.isEmpty()) { return null; } return this.nodes[this.idx]; }, reset: function () { this.nodes = []; this.idx = 0; }, count: function () { return this.nodes.length; }, }; function showCurrent(state) { var currentNode = state.current(), currentRect, searchRect; if (currentNode) { reveal(currentNode); highlight(root, currentNode, state.nodes); if ('scrollIntoView' in currentNode) { currentNode.scrollIntoView(true); currentRect = currentNode.getBoundingClientRect(); searchRect = search.getBoundingClientRect(); if (currentRect.top < (searchRect.top + searchRect.height)) { window.scrollBy(0, -(searchRect.top + searchRect.height + 5)); } } } counter.textContent = (state.isEmpty() ? 0 : state.idx + 1) + ' of ' + state.count(); } var search = doc.createElement('div'); search.className = 'sf-dump-search-wrapper sf-dump-search-hidden'; search.innerHTML = ' <input type=\"text\" class=\"sf-dump-search-input\"> <span class=\"sf-dump-search-count\">0 of 0<\\\/span> <button type=\"button\" class=\"sf-dump-search-input-previous\" tabindex=\"-1\"> <svg viewBox=\"0 0 1792 1792\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M1683 1331l-166 165q-19 19-45 19t-45-19L896 965l-531 531q-19 19-45 19t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19 45-19t45 19l742 741q19 19 19 45.5t-19 45.5z\"\\\/><\\\/svg> <\\\/button> <button type=\"button\" class=\"sf-dump-search-input-next\" tabindex=\"-1\"> <svg viewBox=\"0 0 1792 1792\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M1683 808l-742 741q-19 19-45 19t-45-19L109 808q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z\"\\\/><\\\/svg> <\\\/button> '; root.insertBefore(search, root.firstChild); var state = new SearchState(); var searchInput = search.querySelector('.sf-dump-search-input'); var counter = search.querySelector('.sf-dump-search-count'); var searchInputTimer = 0; var previousSearchQuery = ''; addEventListener(searchInput, 'keyup', function (e) { var searchQuery = e.target.value; \/* Don't perform anything if the pressed key didn't change the query *\/ if (searchQuery === previousSearchQuery) { return; } previousSearchQuery = searchQuery; clearTimeout(searchInputTimer); searchInputTimer = setTimeout(function () { state.reset(); collapseAll(root); resetHighlightedNodes(root); if ('' === searchQuery) { counter.textContent = '0 of 0'; return; } var classMatches = [ \"sf-dump-str\", \"sf-dump-key\", \"sf-dump-public\", \"sf-dump-protected\", \"sf-dump-private\", ].map(xpathHasClass).join(' or '); var xpathResult = doc.evaluate('.\/\/span[' + classMatches + '][contains(translate(child::text(), ' + xpathString(searchQuery.toUpperCase()) + ', ' + xpathString(searchQuery.toLowerCase()) + '), ' + xpathString(searchQuery.toLowerCase()) + ')]', root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null); while (node = xpathResult.iterateNext()) state.nodes.push(node); showCurrent(state); }, 400); }); Array.from(search.querySelectorAll('.sf-dump-search-input-next, .sf-dump-search-input-previous')).forEach(function (btn) { addEventListener(btn, 'click', function (e) { e.preventDefault(); -1 !== e.target.className.indexOf('next') ? state.next() : state.previous(); searchInput.focus(); collapseAll(root); showCurrent(state); }) }); addEventListener(root, 'keydown', function (e) { var isSearchActive = !\/\\bsf-dump-search-hidden\\b\/.test(search.className); if ((114 === e.keyCode && !isSearchActive) || (isCtrlKey(e) && 70 === e.keyCode)) { \/* F3 or CMD\/CTRL + F *\/ if (70 === e.keyCode && document.activeElement === searchInput) { \/* * If CMD\/CTRL + F is hit while having focus on search input, * the user probably meant to trigger browser search instead. * Let the browser execute its behavior: *\/ return; } e.preventDefault(); search.className = search.className.replace(\/\\bsf-dump-search-hidden\\b\/, ''); searchInput.focus(); } else if (isSearchActive) { if (27 === e.keyCode) { \/* ESC key *\/ search.className += ' sf-dump-search-hidden'; e.preventDefault(); resetHighlightedNodes(root); searchInput.value = ''; } else if ( (isCtrlKey(e) && 71 === e.keyCode) \/* CMD\/CTRL + G *\/ || 13 === e.keyCode \/* Enter *\/ || 114 === e.keyCode \/* F3 *\/ ) { e.preventDefault(); e.shiftKey ? state.previous() : state.next(); collapseAll(root); showCurrent(state); } } }); } if (0 >= options.maxStringLength) { return; } try { elt = root.querySelectorAll('.sf-dump-str'); len = elt.length; i = 0; t = []; while (i < len) t.push(elt[i++]); len = t.length; for (i = 0; i < len; ++i) { elt = t[i]; s = elt.innerText || elt.textContent; x = s.length - options.maxStringLength; if (0 < x) { h = elt.innerHTML; elt[elt.innerText ? 'innerText' : 'textContent'] = s.substring(0, options.maxStringLength); elt.className += ' sf-dump-str-collapse'; elt.innerHTML = '<span class=sf-dump-str-collapse>'+h+'<a class=\"sf-dump-ref sf-dump-str-toggle\" title=\"Collapse\"> \u25c0<\/a><\/span>'+ '<span class=sf-dump-str-expand>'+elt.innerHTML+'<a class=\"sf-dump-ref sf-dump-str-toggle\" title=\"'+x+' remaining characters\"> \u25b6<\/a><\/span>'; } } } catch (e) { } }; })(document); <\/script>
<style> .sf-js-enabled .phpdebugbar pre.sf-dump .sf-dump-compact, .sf-js-enabled .sf-dump-str-collapse .sf-dump-str-collapse, .sf-js-enabled .sf-dump-str-expand .sf-dump-str-expand { display: none; } .sf-dump-hover:hover { background-color: #B729D9; color: #FFF !important; border-radius: 2px; } .phpdebugbar pre.sf-dump { display: block; white-space: pre; padding: 5px; overflow: initial !important; } .phpdebugbar pre.sf-dump:after { content: \"\"; visibility: hidden; display: block; height: 0; clear: both; } .phpdebugbar pre.sf-dump span { display: inline-flex; } .phpdebugbar pre.sf-dump a { text-decoration: none; cursor: pointer; border: 0; outline: none; color: inherit; } .phpdebugbar pre.sf-dump img { max-width: 50em; max-height: 50em; margin: .5em 0 0 0; padding: 0; background: url(data:image\/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAHUlEQVQY02O8zAABilCaiQEN0EeA8QuUcX9g3QEAAjcC5piyhyEAAAAASUVORK5CYII=) #D3D3D3; } .phpdebugbar pre.sf-dump .sf-dump-ellipsis { display: inline-block; overflow: visible; text-overflow: ellipsis; max-width: 5em; white-space: nowrap; overflow: hidden; vertical-align: top; } .phpdebugbar pre.sf-dump .sf-dump-ellipsis+.sf-dump-ellipsis { max-width: none; } .phpdebugbar pre.sf-dump code { display:inline; padding:0; background:none; } .sf-dump-public.sf-dump-highlight, .sf-dump-protected.sf-dump-highlight, .sf-dump-private.sf-dump-highlight, .sf-dump-str.sf-dump-highlight, .sf-dump-key.sf-dump-highlight { background: rgba(111, 172, 204, 0.3); border: 1px solid #7DA0B1; border-radius: 3px; } .sf-dump-public.sf-dump-highlight-active, .sf-dump-protected.sf-dump-highlight-active, .sf-dump-private.sf-dump-highlight-active, .sf-dump-str.sf-dump-highlight-active, .sf-dump-key.sf-dump-highlight-active { background: rgba(253, 175, 0, 0.4); border: 1px solid #ffa500; border-radius: 3px; } .phpdebugbar pre.sf-dump .sf-dump-search-hidden { display: none !important; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper { font-size: 0; white-space: nowrap; margin-bottom: 5px; display: flex; position: -webkit-sticky; position: sticky; top: 5px; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > * { vertical-align: top; box-sizing: border-box; height: 21px; font-weight: normal; border-radius: 0; background: #FFF; color: #757575; border: 1px solid #BBB; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > input.sf-dump-search-input { padding: 3px; height: 21px; font-size: 12px; border-right: none; border-top-left-radius: 3px; border-bottom-left-radius: 3px; color: #000; min-width: 15px; width: 100%; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next, .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous { background: #F2F2F2; outline: none; border-left: none; font-size: 0; line-height: 0; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next { border-top-right-radius: 3px; border-bottom-right-radius: 3px; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next > svg, .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous > svg { pointer-events: none; width: 12px; height: 12px; } .phpdebugbar pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-count { display: inline-block; padding: 0 5px; margin: 0; border-left: none; line-height: 21px; font-size: 12px; }.phpdebugbar pre.sf-dump, .phpdebugbar pre.sf-dump .sf-dump-default{word-wrap: break-word; white-space: pre-wrap; word-break: normal}.phpdebugbar pre.sf-dump .sf-dump-num{font-weight:bold; color:#1299DA}.phpdebugbar pre.sf-dump .sf-dump-const{font-weight:bold}.phpdebugbar pre.sf-dump .sf-dump-str{font-weight:bold; color:#3A9B26}.phpdebugbar pre.sf-dump .sf-dump-note{color:#1299DA}.phpdebugbar pre.sf-dump .sf-dump-ref{color:#7B7B7B}.phpdebugbar pre.sf-dump .sf-dump-public{color:#000000}.phpdebugbar pre.sf-dump .sf-dump-protected{color:#000000}.phpdebugbar pre.sf-dump .sf-dump-private{color:#000000}.phpdebugbar pre.sf-dump .sf-dump-meta{color:#B729D9}.phpdebugbar pre.sf-dump .sf-dump-key{color:#3A9B26}.phpdebugbar pre.sf-dump .sf-dump-index{color:#1299DA}.phpdebugbar pre.sf-dump .sf-dump-ellipsis{color:#A0A000}.phpdebugbar pre.sf-dump .sf-dump-ns{user-select:none;}.phpdebugbar pre.sf-dump .sf-dump-ellipsis-note{color:#1299DA}<\/style>\n
<script type=\"text\/javascript\">\nvar phpdebugbar = new PhpDebugBar.DebugBar();\nphpdebugbar.addIndicator(\"php_version\", new PhpDebugBar.DebugBar.Indicator({\"icon\":\"code\",\"tooltip\":\"PHP Version\"}), \"right\");\nphpdebugbar.addTab(\"messages\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"list-alt\",\"title\":\"Messages\", \"widget\": new PhpDebugBar.Widgets.MessagesWidget()}));\nphpdebugbar.addIndicator(\"time\", new PhpDebugBar.DebugBar.Indicator({\"icon\":\"clock-o\",\"tooltip\":\"Request Duration\"}), \"right\");\nphpdebugbar.addTab(\"timeline\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"tasks\",\"title\":\"Timeline\", \"widget\": new PhpDebugBar.Widgets.TimelineWidget()}));\nphpdebugbar.addIndicator(\"memory\", new PhpDebugBar.DebugBar.Indicator({\"icon\":\"cogs\",\"tooltip\":\"Memory Usage\"}), \"right\");\nphpdebugbar.addTab(\"exceptions\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"bug\",\"title\":\"Exceptions\", \"widget\": new PhpDebugBar.Widgets.ExceptionsWidget()}));\nphpdebugbar.addTab(\"views\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"leaf\",\"title\":\"Views\", \"widget\": new PhpDebugBar.Widgets.TemplatesWidget()}));\nphpdebugbar.addTab(\"route\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"share\",\"title\":\"Route\", \"widget\": new PhpDebugBar.Widgets.HtmlVariableListWidget()}));\nphpdebugbar.addIndicator(\"currentroute\", new PhpDebugBar.DebugBar.Indicator({\"icon\":\"share\",\"tooltip\":\"Route\"}), \"right\");\nphpdebugbar.addTab(\"queries\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"database\",\"title\":\"Queries\", \"widget\": new PhpDebugBar.Widgets.SQLQueriesWidget()}));\nphpdebugbar.addTab(\"models\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"cubes\",\"title\":\"Models\", \"widget\": new PhpDebugBar.Widgets.HtmlVariableListWidget()}));\nphpdebugbar.addTab(\"emails\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"inbox\",\"title\":\"Mails\", \"widget\": new PhpDebugBar.Widgets.MailsWidget()}));\nphpdebugbar.addTab(\"gate\", new PhpDebugBar.DebugBar.Tab({\"icon\":\"list-alt\",\"title\":\"Gate\", \"widget\": new PhpDebugBar.Widgets.MessagesWidget()}));\nphpdebugbar.setDataMap({\n\"php_version\": [\"php.version\", ],\n\"messages\": [\"messages.messages\", []],\n\"messages:badge\": [\"messages.count\", null],\n\"time\": [\"time.duration_str\", '0ms'],\n\"timeline\": [\"time\", {}],\n\"memory\": [\"memory.peak_usage_str\", '0B'],\n\"exceptions\": [\"exceptions.exceptions\", []],\n\"exceptions:badge\": [\"exceptions.count\", null],\n\"views\": [\"views\", []],\n\"views:badge\": [\"views.nb_templates\", 0],\n\"route\": [\"route\", {}],\n\"currentroute\": [\"route.uri\", ],\n\"queries\": [\"queries\", []],\n\"queries:badge\": [\"queries.nb_statements\", 0],\n\"models\": [\"models.data\", {}],\n\"models:badge\": [\"models.count\", 0],\n\"emails\": [\"symfonymailer_mails.mails\", []],\n\"emails:badge\": [\"symfonymailer_mails.count\", null],\n\"gate\": [\"gate.messages\", []],\n\"gate:badge\": [\"gate.count\", null]\n});\nphpdebugbar.restoreState();\nphpdebugbar.ajaxHandler = new PhpDebugBar.AjaxHandler(phpdebugbar, undefined, true);\nphpdebugbar.ajaxHandler.bindToFetch();\nphpdebugbar.ajaxHandler.bindToXHR();\nphpdebugbar.setOpenHandler(new PhpDebugBar.OpenHandler({\"url\":\"http:\\\/\\\/localhost\\\/_debugbar\\\/open\"}));\nphpdebugbar.addDataSet({\"__meta\":{\"id\":\"Xd54c0d81c083b9605828bbee9a3e0ff3\",\"datetime\":\"2024-06-26 15:28:56\",\"utime\":1719440936.945661,\"method\":\"GET\",\"uri\":\"\\\/app\\\/debugbar\",\"ip\":\"127.0.0.1\"},\"php\":{\"version\":\"8.2.15\",\"interface\":\"cli-server\"},\"messages\":{\"count\":3,\"messages\":[{\"message\":\"[15:28:56] LOG.info: sql: select top 1 * from [sessions] where [id] = ?\",\"message_html\":null,\"is_string\":false,\"label\":\"info\",\"time\":1719440936.940657,\"xdebug_link\":null,\"collector\":\"log\"},{\"message\":\"[15:28:56] LOG.info: bindings: array (\\n  0 => '6zLP4RGwc3qZMRaEFOxYt9rYFMJ1ipA8UAZ5tYdi',\\n)\",\"message_html\":null,\"is_string\":false,\"label\":\"info\",\"time\":1719440936.94074,\"xdebug_link\":null,\"collector\":\"log\"},{\"message\":\"[15:28:56] LOG.info: query time: 2.24\",\"message_html\":null,\"is_string\":false,\"label\":\"info\",\"time\":1719440936.940811,\"xdebug_link\":null,\"collector\":\"log\"}]},\"time\":{\"start\":1719440936.803974,\"end\":1719440936.945689,\"duration\":0.14171504974365234,\"duration_str\":\"142ms\",\"measures\":[{\"label\":\"Booting\",\"start\":1719440936.803974,\"relative_start\":0,\"end\":1719440936.927631,\"relative_end\":1719440936.927631,\"duration\":0.1236569881439209,\"duration_str\":\"124ms\",\"memory\":0,\"memory_str\":\"0B\",\"params\":[],\"collector\":\"time\"},{\"label\":\"Application\",\"start\":1719440936.927638,\"relative_start\":0.12366414070129395,\"end\":1719440936.94569,\"relative_end\":9.5367431640625e-7,\"duration\":0.018051862716674805,\"duration_str\":\"18.05ms\",\"memory\":0,\"memory_str\":\"0B\",\"params\":[],\"collector\":\"time\"}]},\"memory\":{\"peak_usage\":38198008,\"peak_usage_str\":\"36MB\"},\"exceptions\":{\"count\":0,\"exceptions\":[]},\"views\":{\"nb_templates\":0,\"templates\":[]},\"route\":{\"uri\":\"GET app\\\/debugbar\",\"middleware\":\"public\",\"excluded_middleware\":[\"ValidateSession\",\"LogHit\",\"App\\\\Http\\\\Middleware\\\\PublicSiteAuth\"],\"controller\":\"\\\\App\\\\Http\\\\Controllers\\\\FrontendController@renderDebugBar\",\"namespace\":null,\"prefix\":\"\",\"where\":[],\"file\":\"<a href=\\\"phpstorm:\\\/\\\/open?file=%2FUsers%2Fsam%2Fcode%2Flaravel%2Fapp%2FHttp%2FControllers%2FFrontendController.php&line=22\\\" onclick=\\\"\\\">app\\\/Http\\\/Controllers\\\/FrontendController.php:22-29<\\\/a>\"},\"queries\":{\"nb_statements\":1,\"nb_failed_statements\":0,\"accumulated_duration\":0.0022400000000000002,\"accumulated_duration_str\":\"2.24ms\",\"memory_usage\":0,\"memory_usage_str\":null,\"statements\":[{\"sql\":\"select top 1 * from [sessions] where [id] = '6zLP4RGwc3qZMRaEFOxYt9rYFMJ1ipA8UAZ5tYdi'\",\"type\":\"query\",\"params\":[],\"bindings\":[\"6zLP4RGwc3qZMRaEFOxYt9rYFMJ1ipA8UAZ5tYdi\"],\"hints\":null,\"show_copy\":false,\"backtrace\":[{\"index\":15,\"namespace\":null,\"name\":\"vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/DatabaseSessionHandler.php\",\"file\":\"\\\/Users\\\/sam\\\/code\\\/laravel\\\/vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/DatabaseSessionHandler.php\",\"line\":97},{\"index\":16,\"namespace\":null,\"name\":\"vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Store.php\",\"file\":\"\\\/Users\\\/sam\\\/code\\\/laravel\\\/vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Store.php\",\"line\":113},{\"index\":17,\"namespace\":null,\"name\":\"vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Store.php\",\"file\":\"\\\/Users\\\/sam\\\/code\\\/laravel\\\/vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Store.php\",\"line\":101},{\"index\":18,\"namespace\":null,\"name\":\"vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Store.php\",\"file\":\"\\\/Users\\\/sam\\\/code\\\/laravel\\\/vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Store.php\",\"line\":85},{\"index\":19,\"namespace\":null,\"name\":\"vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Middleware\\\/StartSession.php\",\"file\":\"\\\/Users\\\/sam\\\/code\\\/laravel\\\/vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/Middleware\\\/StartSession.php\",\"line\":147}],\"start\":1719440936.9386091,\"duration\":0.0022400000000000002,\"duration_str\":\"2.24ms\",\"memory\":0,\"memory_str\":null,\"filename\":\"DatabaseSessionHandler.php:97\",\"source\":\"vendor\\\/laravel\\\/framework\\\/src\\\/Illuminate\\\/Session\\\/DatabaseSessionHandler.php:97\",\"xdebug_link\":{\"url\":\"phpstorm:\\\/\\\/open?file=%2FUsers%2Fsam%2Fcode%2Flaravel%2Fvendor%2Flaravel%2Fframework%2Fsrc%2FIlluminate%2FSession%2FDatabaseSessionHandler.php&line=97\",\"ajax\":false,\"filename\":\"DatabaseSessionHandler.php\",\"line\":\"97\"},\"connection\":\"LaravelAtlas\",\"start_percent\":0,\"width_percent\":100}]},\"models\":{\"data\":[],\"count\":0,\"is_counter\":true},\"symfonymailer_mails\":{\"count\":0,\"mails\":[]},\"gate\":{\"count\":0,\"messages\":[]}}, \"Xd54c0d81c083b9605828bbee9a3e0ff3\");\n\n<\/script>\n

Then I also needed to modify the patttern used as the key under the devServer.proxy configuration in vue.config.js to send the debugbar AJAX requests to the laravel service, just as it does for the other API requests.

With the updated path (formerly was '^/app/'):

module.exports = {
  devServer: {
    proxy: {
      '^/(app|_debugbar)/': {
        target: 'http://localhost:8000'
        ws: true,
        changeOrigin: true
      }
    }
  }
}

injectDebugbar.js

This is integrated in app.vue via require(). It takes the <script> tag that has a src attribute set on it and adds it to the <head> element. After it has loaded then the other elements will be added to the <head>.

Initially I attempted to simply add the HTML elements without cloning them but it seemed that the scripts were not loaded or executed, so I had to manually set the src or text attribute.

import Vue from 'vue'

document.addEventListener('DOMContentLoaded', async () => {
  try {
    const response = await Vue.prototype.$http.get('debugbar')
    const headElement = document.createElement('head')
    headElement.innerHTML = response.data.toAppend
    const scriptWithSrc = headElement.querySelector('script[src]')
    if (!scriptWithSrc) {
      throw new Error('no script tag with src attribute set- cannot proceed as usual')
    }
    const clonedScriptWithSrc = document.createElement('script')
    clonedScriptWithSrc.src = scriptWithSrc.getAttribute('src')
    clonedScriptWithSrc.addEventListener('load', () => {
      if (typeof jQuery === 'function') {
        [...headElement.children].forEach((child) => {
          if (child.nodeName.toLowerCase() === 'script') {
            const scriptElement = document.createElement('script')
            scriptElement.text = child.text
            document.head.appendChild(scriptElement)
            headElement.removeChild(child)
          } else {
            document.head.appendChild(child)
          }
        })
      }
    })
    headElement.removeChild(scriptWithSrc)
    document.head.appendChild(clonedScriptWithSrc)
  } catch (e) {
    console.log('caught exception: ', e.message)
  }
})

I know I could have used the parseFromString method from DOMParser but it seemed simple enough to just set the innerHTML of the temporary <head> element which doesn't require setting the mimeType.

Is there a simpler and/or more robust way to do this?

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.