npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

cobuild

v0.1.5

Published

Cobuild isn't a build system, but it is a system that helps you build build systems faster.

Downloads

9

Readme

Cobuild for NodeJS


  1. Introduction
  2. Basic Usage
  3. Basic Methods
  4. Build/Render Options
  5. Advanced Methods
  6. Creating Your Own Renderers
  7. Middleware

Cobuild isn't a build system, but it is a system that helps you build build systems faster. This (mostly) asynchronous module allows you to pass one or more files through it to transform text-based content by sending it through one or more renderers based on their filetype.

You can quickly process your CSS, compress your JS, run your HTML through a template parser, or process any other text document... all through a single interface.

If a renderer supports it, you can concatenate text files. Any files with unknown/unspecified content types are simply copied to their destinations, so you can pass in images and other files right alongside with your text files and they'll end up right where they belong.

All examples (as well as the module itself) are written in Coffeescript.


# Load the cobuild module
cobuild = require 'cobuild'

# Create our builder and pass it our global configuration options
builder = new cobuild
  base_path:     "#{__dirname}/"
  renderer_path: "#{__dirname}/renderers/"
  eco:
    global:
      var1:      "foo"
      var2:      "bar"
  stylus:
    foo:         "bar"

# Array of file description objects
files = [{
    source:      'src/example.js'
    destination: 'release/example.js'
  }
  {
    source:      'src/example.styl'
    destination: 'release/example.css'
  }
  {
    source:      'src/example.html.eco'
    destination: 'release/example.html'
  }]

# Options specific to the build we're going to run
# In this case, we're overriding a global setting from above
options =
  stylus:
    foo: "foo"

# Let's do it
builder
  .add_renderer('styl', 'stylus_r')
  .add_renderer('js', 'uglifyjs_r')
  .add_renderer('eco', 'eco_r')
  .add_renderer('eco', 'uppercase_r')
  .build
      files:   files
      options: options
    , (err, result) ->
      console.log "Build successful" unless err
      return

constructor(config)

config is an object that contains the global configuration settings. Renderers have access to this object, so it's a good place to store global settings for those, too.

add_renderer(type, path_to_render)

Use this method to add a renderer to the file type specified by type. Renderers are loaded (via require) on first use (via one of the build methods below), and they are loaded from the renderer path specified in your config file, or from Cobuild's default render path. The build method will render each type in the order specified by successive calls to this method.

Returns this for chaining

build(params, callback)

Use Cobuild to transform the content based on what you pass in via the params object.

Render multiple files at once (or a single file you want to be saved after rendering):

files: (array)     # An array of file objects (see below)
                   # E.g. [{ source: 'src/my_file.html',
                   # destination: 'release/my_file.html' }]

Render one file at a time:

file: (string)    # String containing a file path relative
                  # to the base_path (single file)
                  # E.g. 'src/my_file.html'

Render a single string:

string: (string)   # String containing the text you want to transform
                   # E.g. 'Transform me!'

Force cobuild to render content as a certain type (required if rendering a string)

type: (string)     # If a file is specified, the type is
                   # automatically detected from the file extension,
                   # but if specifying a string (or if you want to force
                   # files to be transformed as a certain type),
                   # E.g. 'html'

Build-specific options. These will override any global settings you've already specified.

options: (object)  # Optional settings to be passed to the renderers.
                   # E.g. { stylus: { foo: "bar" } }

If a renderer doesn't exist for the provided type, the method will copy the file to its destination (if specifying multiple files), or output the untransformed content when passing a single file or a string.

The callback function takes two arguments, err and result.

err will contain any uncatchable errors (if any) that were encountered when rendering the files, and result will contain the results of the build. If you specified multiple files, result will be a boolean true or false, if you specified a single file or string, result will contain the transformed text.


The only three build-related options are callbacks that are ran on pre and post processing of content, and an option to force cobuild to build a file even if the destination and source seem to be unchanged (based on modification time). These options can be overriden on a per-file basis using the build method above.

preprocess: [callback]   # Process the content before it hits the
                         # rendering chain so you can strip metadata,
                         # or do other transforms

postprocess: [callback]  # Process the content after its been rendered
                         # Last chance to make changes before it's saved/output

force: false             # Force cobuild to process this file even if the
                         # destination and source modification times match

Callbacks specified for preprocess/postprocess should be in the form of:

postprocess: (content, type, options, callback) -> ...

Where content is a string containing content being rendered, type is the type of content being rendered, options are the build-specific options passed to the current build process, and callback is the function you need to call after you're finished processing the content to continue the render process.

The signature for this callback is:

callback = (`err`, `processed_content`) -> ...

render(content, renderer, options)

This method is called if you want to render a string (content) and pass in your own renderer that's already been initialized. renderer must be an instance of an object that implements the render method as outlined below. The build method above uses this internally to render any content/files passed to it.

Returns string

remove_renderer(type, path_to_render (optional))

Use this method to remove all renderers from the file type specified by type. Optionally, if you only want to remove a specific renderer, you can pass the same path you used to add the renderer for this method to remove just that renderer.

Returns this for chaining


This is where Cobuild really shines as it's easy to create pluggable renderers with very little code. Renderers are just objects that implement the render method:

render = (`content`, `type`, `options`, `callback`) -> ...

It's your responsiblity to a return the string value of any transformations you make via the provided callback.

callback = (`err`, `rendered_content`) -> ...

If you want to make any parts of your renderer user-configurable, you can just include those options when calling build and they'll be made available to your renderer via the options parameter. In addition, any configuration options set via the cobuild configuration will be included and available under options.config If a file is passed to the build method (whether build is called with a single file or multiple files), an object describing the current file being processed (that includes the source, destination, etc.) will be available at options.file.

By including your renderer in your renderer_path (specified in the configuration file you passed to Cobuild during initialization), Cobuild will use your renderer when you pass it to the add_renderer method. The renderer itself will be initialized when it's first used, and it's instance will persist until it's been removed; this lets you do things like track statistics and thi if you want.

To keep naming consistent and make renderers easily identifiable, the official renderers will always have an _r suffix at the end of them. I recommend you do the same with your renderers.


Example Renderer

You can always view the renderers in the lib/renderers folder for reference (there are renderers for eco, stylus, and tidy), but here is a quick example of a renderer (in CoffeeScript):

module.exports = class Stylus_r

  render: (content, type, options, callback) ->
    styl_opts = options.stylus || {}
    styl_opts.filename = options.file?.source || ''
    stylus.render content, styl_opts, callback

Cobuild includes a middleware component that allows you to render assets on demand.

There are two modes available when using the middleware.

The first mode allows you to specify explicit mapping between destination and source files. When a request is made, cobuild checks to see if the URI matches the destination of any of the files passed to it. If it finds a match, it loads the source, renders it, and then saves the output back to the destination.

The second mode allows you to specify the source_path and output_path and cobuild will attempt to build any files requested if they exist in the source_path. Since you might be using different extensions for your files to identify what kind of file they are in your source folder, you can optionally pass alternate extensions that cobuild will check for when attempting to match a source file to the destination URI. Cobuild will render the first file it finds successfully.

The middleware component requires a different initialization object that specifies not only the configuration options, but also additional settings specific to the middleware. These will be documented at a later time, but for now refer to the examples below.

Example of using the middleware to render certain files explicitly (first mode):

cobuild = require '.cobuild'
express = require 'express'
http    = require 'http'
app     = express.createServer()
port    = 9999

# We need a special config object to pass to our middleware constructor
middleware_config =
  options:
    base_path:      "#{__dirname}/"
    renderer_path:  "renderers/"
  middleware:
    source_path:    "source/
    output_path:    "output/web/"
  files: [{
      source:      'foo.html'
      destination: 'foo.html'
    },{
      source:      'bar.eco'
      destination: 'bar.html'
    }]
  renderers:
    'eco':  [ 'eco_r' ]
    'html': [ 'eco_r', "tidy_r" ]

# Configure the server with our middleware
app.configure ->
  app.use app.router
  app.use cobuild.middleware middleware_config
  app.use express.static "#{__dirname}/output/web/"

# Start the server
app.listen port

Example of using the middleware to render all files under source_path (second mode):

cobuild = require '.cobuild'
express = require 'express'
http    = require 'http'
app     = express.createServer()
port    = 9999

# We need a special config object to pass to our middleware constructor
middleware_config =
  options:
    base_path:      "#{__dirname}/"
    renderer_path:  "renderers/"
  middleware:
    source_path:    "source/
    output_path:    "output/web/"
    extensions:
      'html': [ 'eco' ]
      'css':  [ 'styl', 'less' ]
  renderers:
    'eco':    [ 'eco_r' ]
    'styl':   [ 'stlyus_r' ]

# Configure the server with our middleware
app.configure ->
  app.use app.router
  app.use cobuild.middleware middleware_config
  app.use express.static "#{__dirname}/output/web/"

# Start the server
app.listen port