Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Bundle CommonJS/Node.js modules for web browser

This branch is 0 commits ahead and 0 commits behind master

Fetching latest commit…

Cannot retrieve the latest commit at this time

README.md

modules-webmake

Bundle CommonJS/Node.js modules for web browsers.

Webmake allows you to organize JavaScript code for the browser the same way as you would for Node.js.

For a more in depth look into JavaScript modules and the reason for Webmake, see the slides from my presentation at Warsaw's MeetJS:

JavaScript Modules Done Right

How does it work?

Let's say in package named foo you have following individual module files:

add.js

module.exports = function() {
  var sum = 0, i = 0, args = arguments, l = args.length;
  while (i < l) sum += args[i++];
  return sum;
};

increment.js

var add = require('./add');
module.exports = function(val) {
  return add(val, 1);
};

program.js

var inc = require('./increment');
var a = 1;
inc(a); // 2

Let's pack program.js with all it's dependencies so it will work in browsers:

$ webmake program.js build.js

The generated file build.js now contains the following:

(function (modules) {
  // about 60 lines of import/export path resolution logic
}) ({
  "foo": {
    "add.js": function (exports, module, require) {
      module.exports = function () {
        var sum = 0, i = 0, args = arguments, l = args.length;
        while (i < l) sum += args[i++];
        return sum;
      };
    },
    "increment.js": function (exports, module, require) {
      var add = require('./add');
      module.exports = function (val) {
        return add(val, 1);
      };
    },
    "program.js": function (exports, module, require) {
      var inc = require('./increment');
      var a = 1;
     inc(a); // 2
    }
  }
})
("foo/program");

When loaded in browser, program.js is immediately executed.

Installation

$ npm install -g webmake

Usage

From the shell:

$ webmake <input> <output>

input is the path to the initial module that should be executed when script is loaded.
output is the path to which the bundled browser ready code is written.

Additionally you may output modules with source maps, for easier debugging.

$ webmake --sourcemap <input> <output>

Source maps work very well in WebKit and Chrome's web inspector. Firefox's Firebug however has some issues.

Development with Webmake

Currently best way is to use Webmake programmatically and setup a static-file server to generate bundle on each request. Webmake is fast, so it's acceptable approach even you bundle hundreds of modules at once.

You can setup simple static server as it's shown in following example script.
It uses also node-static module to serve other static files (CSS, images etc.) if you don't want it, just adjust code up to your needs.

// Dependencies:
var createServer = require('http').createServer;
var staticServer = require('node-static').Server;
var webmake      = require('webmake');

// Settings:
// Project path:
var projectPath  = '/Users/open-web-user/Projects/Awesome';
// Public folder path (statics)
var staticsPath  = projectPath + '/public';
// Path to js program file
var programPath = projectPath + '/lib/public/main.js';
// Server port:
var port = 8000;
// Url at which we want to serve generated js file
var programUrl = '/j/main.js';

// Setup statics server
staticServer = new staticServer(staticsPath);

// Initialize http server
createServer(function (req, res) {
  // Respond to request
  req.on('end', function () {
    if (req.url === programUrl) {
      // Generate bundle with Webmake

      // Send headers
      res.writeHead(200, {
        'Content-Type': 'application/javascript; charset=utf-8',
        // Do not cache generated bundle
        'Cache-Control': 'no-cache'
      });

      var time = Date.now();
      webmake(programPath, { sourceMap: true }, function (err, content) {
        if (err) {
          console.error("Webmake error: " + err.message);
          // Expose eventual error brutally in browser
          res.end('document.write(\'<div style="font-size: 1.6em; padding: 1em;'
            + ' text-align: left; font-weight: bold; color: red;'
            + ' position: absolute; top: 1em; left: 10%; width: 80%;'
            + ' background: white; background: rgba(255,255,255,0.9);'
            + ' border: 1px solid #ccc;"><div>Could not generate ' + programUrl
            + '</div><div style="font-size: 0.8em; padding-top: 1em">'
            + err.message.replace(/'/g, '\\\'') + '</div></div>\');');
          return;
        }

        // Send script
        console.log("Webmake OK (" + ((Date.now() - time)/1000).toFixed(3) + "s)");
        res.end(content);
      });
    } else {
      // Serve static file
      staticServer.serve(req, res);
    }
  });
}).listen(port);
console.log("Server started");

Options

webmake(inputPath[, options], callback);
output string

Path of output file, if you want Webmake to create one

include string|Array

Additional module(s) that need to be included (but due specific reasons can't be picked by parser).

sourceMap boolean

Include source maps.

Limitations

The application calculates dependencies via static analysis of source code (with the help of the find-requires module). So in some edge cases not all require calls can be found. You can workaround that with help of include option

Only relative paths and outer packages paths are supported, following will work:

require('./module-in-same-folder');
require('./module/path/deeper');
require('./some/very/very/very/long' +
'/module/path');
require('../../module-path-up'); // unless it goes out of package scope
require('other-package');
require('other-package/lib/some-module');

But this won't:

require('/Users/foo/projects/awesome/my-module');

Different versions of same package will collide:
Let's say, package A uses version 0.2 of package C and package B uses version 0.3 of the same package. If both package A and B are required, package B will most likely end up buggy. This is because webmake will only bundle the version that was called first. So in this case package B will end up with version 0.2 instead of 0.3.

Tests Build Status

$ npm test

Contributors

  • @Phoscur (Justus Maier)
    • Help with source map feature
  • @jaap3 (Jaap Roes)
    • Documentation quality improvements
Something went wrong with that request. Please try again.