Thursday, October 25, 2012 4:46 PM

Meteor resource loading: Eliminate cluttered js and css code

Author: matthias - Last modified: Thursday, November 1, 2012 11:40 AM

en meteor  twitter-bootstrap  responsiveness smart-packages  css

Today I stumbled upon an interesting question asked on stackoverflow related to a problem with Twitter Bootstrap and how to solve it in Meteor.

Since Meteor loads a lot of resources "under the hood" one might ask how to manipulate e.g. css styles with inline style definitions after loading x.css but before loading y.css and so on (these things we all like to do as a quick solution, right?).

When writing Meteor apps you won't even get in touch with defining <link> or <script> tags and instead see some magically rendered code within your application HTML looking something like:

<link rel="stylesheet" href="/packages/bootstrap/css/bootstrap.css">
<link rel="stylesheet" href="/packages/bootstrap/css/bootstrap-responsive.css">
<link rel="stylesheet" href="/packages/bootstrap/css/bootstrap-override.css">
<link rel="stylesheet" href="/client/bootstrap-user.css"> 

Same with the following JS resources. End. That's your app. Nice.

The question specifically refers to a problem where body margins are "hacked" between the loading of bootstrap.css and bootstrap_responsive.css. That way, that the margins don't apply in certain media device dependent screen width sizes. How to hack this in Meteor?

I found the question interesting enough to figure out some solutions plus gathering some basic thoughts on this problem and on the Meteor way ignoring (or better: dealing with) it. I posted a quite too long answer and came to the conclusion that Meteor helps us writing cleaner code.

Meteor states in its' documentation that applications should be written such a way that it is insensitive to the order in which files are loaded (see Meteor documentation) . While this is (ideally) a good paradigm for designing and loading javascript modules and dependencies, it raises questions on how to do-it-best when defining user styles on top of a foundation like bootstrap.

In fact order matters when it comes to css in that way that specific styles should override default styles. With smart packages like Meteors bootstrap package the loading order of bootstrap.css and bootstrap_responsive.css directly one after another is fixedly defined. Thus said, putting something between it "on-the-fly" is impossible.

Recommended solution: Override on top of boostrap/responsive:

In my opinion best practice is do define and load user styles that way that they work like desired when loading after all of the foundation files. An example:

bootstrap-user.css:

@media (min-width: 980px) {
  body {
    padding-top: 60px;
    padding-bottom: 40px;
  }
}

When putting this into one of the user css files everything should be fine. User css files in the Meteor project root are always loaded after smart package files like those linked by the bootstrap package.

Well, here's the "inter-style" approach

If one nevertheless wants to hack it in that way like described in this answer (and even twitter itself suggests) you can go and write your own smart package:

package.js:

Package.describe({
  summary: "UX/UI framework from Twitter - My way"
});

Package.on_use(function (api) {
  api.add_files('css/bootstrap.css', 'client');
  api.add_files('css/bootstrap-pre-responsive.css', 'client');
  api.add_files('css/bootstrap-responsive.css', 'client');
  ...
  // More resource definitions like glyphicons-halflings go here
  ...
}

While the package file css/bootstrap-pre-responsive.css contains:

body {
  padding-top: 60px;
  padding-bottom: 40px;
}

Alternatively one can skip using a smart package for bootstrap integration and instead let just let Meteor collect and load the project resources - the conventions for loading order within your project root is described within the concepts section of the Meteor doc. But: This would mean naming files in an alphabetical way that reflects desired order! (not very elegant)

However, I personally don't like the way of solving the problem like described the latter way.

Last but not least: Of course it's sometimes the best way to build and compile an own boostrap variant with all desired styles minified to one file.

Comment / Share »