Question

I'm currently using requirejs mostly due to its resource loader. I like the way it manages fallbacks.

My javascript app is not complex at all, just some jQuery UI widgets and other minor tweaks.

I didn't even know what the FOUC was until I started with requirejs. It is quite noticeable so at the moment I'm avoiding it with:

var protect_from_FOUC = function(element) {
    if(typeof element === 'string') {
        element = document.querySelector(element);
    }
    element.classList.add('ui-helper-hidden');
};

<div id="main" class="main_block" role="main">
<!-- a block affected by FOUC -->
</div>
<script>protect_from_FOUC('#main');</script>

and in my scripts:

require(['jquery', 'jquery-ui' /*, ...*/], function($) {

var recover_from_FOUC = function(element) {
    $(element).show({
        effect: 'blind',
        duration: 200
    }).removeClass('ui-helper-hidden');
};

$(document).ready(function() {

    // Themed buttons:
    $(':button, :submit, :reset, .button').button();
    // ... Some other similar changes
    recover_from_FOUC('#main');

});  // document.ready

});  // require

This is the best I have and all the online resources on the subject I've found recommend something along those lines.

My question is, considering that I'm talking about scripts that affect only the UI, Is requirejs worth it? As I said I would like to keep using its resource fallback system but the whole "FOUC patching stuff" seems counterproductive...

Every jQuery UI example includes the scripts in the head but everyone in the internet recommends including the scripts before closing the body or with an asynchronous loader. Is this advice only applicable to "non UI" scripts?

What would be the best in such cases?

Note that, even though close, this is not just another "How to avoid FOUC question".

EDIT: Adding the external files included in my page and my require.config:

<!-- This is in my head right below the meta tags and exactly in this order -->
<link rel="shortcut icon" href="images/favicon.ico"/>
<!-- Keep before the site css to allow overriding jquery's style -->
<link rel="stylesheet" href="style/lib/jquery-ui/ui-lightness/jquery-ui.css"/>
<link rel="stylesheet" href="style/lib/chosen/chosen.css"/>
<link rel="stylesheet" href="style/lib/icheck/minimal/yellow.css">
<link rel="stylesheet" href="style/reset.css">
<link rel="stylesheet" href="style/style.css"/>

<!-- Here I have the definition of `protect_from_FOUC` in an inline script -->

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

In main.js:

require.config({
    paths: {
        // Common:
        'jquery': ['//code.jquery.com/jquery-2.0.3.min', 'lib/jquery'],
        'sugar': ['//cdnjs.cloudflare.com/ajax/libs/sugar/1.3.9/sugar.min', 'lib/sugar'],

        // UI:
        'jquery-ui': ['//code.jquery.com/ui/1.10.3/jquery-ui.min', 'lib/jquery-ui'],
        'autosize': ['//cdnjs.cloudflare.com/ajax/libs/autosize.js/1.17.1/autosize-min', 'lib/jquery.autosize'],
        'chosen': ['//cdnjs.cloudflare.com/ajax/libs/chosen/0.9.15/chosen.jquery.min', 'lib/chosen.jquery'],
        'icheck': ['lib/jquery.icheck'],

        // django i18n:
        'gettext': [translations_url + '?noext']
    },
    shim: {
        'jquery-ui': {
            deps: ['jquery']
        },
        'autosize': {
            deps: ['jquery']
        },
        'chosen': {
            deps: ['jquery']
        },
        'icheck': {
            deps: ['jquery']
        }
    }
});

require(['style', 'interaction']);
Was it helpful?

Solution

The reason for the paean of scripts-right-before-</body> is because they block parsing.

This is bad, especially considering your use case, in which there is likely much content on your page waiting to be parsed and rendered other than what you are including via Javascript.

Including scripts last allows for everything included directly in HTML to parse and render happily without waiting for any scripts (and their entire cycle of request -> parse -> execute).

However, there is a problem with this strategy. And that is piling script tags at the end of your body doesn't allow for good (any?) dependency management. This is one of the main reasons requirejs was created (among other purposes like code encapsulation, versioning/fallbacks, template plugins, etc).

You are using requirejs for a valid purpose that would be a pain to manage otherwise, and so I would certainly say that requirejs is "worth it" in this case.

As to your comment on "FOUC patching" seeming counter-productive, I am not exactly sure why you find that to be so. Consider what the patch provides you: both a smooth-loading UI and unblocked HTML. Throwing blocking scripts in the head could certainly be a valid decision, but only if most of the content on the page depends on them being loaded as quickly as possible. This is rarely the case (and is in fact something of an antipattern outside of demo/development use).

Think about user experience, specifically thinking about the slow connections/slow JS parsing/executing speeds of somewhat aged smartphones. Rather than keeping these users on a blank screen for 3-5+ seconds, loading asynchronously allows your perceived load time to be much faster. The UI bells and whistles can then be displayed with your FOUC patch when the scripts have finally become available.

Thus you can deliver a seemingly fast page load with async scripts and enhance with JS when loaded, all while getting dependency management/smart resource fallbacks with requirejs. Sounds good to me.

OTHER TIPS

As a follow-up example to external CSS blocking rendering. The rendering of following page will be blocked (in Chrome and FF that I have tested) by the slow external style sheet.

<!doctype html>

<html>

<head>
    <style>body { background: white; }</style>
    <link rel="stylesheet" type="text/css" href="http://deelay.me/0/http://rawgithub.com/gitgrimbo/6487200/raw/red.css">
    <link rel="stylesheet" type="text/css" href="http://deelay.me/5000/http://rawgithub.com/gitgrimbo/6487200/raw/blue.css">
</head>

<body>
    <h1>Top header</h1>

    <script>console.log(new Date()); document.write(new Date());</script>

    <h1>Bottom header</h1>
</body>

</html>

But if you move the two <link> elements into the page body (as the first elements of <body>), then from what I can see in Chrome and FF...

In Chrome, the behaviour is the same as if the <link> elements are in the document's <head>.

In FF, you sometimes see the red background for 5 seconds before the blue, and you sometimes see a flash of red before the blue. I'm not sure why this is.

Blocking script?

It seems as though both Chrome and FF also block the running of the <script> block due to the CSS delay. Not sure why this would be either.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top