Load requireJS module inline the HTML body?

2019-06-15 03:33发布

问题:

I am integrating RequireJS in a CMS so I placed this on the bottom of my page template:

<html>
<body>
  {Placeholder1}
  <script src="scripts/require.js" data-main="scripts/main"></script>
  {Placeholder2}
</body>
</html>

Then on each page, I would like to create a function that leverages RequireJS. So I tried placing this on the bottom of the page:

<html>
<body>
    <h1>Home</h1>
    <div class="slider">Slider content</div>

    <script src="scripts/require.js" data-main="scripts/main"></script>

    <script type="text/javascript">
      require([
        'jquery',
        'utils',
        'slider'
      ], function ($, utils, slider) {
        slider.start();
      });
    </script>
</body>
</html>

But I am getting 404's on jquery, utils and slider js files. It seems like it is not reading my main.js configs that I have:

require.config({
    paths: {
        jquery: 'libs/jquery-1.8.1.min',
        utils: 'libs/utils',
        slider: 'libs/jquery.slider.min'
    },
    shim: {
        slider: ['jquery']
    }
});

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

I tried loading RequireJS and main in the page head, but got inconsistent results that way. Sometimes jquery, utils and slider would be loaded in time and other times not. It is as if the inline "require" on the bottom of the page is not aware of the main RequireJS on page or the dependency rules, but my breakpoint hits in main.js so I know it is being called. Is it because main.js gets loaded asynchronously but my inline "require" block on the bottom of the page is loaded on page render? How do I get around this?

I have used RequireJS successfully before but without a CMS. I always used "define" and had modules always called asychronously, but never had to call RequireJS function inline like this. Any ideas on the correct way to do this?

回答1:

The important thing here is that the config options are set before any modules are requested. As you have rightly identified, there are race conditions that mean the config options in your main.js aren't loaded in time. Simplest way round it would be to put the config options inline before the require.js script is loaded.

<script>
var require = {
    baseUrl: <?= $someVar ?>,
    paths: {
        // etc
    }
}
</script>
<script src="scripts/require.js" data-main="scripts/main"></script>

Further down the page:

<script>
    require([
        'jquery',
        'utils',
        'slider'
      ], function ($, utils, slider) {
        slider.start();
      });
</script>

See also How does RequireJS work with multiple pages and partial views?



回答2:

It seems like what is happening is that the main.js is being loaded asynchronously while the inline require is called right away. This is why there are inconsistent results. The solution is to NOT use the data-main attribute and call the main.js file via script tag underneath the require.js script tag.

You can still determine the baseUrl from the loaded main.js file by doing this in there:

//DETERMINE BASE URL FROM CURRENT SCRIPT PATH
var scripts = document.getElementsByTagName("script");
var src = scripts[scripts.length-1].src;
var baseUrl = src.substring(src.indexOf(document.location.pathname), src.lastIndexOf('/'));

//CONFIGURE LIBRARIES AND DEPENDENCIES VIA REQUIREJS
require.config({
    baseUrl: baseUrl,
....