Four Kitchens
Insights

Inlining one-use JavaScript

3 Min. ReadDevelopment

Let’s say you have a piece of JavaScript that will only be used on one page, perhaps to provide some unique interactivity. It’s probably attached to a View or maybe a unique node ID. It’s so easy to toss in a drupal_add_js() and move on — or worse, throw the code in your theme. Wouldn’t it be nice if you could inline all these one-use scripts and make them appear only the page they’re needed?

Inline on the Fly

Here’s an easy way to inline scripts without losing the ability to edit them easily. We don’t want our code sitting in a PHP string so we create and maintain a real JS file, and use file_get_contents() to grab it whenever the appropriate page is built.

  // Ensure this JS ends up inline at the bottom of the page
  $options = array(
    'scope' => 'footer',
    'type' => 'inline',
  );

  // JS lives in its own file but is included inline when page renders
  $js_code = file_get_contents(drupal_get_path('module','my_module').'/my_code.js');

  // Add JS to page
  drupal_add_js($js_code, $options);

Optimized pages + organized code

I often find myself using hook_views_post_build() to apply this behavior when a specific Views display needs some custom JS to function properly. That way I don’t have to worry about the path, it just works anytime this View is used.

Avid Features users know it’s much more maintainable to keep the JS in its own file next to the View instead of stuffing it in a Views footer, or worse: tossing vital code for components into the theme’s “main” (read: only) JS file. Putting code in a theme file can seem swell until you copy a Feature for use in another project and just can’t figure out where that JavaScript went.

/**
 * Implements hook_views_post_build().
 */
function my_feature_views_post_build(&$view) {
  $has_run = &drupal_static(__FUNCTION__);

  if (!$has_run) {
    switch ($view->name) {
      // Check for the relevant View(s)
      case 'my_view':
        // Check for the relevant display(s)
        if ($view->current_display == 'my_block') {
          // Ensure this JS ends up inline at the bottom of the page
          $options = array(
          'scope' => 'footer',
          'type' => 'inline',
          );

          // JS lives in its own file but is included inline when page renders
          $js_code = file_get_contents(drupal_get_path('module','my_feature').'/my_code.js');

          // Add JS to page
          drupal_add_js($js_code, $options);
          $has_run = TRUE;
        }
        break;
    }
  }
}

Performance

Inlining a script avoids an http request and is great for frontend performance. However, if you have a page that is uncached and hit continuously, adding disk reads won’t be so great for the actual server’s performance. You can see in the second example there’s a reference to drupal_static(). This is a good way to avoid running a slow Drupal hook more than once per page request. Always make sure to cache the outcome of functions like this one in order to avoid too many disk reads.