3

I'm working on a module to embed Highcharts into nodes. Other chart modules provide a PHP helper function to trigger the necessary library loading. To avoid enabling the PHP module, I tried creating an input filter with a token for loading the Javascript library. Unfortunately, filter output gets cached, so calls to drupal_add_js within a filter function don't get called on every page load.

I can think of a few workarounds:

  • a small inline script to load the library, after a node containing a chart has loaded
  • embed the whole library file inline, on pages where it's needed
  • load the library on every page, via hook_init

From a performance perspective, what is my best option?

For what it's worth, the compressed Highcharts library is 81k. The site I plan on using this on has Javascript aggregation enabled, but few content items will have charts, especially initially. Plus, I'd like to contribute the module on d.o, so I'd like to solve this in a way that would make sense on most sites.

1
  • 1
    If this is going to be for D6; open up an issue on AdvAgg, I think we can come up with a good solution.
    – mikeytown2
    Commented Oct 17, 2011 at 1:22

3 Answers 3

3
+50

You could also hook into the node's presave, check whether the body contains whatever it is, then set a flag on the node (perhaps using flag or taxonomy) if it does. Then on view, you look for the flag and use drupal_add_js if necessary. This will survive the cache and let you aggregate the script if you want to. If you'd prefer, rather than storing the flag in the DB, you can check for highcharts on every view (via hook_nodeapi()) and just add the JS there directly.

Btw, strongly recommend against the hook_init() approach - there are definitely better ways imho. hook_init is called on every full bootstrap, which includes eg. 404s and imagecache generation (as well as every normal node view). Generally it's a good idea not to use this if your code is only needed in specific circumstances (eg. only when there's Highcharts code embedded). In those situations, you want to find a way to add your code only to appropriate pages.

10
  • Agreed, hook_init() is way too early in the bootstrap process and can result in some really funky results.
    – DeeZone
    Commented Oct 13, 2011 at 13:04
  • Can either of you elaborate on why to avoid hook_init? I've noticed several contrib modules that add Javascript that way. In any case, thanks for the feedback!
    – Matt V.
    Commented Oct 13, 2011 at 14:41
  • @Matt V. updated answer.
    – Andy
    Commented Oct 13, 2011 at 16:23
  • @DeeZone - I'm not sure the results should be particularly funky, just not such a good idea from a perf perspective...
    – Andy
    Commented Oct 13, 2011 at 16:25
  • See the doc page for hook_init - api.drupal.org/api/drupal/modules--system--system.api.php/… The documentation states: "To add CSS or JS that should be present on all pages, modules should not implement this hook, but declare these files in their .info file." The "funkiness" is a result of "This hook is not run on cached pages."
    – DeeZone
    Commented Oct 13, 2011 at 20:36
2

That's kind of a toss-up. Note that 81kB is the "minimized" size - when gzipped it's further reduced to 32kB. Still, I'd lean towards inline - adding <script src="...highcharts.js" /> in the filter output. This tag will survive the filter cache, and you won't inflate the aggregate on pages that don't display charts. The browser will cache the file after the first load.

For size comparison, a default Drupal 7 install includes about 50k (gzipped) of scripts on the home page.

1

I don't know exactly how will be your implementation of embeding, but I think filter solution is too intrusive. If later on you decide to stop using this module, you will have those tags in the content of your nodes

Probably a good intermediate solution would be to use the hook nodeapi view, to add the js needed with drupal_add_js, and have an admin settings page to enable this feature per content type.

Once that the user has downloaded first time the library, it's cached by the browser, so not big deal.

Inline script tags can't be aggregated by Drupal core. And they will block the browser (rendering the page) to start downloading the library. It's better to load the library in the bottom of the page or async way. Mikeytown knows more about this. ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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