dimagi/Vellum — pull request #229 by millerdev (2014-08-20 19:46:48+00:00)
Title: Fix missing tree

http://manage.dimagi.com/default.asp?128716

@mwhite

## Explanation:

The CSS was sometimes loading images relative to the Vellum base URL (presumably as intended) and sometimes relative to the page URL (broken). It was unclear, and still is to some degree, why this was an intermittent bug. My best guess at this point is that there was a race condition in the JavaScript code, probably part of the RequireJS configuration, that was sometimes running before the CSS images were requested.

The first thing I began investigating was the way Vellum handles source paths, which are different depending on the context in which it is being loaded (raw source, built; in test page, in HQ). I had noticed a hack in the require config that dynamically set relative paths of various resources. This hack seemed particularly relevant (and incomplete) because it did not fix up image URLs embedded in CSS.

To make things even more complicated, Vellum uses RequireJS plugins ([require-less](https://github.com/guybedford/require-less) and [require-css](https://github.com/guybedford/require-css)) that compile LESS files and inline CSS into the JavaScript during the build process. It was (and still is) unclear what the base URL of that CSS is once it had been inlined (I have an item on my long-term TODO list to learn the intricacies of embedded CSS and resource loading). It would have been convenient and even made sense if this was the path of the JavaScript file, but that did not appear to be the case in practice.

Unfortunately there was no comment about why the path munging hack was needed, and I could not find anything similar in the examples for setting up RequireJS, and Google knew nothing about the names of the functions used to implement the hack (it did not appear to be a well-known issue/fix). So my first task was to remove the path munging hack to see if that fixed or changed the error. It did. The CSS now always requested image resources relative to the page URL (bummer). It was in the process of working through this that I came upon two bugs related to require-less and require-css that affect Vellum:

LESS and CSS cannot be combined in the same built module because require-less and require-css plugins do not work together perfectly (odd, given that they are both written by the same author). The suggested fix requires a source code patch that has not been incorporated into the main repo yet. https://github.com/guybedford/require-less/issues/48

Embedding CSS in the JavaScript is not supported for movable components like Vellum that may be loaded from any arbitrary path (relative to the page URL) once built: https://github.com/guybedford/require-css/issues/139

The fixes for these issues are:

- build all LESS in a module that does not contain raw CSS, and build CSS files in other modules that do not contain LESS. This is pretty easy to do, but would be nice if we didn't have to worry about it. TODO: make require-less handle CSS correctly and submit a PR to that project.

- compile CSS into a separate file rather than inlining it in the JavaScript. The disadvantage is that it requires an extra request to load the CSS, but that seems like a small price to pay at this point.

Once I had removed the hack and discovered the bugs, it still took quite a bit of trial and error to get all the different use scenarios of Vellum working: stand-alone test page, embedded in HQ; raw source version, built version; Chrome, Firefox, phantomJS (headless test runner).

Takeaways:

- RequireJS resource loading is complicated and does not support LESS/CSS and image dependencies seamlessly. Unless you have CSS that does not need to load external resources like images, it's probably best to follow the lead of well-known components like jquery-ui and bundle/load style sheets separately rather than embedding them in JavaScript.

- RequireJS does not seem to have a lot of documentation for the use case of implementing a complex reusable/embeddable component like Vellum. It seems to be more geared toward managing and optimizing an entire website. An especially tricky point is dealing with resources such as jQuery that are required by Vellum and may or may not be used by the rest of the site. How to bundle and load them without interfering/breaking things? This gets even more complicated (unworkable?) with multiple versions of said dependencies (e.g., if Vellum uses jQuery 1.9 while HQ uses jQuery 1.8). Topic for ongoing investigation: what are the best practices for using RequireJS to develop a component like Vellum? How to handle symbolic naming of internal components without having those names bleed out into-, and conflict with the website context in which the component is loaded (assuming the site also uses RequireJS)? How to handle relative resource paths in the Vellum RequireJS config when there appears to be a single (global?) `baseUrl` setting relative to which all resources are loaded? It works fine as long as Vellum is the only thing on the page using RequireJS, but what about when we want to use RequireJS for other things too?