Packaging for Environments

Series: the Stack

Different contexts, different assets

Typical Environments:

  • localdev: a local development environment runs on developers machine. Moves fast so automate rebuilding of assets every time a dependent file changes. Keep css and js human readable.
  • development: deplyed to a private server for testing.
  • production: in production, make it lean.

Loopback provides several schemes for maintaining different configurations in the same repository that obey the NODE_ENV environment variable.

So when you run the app...

NODE_ENV=localdev node .  

The app is configured for the localdev environment and typically connects to a local database.


Automation and Packaging of Assets

For client side assets you typically want human readable CSS and JS in the localdev and development environment and minified and uglifyed sources in production.

A moderately complex site would typically include several open source frameworks and packages which need to be rolled up into the packages so the client does not have to download many files.

Grunt to the rescue (or Bower if you prefer.) Use concat to combine all your javascript sources into one file for faster page load. Same for css.

In production you can use grunt's uglify and cssmin components to further compress and obfuscate the client assets.

In a typical case you will want to:

  • concatenate JS for bootstrap, jquery etc with your site JS into a single file
  • run the concatenated js though uglify to generate a xxx.min.js version
  • run less on your bootstrap base.less to compile bootstrap css
  • compile site stylus files to css
  • concatenate bootstrap css and your site css compiled from stylus into a package
  • run the concatenated css through cssmin to compress it into an xxx.min.css file

All of these annoying tasks can be automated using watch to run this any time a source file is changed.

Working example of gunt configuration grunt.js

The compiled result is placed in client/dist/css and client/dist/js for inclusion in your markup.


Now that you have the packages you can expose the running environment value on app.locals so they are accessible in your template engine.

For the Jade template engine:

server/server.js

// expose the running environment name to jade
app.locals.env = app.get('env');  

Now we can conditionally reference JS and CSS payloads compiled for each environment in your templates.

server/views/wrapper.jade

    if env === 'production'
      link(rel='stylesheet' href="/dist/css/DigitopiaExamples.min.css")
    else 
      link(rel='stylesheet' href="/dist/css/DigitopiaExamples.css")

....

    if env === 'production'
      script(src="/dist/js/DigitopiaExamples.min.js")
    else
      script(src="/dist/js/DigitopiaExamples.js")

Photo: A sifaka in a baobab tree in Madagascar (2008)
Document version 1.0