putyourlightson / craft-sprig

A reactive Twig component framework for Craft CMS.
https://putyourlightson.com/plugins/sprig
MIT License
125 stars 9 forks source link

JS Reloading Issue #383

Closed bossanova808 closed 1 month ago

bossanova808 commented 1 month ago

Support Request

Hmm... I am thinking this: https://github.com/putyourlightson/craft-sprig/issues/329 might be related to/the cause of a recent issue we've been having.

We have a few sprig enabled control panel dashboard things, part of which is a toolbar that uses an s-trigger to refresh itself every 5 seconds (it displays some useful counts of things we need to act on).

In the last few weeks, we've been having constant performance issues with our site, particularly during business hours, and I just have not been able to work out why. In all the log combing etc, I have only been looking at external traffic, looking past 'internal' traffic as it's never been an issue in our 10+ years with Craft. I had pretty much convinced myself there was some sort of DDOS or more realistically over-zealous search bot thing going on...

However for some reason my brain flipped on this the other day and I then started to realise that there was actually a LOT of traffic coming from our office IP....way, way more than there should be. There's always a lot of noise, all the CP extended session stuff etc, but I realised it was in fact well beyond normal.

Digging in to this, I then noticed a strange thing (and for context, we load our htmx related JS using a Craft Asset bundle and always have done). Whenever one of these pages was open, I log all htmxAfterRequest event to the console. Looking in there, I started seeing a lot of these - and indeed, noticed that the number of log lines was increasing by one with each 5s refresh of the toolbar.

It seems that the JS via the asset bundle was being reloaded each time, and was certainly creating a highly increasing number of requests - on page load 1, then 2, then 3, etc.etc...continuing forever until the amount of traffic going back and forth from this one simple component refresh was seemingly pegging the CPU.

I've come to this conclusion largely by re-reading the Sprig JS docs and based on those moving the JS loading to be in the template:

{% js craft.app.assetManager.publishedUrl('@modules/bridge/assets/src/bridge.js', true) with {defer: true} %}

..and finding that immediately solves at least most of the issue, with the expected one network request every 5 seconds instead of this ever increasing number of requests.

(It's so long ago I am not per se sure why I used an Asset Bundle approach, presumably for convenience or just out of habit...)

I do note that even after this change, on each component refresh, all the standard back end JS is being reloaded each time too (from cache of course) - this also feels like new behaviour to me, I am fairly sure I have tracked network requests for this and not seen all this js constantly reloading.

Here's a video to make clear what I mean - I really do feel like something has changed here, and I don't really see why it is reloading this JS each time for a basic component refresh?

https://github.com/user-attachments/assets/773b0c62-1999-4da2-bdf4-25e51e35904b

Here's the templates involved:

{% extends '_layouts/cp' %}

{% set title = 'Stock Check' %}

{% block toolbar %}
    {{ (not devMode) ? sprig('bridge/_sprig_components/toolbar') }}
    {% js craft.app.assetManager.publishedUrl('@modules/bridge/assets/src/bridge.js', true) with {defer: true} %}
{% endblock %}

{% block content %}
    {{ sprig('bridge/_sprig_components/stock') }}
{% endblock %}

And the toolbar is :

{# Re-render the tool bar every 5 seconds.  Placed here so it doesn't trigger the indicators in the toolbar wrapper below... #}
{# IMPORTANT: Buttons below must all have IDs and s-preserve set to true... #}
{#{% if not devMode and craft.app.isLive and not craft.app.isInMaintenanceMode %}#}
<span id="trigger-toolbar" style="display:none;" sprig  s-trigger="every 5s"></span>
{#{% endif %}#}
{% set updatedTimes = craft.dear.cacheUpdatedTimes() %}
{% set countUnpushedOrders = craft.orders.orderStatusId(['1']).count() %}
{% set countWaitingOnPayment = craft.orders.orderStatusId(['16']).count() %}
{% set countPushError = craft.orders.orderStatusId(['24']).count() %}
{% set countActionDocs = craft.dear.countActionDocs() %}

<div id="toolbar" class="wrapper-toolbar">
 ... buttons etc
</div>

(Craft 4 latest + Sprig 2 latest)

Plugin Version

Sprig 2.10.1

bossanova808 commented 1 month ago

I am also seeing, in logs and just for these pages, what seems to be an excessive number of these:

199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 506 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 506 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 507 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 506 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 505 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 503 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 505 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 507 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 504 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 506 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
199.200.31.70 - - [08/Aug/2024:15:35:21 +1000] "GET /index.php/admin/actions/users/session-info?dontExtendSession=1 HTTP/2.0" 200 506 "https://imagescience.com.au/admin/bridge/sales" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"
bencroker commented 1 month ago

One of the things that changed in Sprig 2.10.0 is that components now render markup added via {% html %}, {% css %} and {% js %} tags. Are you using any of them inside your Sprig components?

Also, it is probably a better idea to allow Sprig to load htmx, which may turn out to solve your issue.

bossanova808 commented 1 month ago

I am not using those tags, no, other than as I said above, to load my js:

{% js craft.app.assetManager.publishedUrl('@modules/bridge/assets/src/bridge.js', true) with {defer: true} %}

Previously I loaded it this way (now commented out):

class BridgeAsset extends AssetBundle
{

    /**
     * @inheritdoc
     */
    public function init(): void
    {
        $this->sourcePath = __DIR__ . '/src';

        $this->depends = [
            CraftCpAsset::class,
            HtmxAssetBundle::class,
        ];

        $this->css = ['bridge.css'];
        // Now seems to cause the JS to be loaded over and over...?
//        $this->js = ['bridge.js'];

        parent::init();
    }
}

Is that what you mean by: Also, it is probably a better idea to allow Sprig to load htmx, which may turn out to solve your issue.

bencroker commented 1 month ago

Well, you definitely shouldn’t be loading your asset bundle inside the Sprig component, since it will load htmx and all CP assets in each component refresh. If you must, then load it in the page template, but it shouldn’t even be necessary to do so since Sprig will, by default, load its own asset bundle containing htmx. https://github.com/putyourlightson/craft-sprig-core/blob/develop/src/assets/HtmxAssetBundle.php

bossanova808 commented 1 month ago

Ok I am now very confused, sorry. We previously had a discord chat where (I thought, at least) - we came to the conclusion I should do this:

class Bridge extends Module
{
    use BridgeTrait;

    /**
     * @throws InvalidConfigException
     */
    public function init(): void
    {
        parent::init();
        self::$instance = $this;

        // See: https://github.com/putyourlightson/craft-sprig-core#sprig-core-module-for-craft-cms
        Sprig::bootstrap();

        if (Craft::$app->getRequest()->getIsCpRequest()) {
            Craft::$app->getView()->registerAssetBundle(BridgeAsset::class);
        }
    }
}

And

class BridgeAsset extends AssetBundle
{

    /**
     * @inheritdoc
     */
    public function init(): void
    {
        $this->sourcePath = __DIR__ . '/src';

        $this->depends = [
            CraftCpAsset::class,
            // make sure htmx is loaded _before_ bridge.js
            HtmxAssetBundle::class,
        ];

        $this->css = ['bridge.css'];
        $this->js = ['bridge.js'];

        parent::init();
    }
}

...to bootstrap Sprig and load htmx (early) for my module's js code (in bridge.js) to then use. Are you saying I've got this wrong and this is what is leading to the constant reloading of the CP JS with each refresh?

The question then would be - how can I avoid that, such that my bridge.js can access htmx?

The sprig components themselves (being standard live search twig things with a search bar and results area) are not loading any further js or bundles....so I really don't see why the s-trigger="every 5s" in the toolbar does anything more than reload this specific component...why is it dragging in all the CP assets?

(and why do none of my other components do this - only the toolbar with the polling causes this...)

bencroker commented 1 month ago

Are you saying I've got this wrong and this is what is leading to the constant reloading of the CP JS with each refresh?

No, I think I was misunderstanding how you’re using Sprig. This makes more sense to me now.

(and why do none of my other components do this - only the toolbar with the polling causes this...)

This is likely to hold the key to the puzzle. Can you show me how you are using polling on the toolbar? It might also be worth inspecting the raw response body and identify where the assets are being reloaded.

bossanova808 commented 1 month ago

Ok now we're getting somewhere I think...

The toolbar is a pretty simple thing:

{# Re-render the tool bar every 5 seconds.  Placed here so it doesn't trigger the indicators in the toolbar wrapper below... #}
{# IMPORTANT: Buttons below must all have IDs and s-preserve set to true... #}

<span id="trigger-toolbar" style="display:none;" sprig  s-trigger="every 5s"></span>

{% set updatedTimes = craft.dear.cacheUpdatedTimes() %}
{% set countUnpushedOrders = craft.orders.orderStatusId(['1']).count() %}
{% set countWaitingOnPayment = craft.orders.orderStatusId(['16']).count() %}
{% set countPushError = craft.orders.orderStatusId(['24']).count() %}
{% set countActionDocs = craft.dear.countActionDocs() %}

<div id="toolbar" class="wrapper-toolbar">

    <button
            id="print-docs-button"
            class="btn small action-button"
            title="Print the order action documents"
            sprig
            s-method="post"
            s-action="/dear/dear/print-docs"
            s-indicator="#indicator-print-docs"
            s-preserve="true"
    >
        Print Docs
        <img id="indicator-print-docs"
             alt="Print Docs"
             class="progress-indicator htmx-indicator"
             src="{{ craft.app.assetManager.publishedUrl('@modules/bridge/assets/icons/puff.svg', true) }}"
        >
    </button>

... etc for other buttons, and then there's the display of the counts:

    <div class="cache-class">
        <a href="https://imagescience.com.au/ghost/commerce/orders/orderreceived">New
            Orders</a>: <span
                class="cache-class-header">{{ countUnpushedOrders }}</span><br>
        New Docs: <span class="cache-class-header">{{ countActionDocs }}</span>
    </div>

</div>

Ok, the raw response body is interesting. There's the toolbar component itself being reloaded, just as show above albeit with some extra header stuff:

    <button id="update-cache-button" class="btn small action-button" title="Update the local DEAR cache" sprig s-method="post" s-action="/dear/dear/update-caches-job" s-indicator="#indicator-update-cache" s-preserve="true" data-hx-headers="{&quot;X-CSRF-Token&quot;:&quot;oOOBFPu4t0GBAhS0O8_QpDvCjV6BP6cTxvs7imsTGhZOJQReJjD9GMaj8lBtDzEauLye9z6YrdKbzBy1NGTslP3Qmf8Z3jjQqITupAfO__6pZN0Cd7QGA2evjotIFa-FqkI8sEafVhDWXTo9gb4SkDQatWeQSx571F7G6JSwqoTNaIrOSAF_RgPWV_Di7_2N2mcqx7Xubpjr3iLiNnzCTp6pkGiX5m7SUd97kcJhyVt3aVd5TXYrcEWxdrqSwmcMbFQjjo2txgugmuWqrS_WUAHUp8W1-s8g7Qrhm-XfkTKvnMyYBuhgR4ZjNVKZ7LkpJ8nhnSRfiH_8YiTnOmxS-91B-Vd5gQ_mPk8C4A2Tg6TjxPylP7OUCzEbNULhP4KXuYjBtBsb&quot;}" data-hx-post="https://craft-dev.ddev.site/index.php/ghost/actions/sprig-core/components/render?sprig:action=5bc8be6ef21fc12aad463442e9b76491034ea7e38fd2ddaaea92995aca4f32af/dear/dear/update-caches-job" data-hx-indicator="#indicator-update-cache" data-hx-preserve="true" data-sprig-parsed>
        Update Cache
        <img id="indicator-update-cache"
             alt="Update Cache"
             class="progress-indicator htmx-indicator"
             src="https://craft-dev.ddev.site/cpresources/a3c1a36a/puff.svg?v=1719183160"
        >
    </button>

That looks ok/expected to me.

However after toolbar is all of this:

<script>window.d3FormatLocaleDefinition = {"decimal":".","thousands":",","grouping":[3],"currency":"USD","numerals":["0","1","2","3","4","5","6","7","8","9"],"percent":"%","minus":"-","nan":"NaN"};
window.d3TimeFormatLocaleDefinition = {"dateTime":"%x, %X","date":"%-m/%-d/%Y","time":"%-I:%M:%S %p","periods":["AM","PM"],"days":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"shortDays":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"months":["January","February","March","April","May","June","July","August","September","October","November","December"],"shortMonths":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]};
window.d3Formats = {"shortDateFormats":{"day":"%-d\/%-m","month":"%-m\/%Y","year":"%Y"}};
if (typeof Craft.translations["app"] === 'undefined') {
    Craft.translations["app"] = {};
}
Craft.translations["app"]["{first, number}-{last, number} of {total, number} {total, plural, =1{{item}} other{{items}}}"] = "{first, number}–{last, number} of {total, number} {total, plural, =1{{item}} other{{items}}}";
Craft.translations["app"]["{first}-{last} of {total}"] = "{first}–{last} of {total}";</script><div s-swap-oob="beforeend:body" data-hx-swap-oob="beforeend:body" data-sprig-parsed><script>Sprig.components.push({"id":"component-ibafpe","siteId":"1","component":"","template":"bridge\/_sprig_components\/toolbar","variables":[],"action":null,"triggerRefreshSources":[]})</script></div><script src="https://craft-dev.ddev.site/cpresources/3ce35160/tailwind_reset.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/b8f47ac/axios.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/2d8b6f43/d3.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/e9457d40/jquery.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/bfb809ea/jquery.mobile-events.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/ba7cd43f/velocity.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/55d4d0e9/garnish.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/e3a2ed56/jquery-ui.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/bfebd688/jquery.payment.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/83b00c56/picturefill.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/3bf6eb42/selectize.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/fdd93bfd/jquery.fileupload.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/8808b156/xregexp-all.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/7d66e7fe/fabric.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/26ea66f4/iframeResizer.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/37be490a/cp.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/72c68d/htmx.min.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/8933f1d8/bridge.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/fdf968c5/cp.js?v=1709757525"></script>
<script src="https://craft-dev.ddev.site/cpresources/fdf968c5/cp-commerce-tweaks.js?v=1709757525"></script>
<script src="https://craft-dev.ddev.site/cpresources/3ef6e927/js/Campaign.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/3ef6e927/js/CampaignIndex.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/3ef6e927/js/ContactIndex.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/3ef6e927/js/MailingListIndex.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/3ef6e927/js/SegmentIndex.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/3ef6e927/js/SendoutIndex.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/b3a003c8/js/matrixcolors.js?v=1696384653"></script>
<script src="https://craft-dev.ddev.site/cpresources/6597a5b9/MatrixInput.js?v=1723254975"></script>
<script src="https://craft-dev.ddev.site/cpresources/efd83ed8/js/FieldManipulator.js?v=1696384653"></script>
<script>if (typeof Craft.MatrixInput !== "undefined") { Spoon.fieldmanipulator = new Spoon.FieldManipulator({"blockTypes":{"global":[{"id":129,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":14,"matrixBlockType":{"id":14,"fieldId":23,"fieldLayoutId":2451,"name":"Page Title","handle":"pageTitle","sortOrder":1,"hasFieldErrors":false,"uid":"0251ce53-74ba-4a07-b0a5-19c93067624b"},"groupName":"Headers","context":"global","groupSortOrder":1,"sortOrder":1,"uid":"9c69c54e-4929-47dd-b151-8379676ce432"},{"id":130,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":3,"matrixBlockType":{"id":3,"fieldId":23,"fieldLayoutId":2452,"name":"Header","handle":"header","sortOrder":2,"hasFieldErrors":false,"uid":"c399a538-15b5-4e68-b2c2-d6b9ad774ff7"},"groupName":"Headers","context":"global","groupSortOrder":1,"sortOrder":2,"uid":"0fff4007-d922-4176-99a9-e31b6513f427"},{"id":131,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":4,"matrixBlockType":{"id":4,"fieldId":23,"fieldLayoutId":2453,"name":"WYSIWYG Text Block","handle":"wysiwyg","sortOrder":3,"hasFieldErrors":false,"uid":"45e85d64-dee8-4c78-bee9-a0c6dfa45879"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":1,"uid":"639c5067-5be7-4724-9cff-faaf9ea515c9"},{"id":132,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":17,"matrixBlockType":{"id":17,"fieldId":23,"fieldLayoutId":2454,"name":"WYSIWYG Fixed Columns","handle":"wysiwygFixedColumns","sortOrder":4,"hasFieldErrors":false,"uid":"0e43f288-1697-4396-9460-a6d271f49632"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":2,"uid":"3518686d-69d6-4a8a-830d-eae7648ce4d2"},{"id":133,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":9,"matrixBlockType":{"id":9,"fieldId":23,"fieldLayoutId":2458,"name":"Feature List","handle":"featureList","sortOrder":7,"hasFieldErrors":false,"uid":"f94d14ff-f7e7-4b9b-b573-cf7a439828eb"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":3,"uid":"70a66cc9-833a-40c3-9fd0-57883ccd2680"},{"id":134,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":10,"matrixBlockType":{"id":10,"fieldId":23,"fieldLayoutId":2460,"name":"Accordion","handle":"accordion","sortOrder":8,"hasFieldErrors":false,"uid":"50693fd7-b114-4f61-9bcd-8319f2be2ae6"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":4,"uid":"a5ab594d-da22-4301-a2ec-b77950105328"},{"id":135,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":18,"matrixBlockType":{"id":18,"fieldId":23,"fieldLayoutId":2463,"name":"Image and Text","handle":"imageAndText","sortOrder":10,"hasFieldErrors":false,"uid":"925a0b07-8517-4f7d-b69d-8cefe49e8b4b"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":5,"uid":"a3a9cebe-7515-4775-9f86-dcb1448956c2"},{"id":136,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":21,"matrixBlockType":{"id":21,"fieldId":23,"fieldLayoutId":2469,"name":"Special","handle":"special","sortOrder":16,"hasFieldErrors":false,"uid":"dc7f1887-cd7b-40e2-8d97-86bc74be7462"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":6,"uid":"a6f4e922-b4d1-4127-92e7-979a4ea228cd"},{"id":138,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":8,"matrixBlockType":{"id":8,"fieldId":23,"fieldLayoutId":2455,"name":"Quote","handle":"quote","sortOrder":5,"hasFieldErrors":false,"uid":"3cdc35ec-7f4c-466b-9d6e-c2b895254797"},"groupName":"Pullouts","context":"global","groupSortOrder":3,"sortOrder":1,"uid":"24f3d281-3fc1-4c78-b8d3-539fa956bc4b"},{"id":139,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":16,"matrixBlockType":{"id":16,"fieldId":23,"fieldLayoutId":2456,"name":"Pullout Sideblock","handle":"pulloutSideblock","sortOrder":6,"hasFieldErrors":false,"uid":"d835eacf-e259-4948-841f-cfffa825fb47"},"groupName":"Pullouts","context":"global","groupSortOrder":3,"sortOrder":2,"uid":"889350bb-e993-4420-a60b-f1d16705c7e6"},{"id":140,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":13,"matrixBlockType":{"id":13,"fieldId":23,"fieldLayoutId":2462,"name":"Images","handle":"images","sortOrder":9,"hasFieldErrors":false,"uid":"19c3d00f-3bd4-4a8c-bcaf-f9ef2e5fd0a0"},"groupName":"Media","context":"global","groupSortOrder":4,"sortOrder":1,"uid":"a08d2967-4885-44ca-b21f-46ab6cbc137a"},{"id":141,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":15,"matrixBlockType":{"id":15,"fieldId":23,"fieldLayoutId":2467,"name":"Embedded Video","handle":"embeddedVideo","sortOrder":14,"hasFieldErrors":false,"uid":"0b9e0709-357b-4548-b51e-755649fc0bc5"},"groupName":"Media","context":"global","groupSortOrder":4,"sortOrder":2,"uid":"7146e600-c65c-49e2-896d-16bfc5125037"},{"id":142,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":11,"matrixBlockType":{"id":11,"fieldId":23,"fieldLayoutId":2465,"name":"Article Preview(s)","handle":"articlePreviews","sortOrder":12,"hasFieldErrors":false,"uid":"5fbb6000-dc56-4154-ae06-4aaa878069bf"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":1,"uid":"0699caf5-ba6c-4e7a-9f85-6f18eb07a544"},{"id":143,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":20,"matrixBlockType":{"id":20,"fieldId":23,"fieldLayoutId":2466,"name":"Category Preview","handle":"categoryPreview","sortOrder":13,"hasFieldErrors":false,"uid":"53704e37-3ddf-42d8-b9d2-ff0908471c1d"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":2,"uid":"4b8d72ab-8590-431f-be69-ce56169bce25"},{"id":144,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":19,"matrixBlockType":{"id":19,"fieldId":23,"fieldLayoutId":2468,"name":"File Preview(s)","handle":"filePreviews","sortOrder":15,"hasFieldErrors":false,"uid":"aa132f55-f5fd-4283-bd1a-61e7ef7dfaf2"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":3,"uid":"f290be83-8632-4e63-8289-ca8694c61e8d"},{"id":145,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":12,"matrixBlockType":{"id":12,"fieldId":23,"fieldLayoutId":2464,"name":"Product Preview(s)","handle":"productPreviews","sortOrder":11,"hasFieldErrors":false,"uid":"872872c6-22d0-426c-8228-8175e00fd055"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":4,"uid":"2a74c372-0e0f-4c45-9c03-1322e7209305"}]},"context":"global","versioned":false,"nestedSettingsHandles":[]}) };</script>

...so that's clearly loading all that JS again and again (and if I watch the memory for this page, it climbs and climbs until the browser basically dies...)

So....why does this trigger cause all that to come back, but not a normal htmx post/get scenario, I guess...?

bencroker commented 1 month ago

It looks like it may have to do with how you’re registering the asset bundle. Sprig requests in the control panel are considered CP requests, so one solution might be too only register it for non action requests.

if (Craft::$app->getRequest()->getIsCpRequest() && !Craft::$app->getRequest()->getIsActionRequest()) {
    Craft::$app->getView()->registerAssetBundle(BridgeAsset::class);
}

Or you could be more specific and only register it on non Sprig requests.

use putyourlightson\sprig\base\Component;

if (Craft::$app->getRequest()->getIsCpRequest() && !Component::getIsRequest()) {
    Craft::$app->getView()->registerAssetBundle(BridgeAsset::class);
}
bossanova808 commented 1 month ago

I tried both of those options, and unfortunately the behaviour remains the same, the JS is reloaded with each refresh.

bencroker commented 1 month ago

What about when you strip the component down to its bare minimum? In these situations it's best to test with an empty component and gradually build back up from there to help identify where the issue lies.

bossanova808 commented 1 month ago

Even if the component in question is just the trigger and the word 'test' it reloads all the CP js when it refreshes.

I will dig in to it more this week, but I do notice that it's not actually just the toolbar's every 5s triggers - e.g. the initial search box here triggers a render of the results (only, no js loaded) - but the sprig enable 'Get Sales' button results in the same behaviour - all the CP is reloaded on that request too I now notice.

image

bencroker commented 1 month ago

Perhaps you’re still registering it somewhere else, possibly using craft.app.assetManager.publishedUrl?

bossanova808 commented 1 month ago

...but, I'm not actually registering 'it' anywhere - this is all the CP/addon js (e.g. tailwind_reset.js or axios.js or Campaign.js) - I don't explicitly refer to any of that ever. Indeed, the asset bundle I am registering (bridge.js) - registered as per above and definitely only there - is not even actually part of this reloaded js!

I guess I need to understand better - when would one expect the 'general' CP JS to all be reloaded, and when wouldn't one? E.g. if you try a basic component there (with current Craft 4), i.e. a component with a trigger and the word test, do you see a reload of the CP JS too?

I'm really struggling to see what I could be doing that would cause this. I haven't changed anything with this in a long time, and I'm also pretty confident this is new behaviour, as it really will bring a browser (locally) to its knees, and if a few of these are open on a live VPS server, then the whole server too, in reasonably short order - as it's basically an aggressive memory leak in effect, and I just don't think it's possible I've missed noticing this in the few years we've been doing things this same way, nor have we had the resulting ongoing performance issues.

We've definitely had some performance issues in recent weeks, but I can't narrow it down to a specific commit/craft upgrade or whatever, unfortunately, as it put me a little while to put it all together. But for sure with the toolbar disabled the issue goes away, so at least that's a workaround, and as I have said I have confirmed with browser tools that the memory for the tab goes up and up and up, and the network traffic browser <> server grows basically exponentially, if I leave the refreshing enabled.

I also notice on these pages if a job happens to be running, then there is this, too - a repeated job progress meter:

image

...which is also, definitely, new behaviour, and presumably a side effect of all this JS being reloaded. (That was first seen/reported to me around the first of this month).

The only reference to loading anything within a component is a basic image load. There are definitely no js tags, no asset bundles, etc within the components.

        <img id="indicator"
             class="progress-indicator progress-indicator-inline htmx-indicator filter-grey"
             src="{{ craft.app.assetManager.publishedUrl('@modules/bridge/assets/icons/puff.svg', true) }}"
             alt=""
        >

I seem to have a real knack for running in to weird issues. For now I am just resigned to disabling the toolbar and hoping that others see some sort of similar behaviour over time, and it gets fixed up along the way...

bencroker commented 1 month ago

You’re right, I was able to confirm that other plugins registering their asset bundles are causing this issue, which means that I’ve had to explicitly disable asset bundles from being registered in Sprig requests in Sprig Core 2.10.2 and 3.3.2. As mentioned in https://github.com/putyourlightson/craft-sprig/issues/383#issuecomment-2275163370, this was due to a recent change in Sprig 2.9.0 (released on the first of this month).

Please update and let me know if this solves the issue for you, and thanks for sticking with me!

bossanova808 commented 1 month ago

Thanks Ben - it's my daughter's birthday so I won't be able to try anything till tomorrow but will definitely report back.

bossanova808 commented 1 month ago

Ok, now we're cooking. So there is now just the one network request for each refresf of the component (as expected) and the JS is not being reloaded. So that's great and indeed looks solved. I can also see, leaving the window open for a longer time, that the memory usage settles and does not continue to rise.

Just to double check, though, in the raw response of the returned, refreshed component, there is still some JS being injected on the end of that...I presume that is necessary/correct, but thought it best to ask while we're looking at this, just to be sure. I've never really looked in detail at the raw responses before, so I don't know if this is normal or not - here's what I am seeing anyway:

<div s-swap-oob="beforeend:body" data-hx-swap-oob="beforeend:body" data-sprig-parsed><script>Sprig.components.push({"id":"component-lywjjg","siteId":"1","component":"","template":"bridge\/_sprig_components\/toolbar","variables":[],"action":null,"triggerRefreshSources":[]})</script></div><script>if (typeof Craft.MatrixInput !== "undefined") { Spoon.fieldmanipulator = new Spoon.FieldManipulator({"blockTypes":{"global":[{"id":129,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":14,"matrixBlockType":{"id":14,"fieldId":23,"fieldLayoutId":2451,"name":"Page Title","handle":"pageTitle","sortOrder":1,"hasFieldErrors":false,"uid":"0251ce53-74ba-4a07-b0a5-19c93067624b"},"groupName":"Headers","context":"global","groupSortOrder":1,"sortOrder":1,"uid":"9c69c54e-4929-47dd-b151-8379676ce432"},{"id":130,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":3,"matrixBlockType":{"id":3,"fieldId":23,"fieldLayoutId":2452,"name":"Header","handle":"header","sortOrder":2,"hasFieldErrors":false,"uid":"c399a538-15b5-4e68-b2c2-d6b9ad774ff7"},"groupName":"Headers","context":"global","groupSortOrder":1,"sortOrder":2,"uid":"0fff4007-d922-4176-99a9-e31b6513f427"},{"id":131,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":4,"matrixBlockType":{"id":4,"fieldId":23,"fieldLayoutId":2453,"name":"WYSIWYG Text Block","handle":"wysiwyg","sortOrder":3,"hasFieldErrors":false,"uid":"45e85d64-dee8-4c78-bee9-a0c6dfa45879"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":1,"uid":"639c5067-5be7-4724-9cff-faaf9ea515c9"},{"id":132,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":17,"matrixBlockType":{"id":17,"fieldId":23,"fieldLayoutId":2454,"name":"WYSIWYG Fixed Columns","handle":"wysiwygFixedColumns","sortOrder":4,"hasFieldErrors":false,"uid":"0e43f288-1697-4396-9460-a6d271f49632"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":2,"uid":"3518686d-69d6-4a8a-830d-eae7648ce4d2"},{"id":133,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":9,"matrixBlockType":{"id":9,"fieldId":23,"fieldLayoutId":2458,"name":"Feature List","handle":"featureList","sortOrder":7,"hasFieldErrors":false,"uid":"f94d14ff-f7e7-4b9b-b573-cf7a439828eb"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":3,"uid":"70a66cc9-833a-40c3-9fd0-57883ccd2680"},{"id":134,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":10,"matrixBlockType":{"id":10,"fieldId":23,"fieldLayoutId":2460,"name":"Accordion","handle":"accordion","sortOrder":8,"hasFieldErrors":false,"uid":"50693fd7-b114-4f61-9bcd-8319f2be2ae6"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":4,"uid":"a5ab594d-da22-4301-a2ec-b77950105328"},{"id":135,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":18,"matrixBlockType":{"id":18,"fieldId":23,"fieldLayoutId":2463,"name":"Image and Text","handle":"imageAndText","sortOrder":10,"hasFieldErrors":false,"uid":"925a0b07-8517-4f7d-b69d-8cefe49e8b4b"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":5,"uid":"a3a9cebe-7515-4775-9f86-dcb1448956c2"},{"id":136,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":21,"matrixBlockType":{"id":21,"fieldId":23,"fieldLayoutId":2469,"name":"Special","handle":"special","sortOrder":16,"hasFieldErrors":false,"uid":"dc7f1887-cd7b-40e2-8d97-86bc74be7462"},"groupName":"Content","context":"global","groupSortOrder":2,"sortOrder":6,"uid":"a6f4e922-b4d1-4127-92e7-979a4ea228cd"},{"id":138,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":8,"matrixBlockType":{"id":8,"fieldId":23,"fieldLayoutId":2455,"name":"Quote","handle":"quote","sortOrder":5,"hasFieldErrors":false,"uid":"3cdc35ec-7f4c-466b-9d6e-c2b895254797"},"groupName":"Pullouts","context":"global","groupSortOrder":3,"sortOrder":1,"uid":"24f3d281-3fc1-4c78-b8d3-539fa956bc4b"},{"id":139,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":16,"matrixBlockType":{"id":16,"fieldId":23,"fieldLayoutId":2456,"name":"Pullout Sideblock","handle":"pulloutSideblock","sortOrder":6,"hasFieldErrors":false,"uid":"d835eacf-e259-4948-841f-cfffa825fb47"},"groupName":"Pullouts","context":"global","groupSortOrder":3,"sortOrder":2,"uid":"889350bb-e993-4420-a60b-f1d16705c7e6"},{"id":140,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":13,"matrixBlockType":{"id":13,"fieldId":23,"fieldLayoutId":2462,"name":"Images","handle":"images","sortOrder":9,"hasFieldErrors":false,"uid":"19c3d00f-3bd4-4a8c-bcaf-f9ef2e5fd0a0"},"groupName":"Media","context":"global","groupSortOrder":4,"sortOrder":1,"uid":"a08d2967-4885-44ca-b21f-46ab6cbc137a"},{"id":141,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":15,"matrixBlockType":{"id":15,"fieldId":23,"fieldLayoutId":2467,"name":"Embedded Video","handle":"embeddedVideo","sortOrder":14,"hasFieldErrors":false,"uid":"0b9e0709-357b-4548-b51e-755649fc0bc5"},"groupName":"Media","context":"global","groupSortOrder":4,"sortOrder":2,"uid":"7146e600-c65c-49e2-896d-16bfc5125037"},{"id":142,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":11,"matrixBlockType":{"id":11,"fieldId":23,"fieldLayoutId":2465,"name":"Article Preview(s)","handle":"articlePreviews","sortOrder":12,"hasFieldErrors":false,"uid":"5fbb6000-dc56-4154-ae06-4aaa878069bf"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":1,"uid":"0699caf5-ba6c-4e7a-9f85-6f18eb07a544"},{"id":143,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":20,"matrixBlockType":{"id":20,"fieldId":23,"fieldLayoutId":2466,"name":"Category Preview","handle":"categoryPreview","sortOrder":13,"hasFieldErrors":false,"uid":"53704e37-3ddf-42d8-b9d2-ff0908471c1d"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":2,"uid":"4b8d72ab-8590-431f-be69-ce56169bce25"},{"id":144,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":19,"matrixBlockType":{"id":19,"fieldId":23,"fieldLayoutId":2468,"name":"File Preview(s)","handle":"filePreviews","sortOrder":15,"hasFieldErrors":false,"uid":"aa132f55-f5fd-4283-bd1a-61e7ef7dfaf2"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":3,"uid":"f290be83-8632-4e63-8289-ca8694c61e8d"},{"id":145,"fieldId":23,"field":null,"fieldLayoutId":null,"fieldLayoutModel":null,"fieldHandle":"blocks","matrixBlockTypeId":12,"matrixBlockType":{"id":12,"fieldId":23,"fieldLayoutId":2464,"name":"Product Preview(s)","handle":"productPreviews","sortOrder":11,"hasFieldErrors":false,"uid":"872872c6-22d0-426c-8228-8175e00fd055"},"groupName":"Previews","context":"global","groupSortOrder":5,"sortOrder":4,"uid":"2a74c372-0e0f-4c45-9c03-1322e7209305"}]},"context":"global","versioned":false,"nestedSettingsHandles":[]}) };</script>

(Re: sticking with it - Ben, you are an absolutely solid gold member of the Craft community and your efforts - e.g. Sprig itself, which is, ludicrously, free - are so far above and beyond what's reasonable or expected. I am definitely the one that should be thanking you...I am quite sure my lack of deeper understanding of this stuff makes it much harder than it should be to work things out, when I report them, and for that I am very sorry (web dev is just such a small part of what I actually do!). In any case, please be assured your support and patience is always very much appreciated and if ever leaks out that I seem frustrated, it's most definitely not with you, but with the problems at hand...and 99% of those are doubtless of my own making!).

bencroker commented 1 month ago

Excellent, that does now appear solved!

The extra element you’re seeing is the (to be documented) feature released in 2.11.0 and 3.3.0 that logs component configurations to a Sprig variable in the browser console when devMode is enabled. This allows you to see what components have been loaded on the current request by running Sprig.components in the browser console. I’ll likely be building this out in coming versions and am open to ideas, in case any come up!