asset-smasher v0.3.2
Asset Smasher
Asset pre-processor, merger, and compressor for Node.js
- Structuring Your Assets
- Using via Command Line
- Using via Express Middleware
- Using via Programmatic Interface
- Transformer Notes
Overview
Asset Smasher is a command-line tool, express middleware, and programmatic interface for:
- Pre-processing and transforming files down to plain JavaScript and CSS.- .coffee- Compile CoffeeScript into JavaScript
- .ejs- Run a file through EJS (e.g. to populate configuration parameters into a JavaScript file)
- .less- Compile Less into CSS
- .hbs- Precompile Handlebars templates into JavaScript files that register them with- Handlebars.templates.
- .dust- Precompile Dust templates into JavaScript files that register them for use with- dust.render.
- Processors can be chained together.  E.g test.js.hbs.ejs(run Handlebars template through EJS, then compile it)
- Additional processors can be plugged in.
 
- Merging files together using Manifest files (.mf) with dependency management directives similar to Sprockets.- require- Require a single file
- require_dir- Require all the files in a specific directory
- require_tree- Require all the files in a specific directory (and subdirectories)
 
- Compressing, gzipping, and generating hashed file names.- Compress JavaScript files with uglify-js
- Compress LESS during LESS preprocessing
- Generate Gzipped versions of files
- Include a MD5 hash of the file's contents in the file name. myAsset.js->myAsset-c89cba7b7df028e65cb01d86f4d27077.js- asset_pathhelper that can be used to reference the hashed name.
 
 
- Compress JavaScript files with 
It's released under the MIT license.
Structuring Your Assets
Asset Smasher has the concept of "asset paths". These are locations in which your asset files will be located, and from which any relative asset paths will be rooted to.
The simplest structure has one asset path.
E.g.
Asset Paths
-----------
 - app
File Structure
--------------
app/
  js/
  css/
  images/A more complicated structure might be
Asset Paths
-----------
 - app
 - lib
 - vendor
File Structure
--------------
app/
  js/
  css/
  images/
lib/
  js/
  css/
  images/
vendor/
  js/
  css/
  images/Both of these examples will result in a compiled structure of
js/
css/
images/Manifest Files
Manifest (.mf) files are used to merge many assets into a single resulting file. The file should be named with the resulting file type before the .mf extension (e.g. manifest.css.mf or manifest.js.mf. Manifest files can require other manifest files
A simple manifest file might look like
# A comment here
require "./one.js"
require_dir "./subdir1"
#
# Another comment
require_tree "./subdir2"Directives:
Using via Command-Line
Use npm install -g asset-smasher to install the asset-smasher command-line tool globally.
  asset-smasher --help
    Usage: asset-smasher [options] <output dir>
    Options:
      -h, --help               output usage information
      -V, --version            output the version number
      --compress               compress/minify the generated files
      --hash                   generate versions of the files with md5 hashes in the name
      --gzip                   generate gzipped versions of the compiled files
      --hashVersion <version>  invalidate all assets without changing file contents [1.0]
      --only <pattern,...>     only process the files matching these glob patterns (relative to any of the paths) [**/*]
      --paths <path,...>       list of paths to look for assets [.]
      --prefix <prefix>        prefix to append to logical paths when constructing urls. use if output dir is not served from the root of your web app []
      --helpers <js_file>      a .js module of helper functions require()s to expose to transforms []
      --plugins <js_file>      a .js plugin module []
    If --only is not specified, *all* files in the --paths will be processed.
    Examples:
      Compile all assets in the current directory to /home/me/compiledAssets
        $ asset-smasher /home/me/compiledAssets
      Something similar to what the Rails asset pipeline does by default
        $ asset-smasher --compress --hash --gzip --prefix=/assets \
            --paths=./js,./css,./images \
            --only **/*.{jpg,gif,png},application.js.mf,application.css.mf ./public/assets
      Compile assets, providing some custom helpers to the transformation
        $ asset-smasher --helpers helpers.js outputHelpers
There is a built-in asset_path helper that can be used to get the "real" (i.e. with hashed file name) path of an asset.  E.g. asset_path('css/myFile.css') might return '/assets/css/myFile-c89cba7b7df028e65cb01d86f4d27077.css.
Some transformers (e.g. the .ejs one) take in a set of local variables that they can use during transformation. You can pass in the path to a JavaScript module whose exports will be included in this set of variables.
You can use this, for example, to set configuration parameters in your JS files:
helper.js
exports.serviceUrl = 'http://my.service/';config.js.ejs
//...
var serviceUrl = '<%= serviceUrl %>';
var cssLocation = '<%= asset_path('css/myFile.css') %>';
//...Execution
$ asset-smasher --helpers helper.js --only config.js.ejs,css/myFile.css .
$ cat config.js
var serviceUrl = 'http://my.service/';
var cssLocation = '/assets/css/myFile-c89cba7b7df028e65cb01d86f4d27077.css';Plugins
If there's a type of file you want to pre-process that is not natively supported by Asset Smasher, you can add it using a plugin file.
TODO: How to add additional transformers via a plugin file.
Using via Express Middleware
Asset smasher exposes an express middleware that can:
- Serve your assets un-merged/mangled in development mode.
- Serve precompiled assets (with hashed file names) in production mode.
The middleware takes in the same arguments as the Smasher constructor, with a few extras:
- serve- boolean whether the middleware should serve the asset files. Usualy set this to- truein development,- falsein production
- assetMapLocation- path to the- map.jsongenerated by the command-line- asset-smasherutil. This allows the helper methods to determine what the hashed file names were
The middleware exposes two helpers to your views:
- js_asset(logicalPath)- Render a- <script>tag for the specified JS asset. When- serveis true, this will "explode" manifests and write out a separate- <script>for each required file. This makes debugging much easier.
- css_asset(logicalPath)- Render a- <link>tag for the specified CSS asset. Same thing happens when- serveis true.
Example
var assetSmasher = require('asset-smasher');Middleware config (Dev)
app.use(assetSmasher.middleware({
  serve: true,
  paths: [path.join(__dirname, 'assetDir1'), path.join(__dirname, 'assetDir2')],
  prefix: '/assets',
  outputTo: path.join(__dirname, 'tmp')
}));Middleware config (Prod)
app.use(assetSmasher.middleware({
  serve: false,
  prefix: '/assets',
  assetMapLocation: path.join(__dirname, 'public/assets/map.json')
}));View (ejs here, but could be others)
<!DOCTYPE html>
<html>
<head>
  <title>Test</title>
  <%- css_asset('application.css') %>
  <%- js_asset('application.js') %>
</head>
<body>
  This is a test
</body>
</html>Using via Programmatic Interface
You can invoke Asset Smasher programmatically by requireing it.  You can also plug in additional transformers this way.
The Smasher object has the following methods:
- compileAssets(cb)- Find and compile all the assets.
- compileSingleAsset(assetFilePath, cb)- Compile a single asset (assetFilePath is the actual path to the file, not a logical path)
- findAssets(cb)- Find, but don't compile the assets. Good for determining dependency graph without compiling.
- getAssetByLogicalPath(logicalPath)- Get information about an asset by its logical path. Only call this after finding/compiling assets.
- getHashedFileMapping()- When- hashis true, this returns a mapping of logical path to "hashed" logical path. This object is what the command-line tool outputs to- map.json. Only call this after finding/compiling assets.
- getRequiredLogicalPathsFor(asset)- Get the logical paths of the assets that should be merged into the specified asset (populated for- .mffiles). Only call this after finding/compiling assets.
- getProcessingOrderLogicalPaths()- Get a list of the order in which assets should be processed in order to satisfy all dependencies. Only call this after finding/compiling assets.
The Asset object returned by getAssetByLogicalPath has the following properties:
- logicalPath- The logical path
- hashedPath- If- hashis true, the hashed filename path, otherwise the same as- logicalPath
- assetFilePath- The full path to the actual source asset
- compiled- Whether the asset has been compiled
- compiledAssetFilePath- The full path to the compiled asset file
Example
var assetSmasher = require('asset-smasher');
var Smasher = assetSmasher.Smasher;
// Plug in a custom transformer
assetSmasher.transforms['MyAwesomeFormat'] = require('myAwesomeFormatTransformer');
var sm = new Smasher({
  paths:['/path/one', '/path/two'],
  only:['**/*.{jpg,gif,png}', 'application.js.mf', 'application.css.mf'],
  prefix:'/assets',
  compress:true,
  hash:true,
  hashVersion:'1.0',
  gzip:true,
  outputTo:__dirname + '/public/assets',
  helpers:{
   my: 'helper',
   another: 'helper'
  }
});
sm.compileAssets(function(err) {
  if(err) {
    console.log('An error occurred', err);
  } else {
    console.log('Compilation done!');
  }
});Transformer Notes
LESS
- When the compressoption is true, the compression is done directly via thelesscompiler
- Any @includepaths are relative to the path that the file is in.
- Any @included files will not be processed individually by Asset Smasher (i.e. you can't@includea LESS file that is preprocessed by ejs)
ejs
- Any registered helpers will be exposed as global variables to the ejstransform.
- The built-in asset_pathshelper can be used here.
dust and Handlebars
- The name of the template will be the template's "logical path" (minus the asset path it is in), minus the .js.dustor.js.hbsfile extension.- E.g. /my/templates/test.js.dust's template name will betest(assuming/my/templatesis the asset path)
 
- E.g. 
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago
13 years ago