RequireJS configuration ignored by inline require

2019-02-23 18:59发布

问题:

I'm using requireJS and I'd like to access a specific module from it. Unfortunately I always receive a 404 message that the module wasn't found.

I include my js file where the path configuration is located like this:

<script src="/js/shop2/springen/vendor/require.min.js" data-main="/js/shop2/springen/app" async></script>

My app.js looks like this:

define('jquery', [], function() {
    return jQuery;
});

requirejs.config({
    baseUrl: '/js/shop2/springen/',
    paths: {
        'lodash': 'vendor/lodash.min',  
        'Functions': 'app/modules/functions',
        'Search': 'app/modules/search',
        'Comparison': 'app/modules/comparison',
        'Globals': 'app/globals',
        'Init': 'app/init',
        ...
    }
});

// globals get loaded first and are available to all subordered scripts
require(['Globals', 'lodash'], function () {

    $(document).ready(function() {

        if ($('#comparison').length) {

            require(['Comparison'], function (Comparison) {
                Comparison.init();
            });

        } else {

            require(['Init']);

        }

    });

});

Now my problem is that I need to setup my search module inline as I have to generate translations on the server side and initialize it with this:

<script type="text/javascript">
$(document).ready(function(){
    require(['Search'], function () {
        $('#q').shopIncrementalSearch({
            resultsDiv: $('#lifesearch'),
            defaultTitle: 'drücken Sie die Eingabetaste, um',
            defaultText: 'Alle Ergebnisse anzeigen',
            searchingText: 'Suche ...',
            dataUrl: 'http://SRV-CACHE01',
            language: 'de',
            countryId: 1,
            portalId: 22,
            isErpPortal: false,
            sectorId: null
        });
    });
});
</script>

Unfortunately I get an error message saying the file wasn't found. Shouldn't I be able to access the requireJS modules when the DOM's ready? Curiously the path of all loaded modules (some modules don't get loaded due to the JS error I guess) are set correctly. Just the Search module looks like this: /js/shop2/springen/Search.js 404 (Not Found) Any suggestions what I'm doing wrong?

EDIT

I've logged following in front of my inline javascript: console.log(typeof require); and it returns me function so require is loaded but the paths aren't set.. Why?

回答1:

What you are doing cannot work reliably because you are loading your RequireJS configuration asynchronously and you have synchronous code that depends on this configuration.

Here's what happens:

  1. This line:

    <script src="/js/shop2/springen/vendor/require.min.js" data-main="/js/shop2/springen/app" async></script>
    

    causes RequireJS to be loaded and causes RequireJS to schedule an asynchronous load for your /js/shop2/springen/app module.

    The async attribute on this element moreover makes it so that the browser is authorized to load RequireJS asynchronously. If it does load RequireJS asynchronously, this compounds the problem you are experiencing because by the time your other <script> element is run, there's no telling whether RequireJS is loaded. It may or may not be loaded depending on a bunch of external factors. It boils down to luck. Removing it, however, is not the whole solution because the module you ask be loaded through data-main is still loaded asynchronously, no matter what.

  2. When this is executed:

    <script type="text/javascript">
      $(document).ready(function(){
        require(['Search'], function () {
          ...
        });
      });
    </script>
    

    there is no telling whether your main module has loaded or not, because (see above) it is loaded asynchronously. So RequireJS may indeed be loaded but it may not have yet been configured, because your configuration is located in a module which may or may not be loaded by the time this script is run. This is why typeof require would be a function but you'd get errors trying to load modules that depend on your configuration.

    $(document).ready does not help because the event which causes $(document).ready to fire can happen before RequireJS has loaded the main module.

If you cannot put the require(['Search']... code in your main module, what you could do is remove the call to requirejs.config from /js/shop2/springen/app, and then add a <script> element just before the one that loads RequireJS that does:

require = {
    baseUrl: '/js/shop2/springen/',
    paths: {
        'lodash': 'vendor/lodash.min',  
        ...
    }
});

Setting a require variable to a configuration before RequireJS is loaded tells RequireJS to use the value of this variable as its configuration.

And remember to remove that async attribute from the <script> that loads RequireJS.