Drupal - Adding JS to a Drupal 8 theme (replacement for drupal_add_js)

It seems you can use hook_preprocess_page with attached as such:

function MYTHEME_preprocess_page(&$vars, $hook) {
  $path = drupal_get_path('theme', 'MYTHEME');
     // Render the main scripts file.
  $local_js = array(
    '#attached' => array(
      'js' => array(
        $path . '/js/scripts.js' => array(
          'group' => JS_THEME,
          'weight' => 9999),
      ),
    ),
  );
  \Drupal::service('renderer')->renderRoot($local_js);
}

This works great (theme.inc uses this method), note the extra nested array around the weight.


The key point in the documentation is this bit

Use the #attached key in render arrays instead.

Emphasis mine.

The $variables array in a theme/preprocess function isn't a render array, it's just an array holding variables. To use #attached you'll need something like this in the preprocess function:

$vars['foo'] = array(
  '#markup' => '<p>Bar</p>',
  '#attached' => array(
    'data' => drupal_get_path('theme', 'mytheme') . '/js/scripts.js',
    'options' => array(
      'group' => JS_THEME,
      'preprocess' => TRUE,
      'every_page' => TRUE,
    ),
  ),
);

And this in the template file:

{ foo }

In other words, more or less the same as in Drupal 7 (at this point in time, at least).

hook_preprocess_html() is likely not the right place for this code by the way; don't forget the js/css files are actually rendered in that template, so it's too late to add any more hook_preprocess_page(), hook_preprocess_node() or equivalent will probably get you more reliable results.

See the Twig best practices - preprocess functions and templates page for more information on preprocessing variables.


As of Drupal 8.0.x-beta2 you can attach CSS and JS from preprocess functions.

See https://www.drupal.org/node/2352319