Nette jako backend – zapojení Laděnky (Tracy)
- sjiamnocna
- Člen | 28
Ahoj,
dělám co nejjednodušší Nettí backend, tj. vyhodil jsem presentry, templaty
ap.
Na FE používám React, ale asi klidně může být něco Javascriptího;
Fakt hodně špatně se to ladí a rád bych měl k dispozici „tradiční“ tracy bar.
Existuje nějaké rozšíření, které by se dalo použít k AJAX requestům a zároveň bych dostal možnost vidět Tracybar?
Případně jak dostanu z Laděnky tracybar kód, abych to mohl nalepit na
každý devel požadavek a poslat dál?
To by potom šlo zobrazit dangerouslySetInnerHTML.
FireLogger vypadá dobře, ale Tracybar to není, navíc je to jen hrom.
Děkuji za nápady :)
Editoval sjiamnocna (4. 5. 2021 15:35)
- uestla
- Backer | 799
Čekal bych, že bude stačit do projektu přidat tracy jako závislost a
v nějakém bootstrapu povolit (https://tracy.nette.org/cs/guide#…).
AJAX požadavky by také měly fungovat out-of-the-box (detaily v https://tracy.nette.org/cs/recipes#…).
- Marek Bartoš
- Nette Blogger | 1263
Tracy se do response připojuje při Content-Type: text/html
,
při jiných typech obsahu se neumí připojit automaticky a ani nemá, jak sama
sebe zobrazit. Asi by šlo podporovat různé typy obsahu response skrze
nějaký interface a vykreslení do stránky nechat na frontendu aplikace, ale
momentálně to myslím podporované není.
Editoval Marek Bartoš (4. 5. 2021 16:41)
- chloris
- Člen | 23
Zrovna řeším něco podobného. Chci udělat SPA aplikaci (v libovolném JS frameworku) a na Backendu mít API v Nette. Chci mít možnost vidět laděnku na každý XHR request (SQL dotazy, případně hezké exceptions a tak). Zatím jsem ve fázi, kdy hledám, zda to už někdo řešil, takže jsem nekoukal, jak je Tracy psaná. Ale teoreticky by stačilo poskytovat nějaký frontendový balíček s laděnkou, který by vykreslil obálku a taky se navázal na XHR dotazy a posílal na server hlavičku „X-Tracy-Ajax: 7a90cbcace2“ a po obdržení odpovědi by se klasicky zeptal druhým dotazem „?_tracy_bar=content-ajax.7a90cbcace2 …“ a obdrženou odpověď zapsal do již připravené obálky. Představuju si to možná naivně jednoduše, ale asi to zkusím napsat :-).
- Marek Bartoš
- Nette Blogger | 1263
Možná pomůže toto. Vyrenderuje to <script>
s Tracy do
proměnné. Na vás je poslat si jej v response a vypsat do stránky
$tracyHtml = \Tracy\Helpers::capture(static function (): void {
\Tracy\Debugger::renderLoader();
});
Editoval Marek Bartoš (7. 5. 2021 21:53)
- chloris
- Člen | 23
Tak jsem to vyzkoušel a funguje to. Nemám sice nikde zatím k vidění online funkční example (mám to v rozdělaném projektu zatím u sebe), ale principiálně je to jednoduché. Co jsem udělal:
- Z Tracy jsem vyzobal všechny JS a CSS a spojil je dohromady jako jeden JS a jeden CSS, a nalinkoval klasicky do dokumentu:
- v takto nactene Tracy jsem pretizil Tracy.Debug.captureAjax, ktera je omezena na stejny „origin“ (reqIdPrefix je ID pro klic do SESSION, ktery se standardne generuje jiz v PHP, zde si ho musime vygenerovat v JS). Vykopírováno z Typescript souboru…
const Tracy = (window as any).Tracy;
Tracy.Debug.captureAjax = () => {
let ajaxCounter = 1;
let autoRefresh = this.settings.autoRefresh;
let reqIdPrefix = ((new Date().getTime()).toString(16)).split('', 10).reverse().join('');
let oldOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
oldOpen.apply(this, arguments);
let url = new URL(arguments[1], location.origin);
if (autoRefresh) { // url.host === location.host;
let reqId = reqIdPrefix + '_' + (ajaxCounter++).toString();
this.setRequestHeader('X-Tracy-Ajax', reqId);
this.addEventListener('load', function() {
if (this.getAllResponseHeaders().match(/^X-Tracy-Ajax: 1/mi)) {
let scriptUrl = url.origin + '/?' + '_tracy_bar=content-ajax.' + reqId + '&XDEBUG_SESSION_STOP=1&v=' + Math.random();
Tracy.Debug.loadScript(scriptUrl);
}
});
}
};
let oldFetch = window.fetch;
window.fetch = function(request, options) {
request = request instanceof Request ? request : new Request(request, options || {});
let url = new URL(request.url, location.origin);
if (autoRefresh) { // && url.host === location.host
let reqId = reqIdPrefix + '_' + (ajaxCounter++).toString();
request.headers.set('X-Tracy-Ajax', reqId);
return oldFetch(request).then((response) => {
if (response instanceof Response && response.headers.has('X-Tracy-Ajax') && response.headers.get('X-Tracy-Ajax')[0] === '1') {
let scriptUrl = url.origin + '/?' + '_tracy_bar=content-ajax.' + reqId + '&XDEBUG_SESSION_STOP=1&v=' + Math.random();
Tracy.Debug.loadScript(scriptUrl);
}
return response;
});
}
return oldFetch(request);
};
};
- připravil jsem si kontejner pro ajaxové požadavky (je potřeba, protože Tracy v Single Page Aplikaci nevygeneruje PHPko). Toto je pak v dokumentu, kde mám nalinkované JS a CSS.
let mainGroup = `<ul class="tracy-row" data-tracy-group="main">
<li id="tracy-debug-logo" style="flex-grow:1;">
<svg viewBox="0 -10 1561 333"><path fill="#585755" d="m176 327h-57v-269h-119v-57h291v57h-115v269zm208-191h114c50 0 47-78 0-78h-114v78zm106-135c17 0 33 2 46 7 75 30 75 144 1 175-13 6-29 8-47 8h-27l132 74v68l-211-128v122h-57v-326h163zm300 57c-5 0-9 3-11 9l-56 156h135l-55-155c-2-7-6-10-13-10zm-86 222l-17 47h-61l102-285c20-56 107-56 126 0l102 285h-61l-17-47h-174zm410 47c-98 0-148-55-148-163v-2c0-107 50-161 149-161h118v57h-133c-26 0-45 8-58 25-12 17-19 44-19 81 0 71 26 106 77 106h133v57h-119zm270-145l-121-181h68l81 130 81-130h68l-121 178v148h-56v-145z"></path></svg>
</li>
<li><a href="#" data-tracy-action="close" title="close debug bar">×</a></li>
</ul>`;
Tracy.Debug.setOptions({
maxAjaxRows: 20, // kolik dotazu se zobrazi, nez zacnou mizet
panelZIndex: 20000 // z-index panelu
});
Tracy.Debug.init(`<div id="tracy-debug-bar">${mainGroup}</div>`);
- Na serveru, pokud nám běží na jiném ORIGINu, je potřeba pak poslat Access-Control hlavičky a povolit origin a x-tracy-ajax header – tedy v presenteru někde poslat:
// Get ORIGIN
$origin = $this->getHttpRequest()->getHeader('origin');
if($origin !== NULL)
{
$resp = $this->getHttpResponse();
$resp->addHeader('Access-Control-Allow-Origin', $origin);
$resp->addHeader('Access-Control-Allow-Credentials', 'true');
$resp->addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
$resp->addHeader('Access-Control-Allow-Headers', 'origin, content-type, accept, x-tracy-ajax');
$resp->addHeader('Access-Control-Expose-Headers', 'origin, location, content-type, accept, x-tracy-ajax');
$resp->addHeader('Access-Control-Max-Age', "1728000");
}
A funguje to! Zachytává se každý ajaxový dotaz do API, které běží na Nette BackEndu a pokud nastane Exception, zobrazí se i ta.
Pokud budu mít čas a bude zájem, můžu udělat někde online funkční example. Zatím alespoň takto, kdyby to někdo chtěl zkusit taky.
Editoval chloris (14. 5. 2021 17:29)
- sjiamnocna
- Člen | 28
Kdybys to @chloris mohl někam dát, budu moc rád. Mě se to zatím nepodařilo napodobit.
Díky
- chloris
- Člen | 23
Spíchnul jsem narychlo principiální demo pro @sjiamnocna.
https://github.com/…/tracy-4-api
V readme v repozitě je popis, jak to zprovoznit.
Jen zmíním, že Tracy používá session pro ukládání laděnky během requestu a v následujícím requestu si pro ní sáhne. Je tedy potřeba, aby fungovala session cookie. To je možné (při současných cookies pravidlech) pouze v těchto dvou případech:
- Používáme http protokol (jako demo) a pak je možné spustit API i JS aplikaci pouze na stejném originu
- Používáme https protokol, pak je možné použít jiný origin (např. api.aplikace.com a app.aplikace.com)
- sjiamnocna
- Člen | 28
Zhruba chápu, co se tam děje, jen jsem to asi dělal celou dobu špatně – nebo je tam jiný zakopaný pes o kterém nevím – v TS nebo Reactu…
Díky moc :)
____________________
EDIT:
Vyměnil jsem XHR za Fetch, vyhodil JQuery a furt funguje.
Vypadá to ale, že když skočí bluescreen (červená chyba :D), tak to sejme úplně všechny Laděnkovité styly a mám jen minimum plaintext, což není hezký. Tak se s tím budu chvíli prát.
Děje se to řekněme i v původní verzi s XHR, takže tohle se musí ještě dozkoumat, budu si hrát, napíšu :)
Hezký den
Editoval sjiamnocna (4. 8. 2021 22:03)