Could not generate " +
280 | programUrl +
281 | "
" +
282 | err.message.replace(/'/g, "\\'") +
283 | "
');"
284 | );
285 | return;
286 | }
287 |
288 | // Send script
289 | console.log("Webmake OK (" + ((Date.now() - time) / 1000).toFixed(3) + "s)");
290 | res.end(content);
291 | });
292 | } else {
293 | // Serve static file
294 | staticServer.serve(req, res);
295 | }
296 | });
297 | }).listen(port);
298 | console.log("Server started");
299 | ```
300 |
301 | ### Using Webmake with Express or Connect
302 |
303 | See [webmake-middleware](https://github.com/gillesruppert/webmake-middleware) prepared by [Gilles Ruppert](http://latower.com/).
304 |
305 | ### Using Webmake with Grunt
306 |
307 | See [grunt-webmake](https://github.com/sakatam/grunt-webmake) prepared by [Sakata Makoto](https://github.com/sakatam).
308 |
309 | ### Working with other module systems
310 |
311 | When you work with old school scripts or framework that uses different modules system, then you'd rather just bundle needed utilities (not whole application) and expose them to global scope.
312 |
313 | #### Webassemble -> https://github.com/kenspirit/webassemble
314 |
315 | Webassemble written by [Ken Chen](https://github.com/kenspirit) provides a convinient way to expose different packages, written CJS style, to outer scripts. It automatically creates one entry package that does the job and is used as a starting point for a Webmake bundle.
316 |
317 | ### Extensions
318 |
319 | #### Extensions published on NPM
320 |
321 | ##### JS
322 |
323 | - **CoffeeScript - [webmake-coffee](https://github.com/medikoo/webmake-coffee)**
324 | - **handlebars - [webmake-handlebars](https://github.com/acdaniel/webmake-handlebars)**
325 | - **ejs - [webmake-ejs](https://github.com/tswaters/webmake-ejs)**
326 |
327 | ##### JSON
328 |
329 | - **YAML - [webmake-yaml](https://github.com/medikoo/webmake-yaml)**
330 |
331 | ##### CSS
332 |
333 | - **LESS - [webmake-less](https://github.com/acdaniel/webmake-less)**
334 | - **SASS - [webmake-sass](https://github.com/acdaniel/webmake-sass)**
335 |
336 | **Submit any missing extension via [new issue form](https://github.com/medikoo/modules-webmake/issues/new)**.
337 |
338 | #### Using extensions with Webmake
339 |
340 | Install chosen extension:
341 |
342 | _EXT should be replaced by name of available extension of your choice_.
343 |
344 | $ npm install webmake-EXT
345 |
346 | If you use global installation of Webmake, then extension also needs to be installed globally:
347 |
348 | $ npm install -g webmake-EXT
349 |
350 | When extension is installed, you need to ask Webmake to use it:
351 |
352 | $ webmake --ext=EXT program.js bundle.js
353 |
354 | Same way if used programmatically:
355 |
356 | ```javascript
357 | webmake(inputPath, { ext: "EXT" }, cb);
358 | ```
359 |
360 | Multiple extensions can be used together:
361 |
362 | $ webmake --ext=EXT --ext=EXT2 program.js bundle.js
363 |
364 | Programmatically:
365 |
366 | ```javascript
367 | webmake(inputPath, { ext: ["EXT", "EXT2"] }, cb);
368 | ```
369 |
370 | #### Writing an extension for a new format
371 |
372 | Prepare a `webmake-*` NPM package _(replace '\*' with name of your extension)_, where main module is configured as in following example:
373 |
374 | ```javascript
375 | // Define a file extension of a new format, can be an array e.g. ['sass', 'scss']
376 | exports.extension = "coffee";
377 |
378 | // Which type is addressed by extension (can be either 'js', 'json', 'css' or 'html')
379 | exports.type = "js";
380 |
381 | // Define a compile function, that for given source code, produces valid body of a JavaScript module:
382 | exports.compile = function (source, options) {
383 | // Return plain object, with compiled body assigned to `code` property.
384 | return { code: compile(source) };
385 |
386 | // If compilation for some reason is asynchronous then assign promise
387 | // (as produced by deferred library) which resolves with expected code body
388 | return { code: compileAsync(source) };
389 |
390 | // If custom format provides a way to calculate a source map and `sourceMap` options is on
391 | // it's nice to generate it:
392 | var data, map, code;
393 | if (options.sourceMap) {
394 | data = compile(source, { sourceMap: true });
395 |
396 | // Include original file in the map.
397 | map = JSON.parse(data.sourceMap);
398 | map.file = options.generatedFilename;
399 | map.sources = [options.localFilename];
400 | map.sourcesContent = [source];
401 | map = JSON.stringify(map);
402 |
403 | return { code: code, sourceMap: map };
404 | }
405 | };
406 | ```
407 |
408 | #### Providing extensions programmatically
409 |
410 | Extension doesn't need to be installed as package, you may pass it programmatically:
411 |
412 | ```javascript
413 | webmake(
414 | inputPath,
415 | {
416 | ext: {
417 | name: "coffee-script",
418 | extension: "coffee",
419 | type: "js",
420 | compile: function (source, options) {
421 | /* ... */
422 | }
423 | }
424 | },
425 | cb
426 | );
427 | ```
428 |
429 | See below [writing extensions](#writing-an-extension-for-a-new-format) section to see how to configure fully working extensions
430 |
431 | #### Writing extesions for either JSON, CSS or HTML
432 |
433 | Be sure to state the right type, and return string that reflects addressed format (not JavaScript code)
434 | e.g. extension for CSS:
435 |
436 | ```javascript
437 | exports.extension = "less";
438 | exports.type = "css";
439 | exports.compile = function (source, options) {
440 | return { code: compileToCSS(source) }; // `compileToCSS` returns plain CSS string
441 | };
442 | ```
443 |
444 | Publish it and refer to [Using extensions](#Using-extensions-with-webmake) section for usage instructions.
445 | Finally if everything works, please let me know, so I can update this document with link to your extension.
446 |
447 | ## Comparison with other solutions
448 |
449 | ### AMD
450 |
451 | AMD is different format, and although most popular loader for AMD is named [RequireJS](http://requirejs.org/) it works very differently from _require_ as introduced earlier with CommonJS (one that Webmake handles).
452 |
453 | Main idea behind AMD is that dependencies are resolved asynchronously (in contrary to synchronous resolution in case of CommonJS format). Sounds promising, but does it really make things better? Cause of waterfall nature of resolution and large number of HTTP requests not necessary. See [benchmark](https://github.com/medikoo/cjs-vs-amd-benchmark#compare-load-times-of-two-module-systems) that compares resolution speed of both formats when used in development mode.
454 |
455 | Agreed advantage of AMD that attributes to its success is that in it's direct form works in a browser (it doesn't require any server setup), that is hard to achieve with CJS style (but [not impossible](https://github.com/creationix/chrome-app-module-loader)). Still due to large number of requests such approach is usually not suitable for production and it appears it's also [not that performant in development mode](https://github.com/medikoo/cjs-vs-amd-benchmark#compare-load-times-of-two-module-systems).
456 |
457 | Quirks of AMD style is that it requires you to wrap all your modules with function wrappers, its modules are not runnable in direct form in Node.js and dependency resolution rules are basic and limited if you compare it with design of node.js + npm ecosystem.
458 |
459 | ### Browserify and other CJS bundlers
460 |
461 | [Browserify](http://browserify.org/) is most popular CJS bundler, and shares very similar idea. The subtle difference is that Browserify is about porting code as written for node.js to web browser, so apart of resolving dependencies and bundling the code it struggles to bring what is needed and possible from Node.js API to the browser.
462 |
463 | Webmake cares only about bringing node.js modules format to other environments. Conceptually it's addition to ECMAScript and not port of node.js to browser. It makes node.js modules format runnable in any environment that speaks at least ECMAScript 3. You can bundle with Webmake for Browser, TV, Adobe Photoshop or maybe a modern dishwasher.
464 |
465 | When comparing with other CJS bundlers, main difference would be that Webmake completely follows resolution logic as it works in node.js. It resolves both packages and modules exactly as node.js, and it doesn't introduce any different ways to do that. Thanks to that, you can be sure that your modules are runnable in it's direct form both on server and client-side.
466 |
467 | Other important difference is that Webmake doesn't do full AST scan to parse require's out of modules, it relies on [find-requires](https://github.com/medikoo/find-requires#find-requires--find-all-require-calls) module, which does only what's necessary to resolve dependencies list, and that makes it a noticeably faster solution.
468 |
469 | ### ES6 modules
470 |
471 | Soon to be released, native JavaScript modules spec shares the main concept with CommmonJS. Thanks to that eventual transition will be easy and can be fully automated. First [transpilers](http://square.github.io/es6-module-transpiler/) are already here.
472 |
473 | As soon as the standard will be finalized, implemented in first engines and possibly adapted by node.js Webmake will support it natively as well, then in a same way it will bundle it either for the sake of a bundle or for any ECMAScript 3+ environment that won't take it in natural way.
474 |
475 | ## Current limitations of Webmake
476 |
477 | The application calculates dependencies via static analysis of source code
478 | (with the help of the [find-requires][] module). So in some edge cases
479 | not all require calls can be found. You can workaround that with help
480 | of [`include` option](#include-stringarray)
481 |
482 | Only relative paths and outer packages paths are supported, following will work:
483 |
484 | ```javascript
485 | require("./module-in-same-folder");
486 | require("./module/path/deeper");
487 | require("./some/very/very/very/long" + "/module/path");
488 | require("../../module-path-up"); // unless it doesn't go out of package scope
489 | require("other-package");
490 | require("other-package/lib/some-module");
491 | ```
492 |
493 | But this won't:
494 |
495 | ```javascript
496 | require("/Users/foo/projects/awesome/my-module");
497 | ```
498 |
499 | Different versions of same package will collide:
500 | 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.
501 |
502 | ## Tests
503 |
504 | $ npm test
505 |
506 | ## Proud list of SPONSORS!
507 |
508 | #### [@puzrin](https://github.com/puzrin) (Vitaly Puzrin) member of [Nodeca](https://github.com/nodeca)
509 |
510 | Vitaly pushed forward development of support for _JSON_ files, [extensions functionality](#extensions), along with [webmake-yaml](https://github.com/medikoo/webmake-yaml) extension. Vitaly is a member of a team that is behind [js-yaml](https://github.com/nodeca/js-yaml) JavaScript YAML parser and dumper, and powerful social platform [Nodeca](http://dev.nodeca.com/). Big Thank You Vitaly!
511 |
512 | ## Contributors
513 |
514 | - [@Phoscur](https://github.com/Phoscur) (Justus Maier)
515 | - Help with source map feature
516 | - [@jaap3](https://github.com/jaap3) (Jaap Roes)
517 | - Documentation quality improvements
518 |
519 | [slides]: http://www.slideshare.net/medikoo/javascript-modules-done-right "JavaScript Modules Done Right on SlideShare"
520 | [source maps]: http://pmuellr.blogspot.com/2011/11/debugging-concatenated-javascript-files.html "Debugging concatenated JavaScript files"
521 |
522 | [firebug issue]:
523 | http://code.google.com/p/fbug/issues/detail?id=2198
524 | 'Issue 2198: @sourceURL doesn't work in eval() in some cases'
525 |
526 | [find-requires]: https://github.com/medikoo/find-requires "find-requires: Find all require() calls"
527 | [node-static]: https://github.com/cloudhead/node-static "HTTP static-file server module"
528 | [nix-build-image]: https://semaphoreci.com/api/v1/medikoo-org/modules-webmake/branches/master/shields_badge.svg
529 | [nix-build-url]: https://semaphoreci.com/medikoo-org/modules-webmake
530 | [win-build-image]: https://ci.appveyor.com/api/projects/status/16c6u5cafarb3yo0?svg=true
531 | [win-build-url]: https://ci.appveyor.com/project/medikoo/modules-webmake
532 | [cov-image]: https://img.shields.io/codecov/c/github/medikoo/modules-webmake.svg
533 | [cov-url]: https://codecov.io/gh/medikoo/modules-webmake
534 | [transpilation-image]: https://img.shields.io/badge/transpilation-free-brightgreen.svg
535 | [npm-image]: https://img.shields.io/npm/v/webmake.svg
536 | [npm-url]: https://www.npmjs.com/package/webmake
537 |
--------------------------------------------------------------------------------
/bin/webmake.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | "use strict";
4 |
5 | require("log-node")({ defaultNamespace: "webmake" });
6 |
7 | const count = require("es5-ext/object/count")
8 | , { resolve } = require("path")
9 | , log = require("log").get("webmake")
10 | , webmake = require("..");
11 |
12 | const { isArray } = Array, { now } = Date;
13 |
14 | const optimist = require("optimist").usage("Usage: $0 [options] [