Socket
Socket
Sign inDemoInstall

buddy

Package Overview
Dependencies
75
Maintainers
1
Versions
180
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    buddy

A fast, simple build tool for web projects.


Version published
Maintainers
1
Install size
7.38 MB
Created

Readme

Source

NPM Version Build Status

buddy

buddy is a fast and simple build tool for js/css/html projects. It compiles source code from higher order js/css/html languages (CoffeeScript, es6, JSX, Handlebars, Dust, Nunjucks, Stylus, Less, Jade, Twig), automatically wraps js files in module definitions, statically resolves js/css/html dependencies, and concatenates (and optionally compresses) all souces into bundles for more efficient delivery to the browser.

Features

  • Allows you to write js modules without module boilerplate (similar to node.js)
  • Resolves js dependencies automatically (including those installed with npm)
  • Compiles CoffeeScript, es6, JSX, Handlebars, Dust, Nunjucks, Stylus, Less, Twig, and Jade source files (or others via custom plugins)
  • Concatenates js modules into file bundles
  • Watches for source changes and builds automatically
  • [Add-on] Serves static files from specified directory on specified port
  • [Add-on] Restarts custom server after each change
  • [Add-on] Refreshes connected browsers after each change
  • Inlines css @imports automatically
  • Inlines html <script>, <link>, and <img> tags when flagged with an inline attribute
  • Inlines json content with require("path/to/my.json")
  • Supports execution of a custom script after each build
  • Supports extension via execution of hook scripts afterEach file is processed, and before and after a target is built
  • Supports output of unique file names
  • Supports compression of image assets
  • Inlines environment variables (process.env.FOO)

Installation

To avoid running buddy directly as a global command, and thus avoid versioning problems across different projects, it is recommended that you install the separate buddy-cli command line interface system-wide:

$ npm -g install buddy-cli

...create a package.json file for each project, locally installing buddy as a devDependency:

{
  "name": "myproject",
  "description": "This is my web project",
  "version": "1.0.0",
  "devDependencies": {
    "buddy": "5.0.x"
  },
  "buddy": {
    ...
  }
}
$ cd path/to/project
$ npm install

Usage

Usage: buddy [options] <command> [path-to-config]

  Commands:

    build [config]   build js, css, html, and image sources
    watch [config]   watch js, css, html, and image source files and build changes
    deploy [config]  build compressed js, css, html, and image sources

  Options:

    -h, --help            output usage information
    -V, --version         output the version number
    -c, --compress        compress output for production deployment
    -g, --grep <pattern>  only run build targets matching <pattern>
    -i, --invert          inverts grep matches
    -r, --reload          reload all connected live-reload clients on file change during watch [ADD-ON buddy-server]
    -s, --serve           create a webserver to serve static files during watch [ADD-ON buddy-server]
    -S, --script          run script on build completion
    -v, --verbose         print all messages for debugging

Configuration

Please refer to the annotated configuration file for all possible settings, and note that the configuration format has changed considerably as of version 3.

Plugins

As of version 4, all transfigure-* packages have been deprecated in favour of buddy-plugin-* package names, now properly referred to as "plugins". In addition, in order to keep install times in check, all compressors have been broken out into separate plugin packages as well.

Compiler plugins

The following compiler plugins are currently available:

Compressor plugins

The following compressor plugins are currently available:

Build concepts

Project Root: The directory from which all paths resolve to. Determined by location of the configuration file.

Sources: An array of additional directories from which referenced files may be retrieved from. The Project Root and node_modules directories are added by default. Note: A module's id is derived from it's relative path to it's source directory.

Targets: Objects that specify the input and output files or directories for each build. Targets are built in sequence, allowing builds to be chained together. Note: A js target can also have nested child targets, ensuring that dependencies are not duplicated across related builds.

Target parameters:

  • input: file, directory, glob/expansion pattern, or array of files to build.

  • output: file, directory, or array of files to output to. Optional: when omitted, input files are only watched for changes (during watch command).

  • output_compressed: an alternate file or directory to use for compressed output.

  • targets: a nested target that prevents the duplication of .js source code with it's parent target.

  • modular: a flag to prevent .js files from being wrapped with a module definition.

  • before, after, afterEach: hooks for modifying the build process

  • bootstrap: a flag to specify that the entry-point .js module should be lazily evaluated (default value is true, triggering evaluation on load. Set to false if you want to lazily evaluate by calling require('myModule') manually).

  • label: an arbitrary name to use for matching when using the --grep subcommand

Hooks

It is possible to intervene in the build process through the use of hooks. Hooks are assigned to specific targets and defined in the target configuration. There are three types available:

  • before: executed before a target is built

  • after: executed after a target is built

  • afterEach: executed after an output file is processed, but before it is written to disk

Hooks can be written as inline JavaScript, or loaded from a file if a path is specified:

{
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "somefile.js",
          "output": "somedir",
          "before": "console.log('before hook'); done();",
          "after": "path/to/afterHook.js"
        }
      ]
    }
  }
}

All hooks are passed the following arguments:

  • context: the target (before and after) or file (afterEach) instance

  • options: the runtime options used to execute buddy (compress, reload, watch, deploy, etc)

  • done: a callback function that accepts an optional error. MUST be called in order to return control back to the program.

Aliases

When writing universal modules for use in both server and browser environments, it is sometimes desirable to specify an alternative entrypoint for inclusion in the browser. The alternative to the main package.json parameter is browser:

{
  "name": "myModule",
  "version": "1.0.0",
  "main": "lib/server.js",
  "browser": "lib/browser.js"
}

buddy correctly handles this remapping when resolving npm dependencies that use the browser parameter. In addition, it is possible to employ more advanced uses to alias files and modules directly in your project:

{
  "browser": {
    "someModule": "node_modules/someModule/dist/someModule-with-addons.js"
  }
}

...or even disable a module completely when bundling for the browser:

{
  "browser": {
    "someModule": false
  }
}

Read more about the uses of browser here.

Unique filenames

Unique filenames can be automatically generated by including one of two types of token in the output filename:

  • %date%: inserts the current timestamp at the time of build
  • %hash%: inserts a hash of the file's content
{
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "somefile.js",
          "output": "somefile-%hash%.js"
        },
        {
          "input": "somefile.css",
          "output": "somefile-%date%.css"
        }
      ]
    }
  }
}

Environment variables

All references to process.env.* variables are automatically inlined in JS source files. In addition to all the system variables set before build, the following special variables are set during build:

  • RUNTIME: current runtime for browser code (value browser)
  • BUDDY_VERSION: current version number of buddy tool
  • BUDDY_{LABEL or INDEX}_INPUT: input filepath(s) for target identified with LABEL or INDEX (value filepath or filepath,filepath,... if multiple inputs)
  • BUDDY_{LABEL or INDEX}_INPUT_HASH: hash(es) of input file(s) for target identified with LABEL or INDEX (value xxxxxx or xxxxxx,xxxxxx,... if multiple inputs)
  • BUDDY_{LABEL or INDEX}_INPUT_DATE: timestamp(s) of input file(s) for target identified with LABEL or INDEX (value 000000 or 000000,000000,... if multiple inputs)
  • BUDDY_{LABEL or INDEX}_OUTPUT: output filepath(s) for target identified with LABEL or INDEX (value filepath or filepath,filepath,... if multiple outputs)
  • BUDDY_{LABEL or INDEX}_OUTPUT_HASH: hash(es) of output file(s) for target identified with LABEL or INDEX (value xxxxxx or xxxxxx,xxxxxx,... if multiple outputs)
  • BUDDY_{LABEL or INDEX}_OUTPUT_DATE: timestamp(s) of output file(s) for target identified with LABEL or INDEX (value 000000 or 000000,000000,... if multiple outputs)
{
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "src/index.js",
          "output": "www/index-%hash%.js",
          "label": "js"
        },
        {
          "input": "src/index.css",
          "output": "www/index-%hash%.css",
          "label": "css"
        },
        {
          "input": "src/service-worker.js",
          "output": "www",
          "label": "sw"
        }
      ]
    }
  }
}

The last target (labelled sw) will have access to the unique outputs of the previous targets:

  // service-worker.js
  const VERSION = process.env.BUDDY_SW_INPUT_HASH;
  const ASSET_JS = process.env.BUDDY_JS_OUTPUT;
  const ASSET_CSS = process.env.BUDDY_CSS_OUTPUT;

...which converts to:

  // service-worker.js
  const VERSION = 'c71a077b25a6ee790a4ce328fc4a0807';
  const ASSET_JS = 'www/index-03d534db2f963c0829b5115cef08fcce.js';
  const ASSET_CSS = 'www/index-cf4e0949af42961334452b1e11fe1cfd.css';

Server

When developing locally, the buddy-server add-on and buddy watch --serve command will start a simple webserver on localhost to test against. Adding the --reload flag will enable automatic reloading of connected browsers through a livereload plugin. Specifying a file path will start/restart a custom application server instead of the default development server.

Install the add-on alongside buddy, and see buddy-server for more details.

{
  "dependencies": {
    "buddy": "5.0.0",
    "buddy-server": "1.0.0"
  },
  "buddy": {
    "server": {
      "port": 8000,
      "file": "./index.js",
      "env": {
        "DEBUG": "*"
      }
    }
  }
}
$ buddy watch --serve --reload

Working with JS

Each JS file is wrapped in a module declaration based on the file's location. Dependencies are determined by the use of require() statements:

var lib = require('./my/lib'); // in current package
var SomeClass = require('../SomeClass'); // in parent package
var module = require('module'); // from node_modules

lib.doSomething();
var something = new SomeClass();
util.log('hey');

Specifying a module's public behaviour is achieved by decorating an exports object:

var myModuleVar = 'my module';

exports.myModuleMethod = function() {
  return myModuleVar;
};

...or overwriting the exports object completely:

function MyModule() {
  this.myVar = 'my instance var';
};

MyModule.prototype.myMethod = function() {
  return this.myVar;
};

module.exports = MyModule;

Each module is provided with a module, exports, and require reference.

When require()-ing a module, keep in mind that the module id is resolved based on the following rules:

  • packages begin at the root project directory, or those specified in build > sources: 'Users/alex/project/src/package/main.js' > 'src/package/main'
  • ids are case-sensitive: 'package/MyClass.js' > 'package/MyClass' (depends on platform)

See node.js modules for more info on modules.

EXAMPLES

Generate www/main.js by concatenating and modularizing all dependencies referenced by src/js/main.js, including modules installed via npm (from the node_modules directory):

{
  "name": "myProject",
  "version": "1.0.0",
  "devDependencies": {
    "buddy": "5.0.0"
  },
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "src/js/main.js",
          "output": "www"
        }
      ]
    }
  }
}
// src/main.js
var lodash = require('lodash') // npm module (node_modules/lodash)
  , view = require('./views/view') // src module (src/views/view.js);

Generate www/main.js and an additional widget www/widget.js using shared sources (avoiding duplicate dependencies):

{
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "src/js/main.js",
          "output": "www",
          "targets": [
            {
              "input": "src/js/widget.js",
              "output": "www"
            }
          ]
        }
      ]
    }
  }
}

Compile a directory of ES6 files for Node.js, skipping module wrapping and concatenation:

{
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "src/es6",
          "output": "js",
          "modular": false
        }
      ]
    }
  }
}

Alias a custom build of jquery:

{
  "browser": {
    "jquery": "libs/js/jquery-custom.js"
  },
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "src/js/main.js",
          "output": "www"
        }
      ]
    }
  }
}
var jquery = require('jquery');

Working with CSS

Like .js modules, .css dependencies are automatically resolved through parsing and inlining of @import directives. NOTE: unlike .js dependencies, .css dependencies are inlined, and may be inlined more than once if several @import directives point to the same file.

Examples

Generate www/main.css by concatenating all dependencies referenced in src/css/main.css:

{
  "buddy": {
    "build": {
      "targets": [
        {
          "input": "src/css/main.css",
          "output": "www"
        }
      ]
    }
  }
}

Working with HTML

When working with html or html templating languages (dust, handlebars, nunjucks, jade, etc), dependencies (partials, includes) are automatically resolved and registered before source files are compiled. In addition, files are parsed for inlineable js and css sources (those with an inline attribute).

Examples

Resolve template includes when compiling a handlebars template:

<!-- layout.handlebars depends on header.handlebars -->
{{> header}}
<body>
  ...
  <!-- ...and footer.handlebars -->
  {{> footer}}
</body>

Inline .js and .css source files with inline attribute (see inline-source):

<!-- project/src/html/index.html -->
<!DOCTYPE html>
<html>
<head>
  <!-- inline project/src/js/inlineScript.js -->
  <script inline src="../js/inlineScript.js"></script>
  <!-- inline project/src/css/inlineStyle.css -->
  <link inline href="../css/inlineStyle.css"></link>
</head>
</html>

Keywords

FAQs

Last updated on 29 Jun 2016

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc