magento2 icon indicating copy to clipboard operation
magento2 copied to clipboard

jQuery Widget or UiComponent mixin don't loading or loading randomized

Open denis-g opened this issue 4 years ago • 31 comments

Maybe need additional fixes on #25587 request.

Preconditions (*)

  1. Magento 2.4.x
  2. Google Chrome 92 (cache disabled on devtools)

Steps to reproduce (*)

  1. Fresh install m2 2.4.4 (also problem with all 2.4.x)
  2. Dev mode on
  3. Cache settings (all on, except for layout, block_html, full_page)
  4. Create new theme (luma parent)

theme structure

requirejs-config.js

var config = {
    map: {
        '*': {
            myWidget: 'Magento_Theme/js/my-widget'
        }
   },
   config: {
        mixins: {
            'Magento_Theme/js/my-widget': {
                'Magento_Theme/js/my-widget-mixin': true
            }
        }
    }
};

my-widget.js

define([
    'jquery',
    'jquery-ui-modules/widget'
], function ($) {
    'use strict';

    $.widget('mage.myWidget', {
        options: {
            color: 'red'
        },
        _create: function () {
            $('body').css('background-color', this.options.color);
        }
    });

    return $.mage.myWidget;
});

my-widget-mixin.js

define([
    'jquery',
    'jquery-ui-modules/widget'
], function ($) {
    'use strict';

    return function (widget) {
        $.widget('mage.myWidget', widget, {
            options: {
                color: 'green'
            }
        });

        return $.mage.myWidget;
    }
});

Expected result (*)

Mixin load and background is GREEN 🟢

Actual result (*)

Results depend on cache, opened devtools.

  1. Init widget on js file – mixin don't load (or randomized loading, also loading when devtools opened) Background is RED 🔴 or GREEN 🟢
define([
    'jquery',
    'myWidget'
], function ($, myWidget) {
    'use strict';

    myWidget();
});
  1. Init widget on phtml file – mixin don't load (or randomized loading, also loading when devtools opened) Background is RED 🔴 or GREEN 🟢
require([
    'jquery',
    'myWidget'
], function ($, myWidget) {
    'use strict';

    myWidget();
});
  1. Init widget on js file (with mage) – mixin load (or randomized don't loading) Background is GREEN 🟢 or RED 🔴
require([
    'jquery',
    'mage/mage'
], function ($) {
    'use strict';

    $('body').mage('myWidget', {});
});
  1. Init widget on js file (without alias) – mixin load (or randomized don't loading when devtools opened) Background is GREEN 🟢 or RED 🔴
define([
    'jquery',
    'Magento_Theme/js/my-widget'
], function ($, myWidget) {
    'use strict';

    myWidget();
});
  1. ALSO, when widget don't load and when call widget again (click event, etc) – mixin load Background is RED 🔴, after event is GREEN 🟢
require([
    'jquery',
    'myWidget'
], function ($, myWidget) {
    'use strict';

    myWidget();

    $('.action.mixin').on('click', function () {
        myWidget();
    });
});
  1. Init widget on phtml file with data-mage-initmixin load (works perfectly, without background flashing and mixin preloading) Background is GREEN 🟢
<div data-mage-init='{"myWidget": {}}'></div>
  1. Init widget on phtml file with js x-magento-initmixin load (works perfectly, without background flashing and mixin preloading) Background is GREEN 🟢
<script type="text/x-magento-init">
    {
        "*": {
            "myWidget": {}
        }
    }
</script>
  1. Init widget on js file (with mixins!) – mixin load (works perfectly, without background flashing and mixin preloading) Background is GREEN 🟢
define([
    'jquery',
    'mixins!myWidget'
], function ($, myWidget) {
    'use strict';

    myWidget();
});

Please provide Severity assessment for the Issue as Reporter. This information will help during Confirmation and Issue triage processes.

  • [ ] Severity: S0 - Affects critical data or functionality and leaves users without workaround.
  • [x] Severity: S1 - Affects critical data or functionality and forces users to employ a workaround.
  • [ ] Severity: S2 - Affects non-critical data or functionality and forces users to employ a workaround.
  • [ ] Severity: S3 - Affects non-critical data or functionality and does not force users to employ a workaround.
  • [ ] Severity: S4 - Affects aesthetics, professional look and feel, “quality” or “usability”.

denis-g avatar Jul 26 '21 16:07 denis-g

Hi @denis-g. Thank you for your report. To help us process this issue please make sure that you provided the following information:

  • Summary of the issue
  • Information on your environment
  • Steps to reproduce
  • Expected and actual results

Please make sure that the issue is reproducible on the vanilla Magento instance following Steps to reproduce. To deploy vanilla Magento instance on our environment, please, add a comment to the issue:

@magento give me 2.4-develop instance - upcoming 2.4.x release

For more details, please, review the Magento Contributor Assistant documentation.

Please, add a comment to assign the issue: @magento I am working on this


:warning: According to the Magento Contribution requirements, all issues must go through the Community Contributions Triage process. Community Contributions Triage is a public meeting.

:clock10: You can find the schedule on the Magento Community Calendar page.

:telephone_receiver: The triage of issues happens in the queue order. If you want to speed up the delivery of your contribution, please join the Community Contributions Triage session to discuss the appropriate ticket.

:movie_camera: You can find the recording of the previous Community Contributions Triage on the Magento Youtube Channel

:pencil2: Feel free to post questions/proposals/feedback related to the Community Contributions Triage process to the corresponding Slack Channel

m2-assistant[bot] avatar Jul 26 '21 16:07 m2-assistant[bot]

+1. We also randomly having similar issue. I think it’s not related to random file loading, as we’re using file bundling and both widget and mixin are inside single bundle. Almost all the time at first page view mixin doesn’t apply, but after page reload - it applies

ihor-sviziev avatar Jul 26 '21 18:07 ihor-sviziev

@ihor-sviziev yep. On bundle, merged, or single it doesn't matter. Core problem on matching mixin with widget/component and random apply.

Also similar issue #22338

denis-g avatar Jul 27 '21 08:07 denis-g

good call! Thanks you denis for some use-cases cc: tag @krzksz here maybe he will give us more information

mrtuvn avatar Jul 27 '21 16:07 mrtuvn

The reproduction path looks quite clear and I would start by attaching a logger/debugger in https://github.com/magento/magento2/blob/2.4-develop/lib/web/mage/requirejs/mixins.js#L161 to see if mixins are not loaded because they are not seen by the plugin or the whole mechanism is completely ignored.

krzksz avatar Jul 27 '21 16:07 krzksz

Hi @engcom-Delta. Thank you for working on this issue. In order to make sure that issue has enough information and ready for development, please read and check the following instruction: :point_down:

  • [ ] 1. Verify that issue has all the required information. (Preconditions, Steps to reproduce, Expected result, Actual result).

    DetailsIf the issue has a valid description, the label Issue: Format is valid will be added to the issue automatically. Please, edit issue description if needed, until label Issue: Format is valid appears.

  • [ ] 2. Verify that issue has a meaningful description and provides enough information to reproduce the issue. If the report is valid, add Issue: Clear Description label to the issue by yourself.

  • [ ] 3. Add Component: XXXXX label(s) to the ticket, indicating the components it may be related to.

  • [ ] 4. Verify that the issue is reproducible on 2.4-develop branch

    Details- Add the comment @magento give me 2.4-develop instance to deploy test instance on Magento infrastructure.
    - If the issue is reproducible on 2.4-develop branch, please, add the label Reproduced on 2.4.x.
    - If the issue is not reproducible, add your comment that issue is not reproducible and close the issue and stop verification process here!

  • [ ] 5. Add label Issue: Confirmed once verification is complete.

  • [ ] 6. Make sure that automatic system confirms that report has been added to the backlog.

m2-assistant[bot] avatar Sep 01 '21 06:09 m2-assistant[bot]

FYI we just tried to debug this issue - that's definitely a very random issue, and it looks like it is related to async js execution/script loading. When the issue reproducing, the following core return false because in the RequireJS config, we don't have all maps and mixins yet. https://github.com/magento/magento2/blob/97f0a1f34efc7c40c97014800cc876e9aedcdc0f/lib/web/mage/requirejs/mixins.js#L161

It looks like the issue coming from using wrapping

(function() {
 ... requirejs-config.js content here
require.config(config);
})();

Or maybe it is related to require.config that probably works in an async way.

https://github.com/magento/magento2/blob/7c6b6365a3c099509d6f6e6c306cb1821910aab0/lib/internal/Magento/Framework/RequireJs/Config.php#L79-L85

So far, fixing this issue won't be really easy, so I stopped the research.

BTW, if you'll try setting a breakpoint to that line, or even adding console.log - the issue won't reproduce OR will reproduce very-very rarely that makes debugging really hard.

Summary: the issue happening because of the missing the mixins! prefix. This prefix isn't getting added because of not fully loaded RequireJS config.

I even thought it might be related to https://github.com/magento/magento2/blob/7c6b6365a3c099509d6f6e6c306cb1821910aab0/lib/web/mage/bootstrap.js#L21

And, issue reproducing both with enabled and disabled

PS: @krzksz, I think now is your turn. We need your knowledge and skills to resolve such hard frontend issues.

ihor-sviziev avatar Sep 01 '21 07:09 ihor-sviziev

Can we have or create new option allow developer determine when and how script defer or async ?

Example if no specific we use async and if we specific

<script type="text/x-magento-init" defer>
//Code
</script>

Current magento only allow add defer tag script via xml. I think somewhere in the code collect and add this attribute. Can we have same approach for script in js or phtml ?

mrtuvn avatar Sep 01 '21 07:09 mrtuvn

@mrtuvn, as you see from the description, the case with <script type="text/x-magento-init">...</script> works fine

ihor-sviziev avatar Sep 01 '21 07:09 ihor-sviziev

https://github.com/magento/magento2/blob/2.4-develop/lib/web/requirejs/require.js#L1881 <= default we always have async true here. So basically all script loaded async will run as soon as it downloaded and may block parse html

mrtuvn avatar Sep 01 '21 07:09 mrtuvn

@mrtuvn, I'm pretty sure the issue isn't simple at all.

ihor-sviziev avatar Sep 01 '21 07:09 ihor-sviziev

Hi @engcom-Lima. Thank you for working on this issue. In order to make sure that issue has enough information and ready for development, please read and check the following instruction: :point_down:

  • [ ] 1. Verify that issue has all the required information. (Preconditions, Steps to reproduce, Expected result, Actual result).

    DetailsIf the issue has a valid description, the label Issue: Format is valid will be added to the issue automatically. Please, edit issue description if needed, until label Issue: Format is valid appears.

  • [ ] 2. Verify that issue has a meaningful description and provides enough information to reproduce the issue. If the report is valid, add Issue: Clear Description label to the issue by yourself.

  • [ ] 3. Add Component: XXXXX label(s) to the ticket, indicating the components it may be related to.

  • [ ] 4. Verify that the issue is reproducible on 2.4-develop branch

    Details- Add the comment @magento give me 2.4-develop instance to deploy test instance on Magento infrastructure.
    - If the issue is reproducible on 2.4-develop branch, please, add the label Reproduced on 2.4.x.
    - If the issue is not reproducible, add your comment that issue is not reproducible and close the issue and stop verification process here!

  • [ ] 5. Add label Issue: Confirmed once verification is complete.

  • [ ] 6. Make sure that automatic system confirms that report has been added to the backlog.

m2-assistant[bot] avatar Sep 02 '21 11:09 m2-assistant[bot]

@denis-g Your workaround 8. saved my day, but probably this should have a completely fix for all.

tuyennn avatar Sep 13 '21 12:09 tuyennn

Hi @denis-g,

Thank you for reporting the issue with detailed description. Verified the issue on 2.4-develop and issue is reproducible.

Here is what I did to reproduce:

  1. As per reporter’s issue description creates new theme with parent luma. Created all files with provided code in newly created theme.
  2. Disabled Cache in Dev Tools.
  3. Tried with multiple scenarios as provided by the reporter in Actual Result section.

Issue: In first 5 scenarios, result appeared first to be loaded with background RED that means mixin didn’t load properly but after reloading the page background became GREEN. In last 3 scenarios, result appeared correct with GREEN background means mixin was loading properly in the first attempt itself.

So based on the above results, confirming the issue.

engcom-Lima avatar Sep 21 '21 12:09 engcom-Lima

:white_check_mark: Jira issue https://jira.corp.magento.com/browse/AC-1311 is successfully created for this GitHub issue.

github-jira-sync-bot avatar Sep 21 '21 12:09 github-jira-sync-bot

:white_check_mark: Confirmed by @engcom-Lima. Thank you for verifying the issue.
Issue Available: @engcom-Lima, You will be automatically unassigned. Contributors/Maintainers can claim this issue to continue. To reclaim and continue work, reassign the ticket to yourself.

m2-assistant[bot] avatar Sep 21 '21 12:09 m2-assistant[bot]

Can you please test following changes? as fixes may related for issue 2.4-develop...mrtuvn:requirejs-resolver-mixins-patch

Using your changes I made a module work. I noticed mixins form a marketplace module were never called and did not even show up in frontend. Came here after a google search.

Module (free): https://marketplace.magento.com/sparsh-magento-2-order-comments-extension.html I'm currently on Magento ver. 2.4.2-p1

This module has two mixins:

var config = {
config: {
    mixins: {
        'Magento_Checkout/js/action/place-order': {
            'Sparsh_OrderComments/js/order/place-order-mixin': true
        },
        'Magento_Checkout/js/action/set-payment-information': {
            'Sparsh_OrderComments/js/order/set-payment-information-mixin': true
        }
    }
}
};

With your changes to lib/web/mage/requirejs/resolver.js the mixins execute and the comment is saved to the order like expected, without your changes the comment is never saved to the order because the mixins will never execute.

Between each test I cleared the static files.

I have not yet tested if this change will affect anything else.

KM-HM avatar Dec 06 '21 16:12 KM-HM

Hi @denis-g, Maybe you can check if everything works as expected with changes from https://github.com/magento/magento2/compare/2.4-develop...mrtuvn:requirejs-resolver-mixins-patch ?

ihor-sviziev avatar Dec 06 '21 17:12 ihor-sviziev

Hi @ihor-sviziev, Hmm, I've tested clean theme and widget from 1st post on 2.4.1 (original resolver.js with patch and original resolver.js from 2.4.3 with patch, and file from patch), also tested on 2.4.3 (original resolver.js with patch, and file from patch) - and mixins did not apply.

On @Kemexyz mixin used a component. Is it probably a different func call there? 🤔 Or patch works with component only... Or something else affects.

Additional testing is needed. Maybe someone has a working result with a patch?

denis-g avatar Dec 07 '21 00:12 denis-g

@mrtuvn, could you create a PR, so we'll be able to run all tests on top of these changes?

ihor-sviziev avatar Dec 07 '21 15:12 ihor-sviziev

faced the same issue with unapplied mixins on storefront. the issue is reproducible when requirejs-config.js executing after mage/requirejs/mixins.js.

As mentioned previously, https://github.com/magento/magento2/blob/4c36116dcf878e127059d9be9566a119783583f2/lib/web/mage/requirejs/mixins.js#L139 can't find mixins due to empty requirejs config.

Seems like the issue introduced with this commit https://github.com/magento/magento2/commit/540b1340275b001aca44ce3d889a039614167a8e

After this changes, mixins use custom context of require, configured on first load of mixins.js using config from default requirejs context. As result - if mixins.js loaded before requirejs-config empty config will be used to build custom context. This custom "empty" context will be used as closure during all next mixins applying

https://github.com/magento/magento2/blob/4c36116dcf878e127059d9be9566a119783583f2/lib/web/mage/requirejs/mixins.js#L10-L28

One of possible solutions - change sequence of assets in head (swap requirejs-config and mixins assets).

https://github.com/magento/magento2/blob/4c36116dcf878e127059d9be9566a119783583f2/app/code/Magento/RequireJs/Block/Html/Head/Config.php#L126-L137

Moreover, looks like this files should be swapped initially, because inserting using correct sequence, but mixed due to the same $after value.

        $requireJsConfig = $this->fileManager->createRequireJsConfigAsset();
        $assetCollection->insert(
            $requireJsConfig->getFilePath(),
            $requireJsConfig,
            $after
        );
        $requireJsMixinsConfig = $this->fileManager->createRequireJsMixinsAsset();
        $assetCollection->insert(
            $requireJsMixinsConfig->getFilePath(),
            $requireJsMixinsConfig,
            $requireJsConfig->getFilePath() // <------  insert after $requireJsConfig asset
        );

isxam avatar Feb 14 '22 09:02 isxam

The issue is reproducible only for target packages with changed path (using require map config or path for example). As workaround, can be added two declaration of mixin for short name and path.

Declaration of mixins

var config = {
   config: {
        mixins: {
            'myWidget': {
                'Magento_Theme/js/my-widget-mixin': true
            }
            'Magento_Theme/js/my-widget': {
                'Magento_Theme/js/my-widget-mixin': true
            }
        }
    }
};

Using

define([
    'jquery',
    'myWidget'
], function ($, myWidget) {
    'use strict';

    myWidget();
});

Short declaration will be used for processNames to add mixins! prefix to target package, the second one with fully path will be used during applying mixins.

isxam avatar Feb 15 '22 10:02 isxam

@ihor-sviziev @mrtuvn Is there any update on this?

tuyennn avatar Apr 21 '24 05:04 tuyennn

@tuyennn sorry, I don't have any updates

ihor-sviziev avatar Apr 22 '24 11:04 ihor-sviziev

@ihor-sviziev @mrtuvn @isxam do we have a patch or workaround for this issue? I tried some of the solutions isxam provided such as specifying $requireJsConfig->getFilePath() as the $after for the mixins assets or two declaration of mixins for the short name and path but neither worked.

In our case, our custom mixins (which just override a widget function) were loading fine until we noticed a style tag in the HTML Head (through Magento's Scripts and Style Sheets CMS block) that referenced a non-existent stylesheet thus generating a 404. After removing that style tag the custom mixins stopped loading. I can only guess that the 404 was generating enough delay for the requirejs-config to be properly loaded and the mixins file to get its context, and without the 404 delay mixins do not get the requrejs-config.

oaguilar5 avatar May 16 '24 16:05 oaguilar5

I have an instance on 2.4.7-p2 and this is happening with customer-data-mixin (and possibly others). Edit: I also have a patch to address load order so config is loaded before mixin, so it's not that. Load order: requirejs/require.js -> requirejs-config.js -> requirejs/mixins.js

How I am replicated it: I am requiring customer-data which SHOULD apply the customer-data-mixin from Magento_Persistent before firing the require function off.

require(['jquery', 'mage/url', 'Magento_Customer/js/customer-data'], function(jQuery, url) {
    url.setBaseUrl('https\u003A\u002F\u002Fexample.com\u002F');
    jQuery.ajax({
        url: url.build('reclaim/checkout/reload'),
        method: 'POST',
        data: {}
    });
});

I am dumping requirejs contexts out right before my error is occurring, and I DO see the mixin defined and accessible as an object with methods available. requirejs.s.contexts._.defined['mixins!Magento_Customer/js/customer-data']

However the storage property the mixin instantiates via call to originalFn customer-data is undefined.

I have to debug further, but seems like the mixin is running after it is defined to requirejs and requirejs fires function off before mixin actually is parsed?

AndresInSpace avatar Aug 22 '24 21:08 AndresInSpace

Upon further debugging it appears any require call in the document can happen before the require mixin call, but after the define call due to setTimeout in requirejs allowing document to then be parsed.

requirejs/mixins.js was loaded and being defined document parsed and require calls fired from requirejs/require.js requirejs/mixins.js require fired and now instantiating

I am looking into a fix.

FIX BELOW: (edit: please see the actual PR suggested, the below is a summary there are additional changes in PR)

  1. patch your requirejs order so config loads BEFORE mixins due to $after var see https://github.com/magento/magento2/issues/33593#issuecomment-1038876652
diff --git a/vendor/magento/module-require-js/Block/Html/Head/Config.php b/vendor/magento/module-require-js/Block/Html/Head/Config.php
index [redacted] 100644
--- a/vendor/magento/module-require-js/Block/Html/Head/Config.php
+++ b/vendor/magento/module-require-js/Block/Html/Head/Config.php
@@ -123,18 +123,18 @@ class Config extends \Magento\Framework\View\Element\AbstractBlock
                 $after = $staticAsset->getFilePath();
             }
         }
-        $requireJsConfig = $this->fileManager->createRequireJsConfigAsset();
-        $assetCollection->insert(
-            $requireJsConfig->getFilePath(),
-            $requireJsConfig,
-            $after
-        );
         $requireJsMixinsConfig = $this->fileManager->createRequireJsMixinsAsset();
         $assetCollection->insert(
             $requireJsMixinsConfig->getFilePath(),
             $requireJsMixinsConfig,
             $after
         );
+        $requireJsConfig = $this->fileManager->createRequireJsConfigAsset();
+        $assetCollection->insert(
+            $requireJsConfig->getFilePath(),
+            $requireJsConfig,
+            $after
+        );
         return parent::_prepareLayout();
     }
 }
  1. removing the timeout nexTick from https://github.com/magento/magento2/blob/2.4-develop/lib/web/requirejs/require.js#L1449 since we are going to want the mixins.js to replace the require function - I believe we can safely ommit this timeout to stop the thread from being freed and parsing DOM. I have not tested with bundledjs (see mixins.js) context.require https://github.com/magento/magento2/blob/2.4-develop/lib/web/mage/requirejs/mixins.js#L219
                    //Mark all the dependencies as needing to be loaded.
                    // context.nextTick(function () {
                        //Some defines could have been added since the
                        //require call, collect them.
                        intakeDefines();

                        requireMod = getModule(makeModuleMap(null, relMap));

                        //Store if map config should be applied to this require
                        //call for dependencies.
                        requireMod.skipMap = options.skipMap;

                        requireMod.init(deps, callback, errback, {
                            enabled: true
                        });

                        checkLoaded();
                    // });
  1. additionally we need to move the require call that sets jquery no conflict out of the generated requirejs-config (should only be config objects) and move it into the mixins so that a require call is not made before requirejs/mixins.js applies its overrides to requirejs.

https://github.com/magento/magento2/blob/2.4-develop/app/code/Magento/Theme/view/base/requirejs-config.js#L87 Just add it to bottom of requirejs/mixins.js inside require(['mixins'], function(mixins){... here}

    require(['jquery'], function ($) {
        'use strict';
    
        $.noConflict();
    });
    
}); // closing tag for require(['mixins'], functions(mixins) { ....

This also ensures the jquery mixin for security captcha is properly applied before jquery is called in context (before DOM requires call jquery and mixin is not applied). https://github.com/magento/security-package/blob/develop/ReCaptchaWebapiUi/view/frontend/requirejs-config.js#L10

Do I get a coffee? :) lol

AndresInSpace avatar Aug 22 '24 22:08 AndresInSpace

@denis-g if you have time can you please apply my patch and run your tests to confirm all are resolved.

AndresInSpace avatar Aug 24 '24 03:08 AndresInSpace

@ihor-sviziev @mrtuvn @isxam do we have a patch or workaround for this issue? I tried some of the solutions isxam provided such as specifying $requireJsConfig->getFilePath() as the $after for the mixins assets or two declaration of mixins for the short name and path but neither worked.

In our case, our custom mixins (which just override a widget function) were loading fine until we noticed a style tag in the HTML Head (through Magento's Scripts and Style Sheets CMS block) that referenced a non-existent stylesheet thus generating a 404. After removing that style tag the custom mixins stopped loading. I can only guess that the 404 was generating enough delay for the requirejs-config to be properly loaded and the mixins file to get its context, and without the 404 delay mixins do not get the requrejs-config.

@oaguilar5 please try my patch It sounds like your file error was keeping the thread busy enough to stop it from processing require calls in DOM before the mixins.js loaded and replaced the require function. (Css is blocking until it loads or errors out, then thread continues)

AndresInSpace avatar Aug 26 '24 21:08 AndresInSpace

@AndresInSpace Here are the 2 file patches we have made for 2.4.7

Checkout-email-fix.patch Moving-jquery-to-mixin-in-lib.patch

And then we overwrote the lib files in:

Screenshot 2024-08-27 at 10 32 45

We're hoping that this resolves the issue where the email form isn't showing in the checkout. However, we are unable to replicate it reliably - even following peoples explanations using incog browser, new browser etc. It is very hard to replicate. I see you mention processing causing busy threads - is there a script we could put on to that would cause the issue to happen every time?

andy-aware avatar Aug 27 '24 09:08 andy-aware