I’ve been developing rails apps for over a year with Six Fried Rice, and we’ve been using ExtJS as our Javascript framework. As is quite common in industry, we’ve developed internal libraries for Ruby, Rails, vanilla Javascript, and ExtJS. When I used to write Java, we would have our shared libraries in separate source control projects, package them up as JARs and just distribute binaries, which we would check in to each project that used them. This worked fairly well because of 2 important reasons:
- Our libraries were mature
- They could be developed independently of a certain project
Number 1 is nice because the libraries don’t need to be updated often, so you usually only needed to spend time getting them set up at the start of a new project. Number 2 was true because our libraries usually revolved around authentication/single sign on and they were maintained by an entirely different group in IT. This is more typical of large enterprise development.
So when I wanted to do something similar for our rails/js libraries, I initially turned to gems and plugins. Either of these solutions would work fine for our modifications to Ruby, and we do currently maintain 2 internal rails plugins that handle our ruby convenience methods and also some changes we’ve made to rails (that haven’t made it into core rails yet….). We keep those plugins in separate subversion projects, and everything work great.
Now enter Javascript. We write lots of javascript. Many times as much as we write ruby. The Javascript also tends to be dirtier than ruby, and we run into a lot of problems that are much harder to reproduce so I usually prefer to test changes to the libraries in the context of the applications that use them. This JS code is also very immature and changes frequently, often daily. The traditional method of developing a library on the side and updating it occasionally breaks down for this case, so the situation for the JS libraries is the opposite of the traditional way I described above:
- Immature code that changes frequently
- Development depends on applications that use the library
It turns out that there is a nice property that is supported by subversion called externals. This allows you to set a directory in one repository to link right to another repository. You can make changes to the library right there, commit it back, and then go run update on a different project and it will go grab the changes. This is perfect, except for one thing. Say I branch off of trunk to write a big new feature that ends up adding a lot of code to the Javascript UI library. This branch may take a few weeks to finish and the whole time I’m committing new code to the javascript, which gets propagated to trunk everytime I update, which could certainly introduce bugs that we might not want in other branches.
This leads me (finally) to the point of this post. I solved this by writing a rake task to “freeze” and “unfreeze” the library. When it is frozen, the library just stays at a version we know to be stable. When you want the latest code, or if you need to make changes, you unfreeze it and test. We’ve been using this solution for a few weeks now and its works really well, so I decided to post the rakefile that handles installation and freezing of a javascript library, called ‘jslib’ by default.
external_js_library.rake
Now I can do cool stuff like
rake jslib:freeze
which makes sure that the library stays at whatever version it is at right now forever, or until I issue:
rake jslib:unfreeze
which sets it back to HEAD and updates. I don’t think this is a replacement for gems/rails plugins, but it does a very good job of handling our shared javascript library. Thoughts?