7

When Drupal is set to optimize JS and CSS, it creates the 'js' and 'css' folders in your public file system root. Aggregated JS and CSS get stored in these directories. I've tried to figure out how Drupal keeps track of these files, and how Drupal matches consequent page request against applicable aggregated files in these directories. Is the filename a hash based on, say, the request URL?

Right now, I'm working on a site which has 4 web servers. All web servers have the same storage mounted as their public and private file systems. When one server generates CSS and JS files for a page, how does any of the other servers utilise these generated files for an indentical request?

14

CSS/JS files get added to Drupal various ways; 5 out of the 7 ways allows for the file to be aggregated. Once they have been added to the page, drupal renders the html markup for them and creates/uses the markup inside of template_process_html().

Functions to look for how an aggregate is built is drupal_build_js_cache() & drupal_build_css_cache(). Inside of these function it gets a list of filenames and then creates a hash of them. This is a lookup, to see if the file has already been created.

  $map = variable_get('drupal_js_cache_files', array());
  // Create a new array so that only the file names are used to create the hash.
  // This prevents new aggregates from being created unnecessarily.
  $js_data = array();
  foreach ($files as $file) {
    $js_data[] = $file['data'];
  }
  $key = hash('sha256', serialize($js_data));
  if (isset($map[$key])) {
    $uri = $map[$key];
  }

If it has not been created before, because of the order and/or contents of the $file['data'] info then it will create a new aggregate based off of all the files contents strung together.

  if (empty($uri) || !file_exists($uri)) {
    // Build aggregate JS file.
    foreach ($files as $path => $info) {
      if ($info['preprocess']) {
        // Append a ';' and a newline after each JS file.
        $contents .= file_get_contents($path) . ";\n";
      }
    }
    // Prefix filename to prevent blocking by firewalls which reject files
    // starting with "ad*".
    $filename = 'js_' . drupal_hash_base64($contents) . '.js';
    // Create the js/ within the files folder.
    $jspath = 'public://js';
    $uri = $jspath . '/' . $filename;
    ...
    $map[$key] = $uri;
    variable_set('drupal_js_cache_files', $map);
  }
  return $uri;

The files are kept track inside of 2 variables drupal_js_cache_files and drupal_css_cache_files; Drupal will also check to make sure the file exists before it is used. The aggregates have nothing to do with the URL. Your 4 webheads will utilize these aggregates due to the variables being stored within the database.

Note: AdvAgg is sorta similar to this but it uses a couple database tables instead of 2 variables; AdvAgg does this for a couple of reasons mainly to fix issues with concurrent variable_set's and allowing for advanced grouping logic.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.