├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bin └── commonize ├── lib ├── cache.js ├── commoner.js ├── context.js ├── grep.js ├── output.js ├── reader.js ├── relative.js ├── util.js └── watcher.js ├── main.js ├── package.json └── test ├── debug.conf ├── release.conf ├── run.js └── source ├── assert.js ├── core.js ├── home.js ├── login.js ├── roots.json ├── schema.json ├── settings.js ├── tests ├── home.js ├── login.js └── settings.js ├── third-party.js └── widget ├── .bogus.js ├── bogus.js~ ├── common.js ├── follow.js ├── gallery.js └── share.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test/output 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.11" 4 | - "0.10" 5 | - "0.8" 6 | before_install: 7 | - npm install -g npm@2.1.10 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Ben Newman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | - - - 2 | 3 | **_This project is not actively maintained. Proceed at your own risk!_** 4 | 5 | - - - 6 | 7 | Commoner [![Build Status](https://travis-ci.org/reactjs/commoner.png?branch=master)](https://travis-ci.org/reactjs/commoner) 8 | --- 9 | 10 | Commoner makes it easy to write scripts that flexibly and efficiently 11 | transpile any dialect of JavaScript into a directory structure of 12 | Node-compatible CommonJS module files. 13 | 14 | This task is made possible by 15 | 16 | 1. a declarative syntax for defining how module source code should be 17 | found and processed, 18 | 2. the use of [promises](https://github.com/kriskowal/q) to manage an 19 | asynchronous build pipeline, and 20 | 3. never rebuilding modules that have already been built. 21 | 22 | The output files can be required seamlessly by Node, or served by any 23 | static file server, or bundled together using a tool such as 24 | [Browserify](https://github.com/substack/node-browserify), 25 | [WrapUp](https://github.com/kamicane/wrapup), or 26 | [Stitch](https://github.com/sstephenson/stitch) for delivery to a web 27 | browser. 28 | 29 | If you pass the `--relativize` option, Commoner also takes care to rewrite 30 | all `require` calls to use [relative module 31 | identifiers](http://wiki.commonjs.org/wiki/Modules/1.1#Module_Identifiers), 32 | so that the output files can be installed into any subdirectory of a 33 | larger project, and external tools do not have to give special treatment 34 | to top-level modules (or even know which modules are top-level and which 35 | are nested). 36 | 37 | Commoner was derived from an earlier, more opinionated tool called 38 | [Brigade](https://github.com/benjamn/brigade) that provided additional 39 | support for packaging modules together into multiple non-overlapping 40 | bundles. Commoner grew out of the realization that many tools already 41 | exist for bundling CommonJS modules, but that fewer tools focus on getting 42 | to that point. 43 | 44 | Installation 45 | --- 46 | 47 | From NPM: 48 | 49 | npm install commoner 50 | 51 | From GitHub: 52 | 53 | cd path/to/node_modules 54 | git clone git://github.com/reactjs/commoner.git 55 | cd commoner 56 | npm install . 57 | 58 | Usage 59 | --- 60 | 61 | Here's the output of `bin/commonize --help`: 62 | ``` 63 | Usage: commonize [options] [ [ ...]] 64 | 65 | Options: 66 | 67 | -h, --help output usage information 68 | -V, --version output the version number 69 | -c, --config [file] JSON configuration file (no file means STDIN) 70 | -w, --watch Continually rebuild 71 | -x, --extension File extension to assume when resolving module identifiers 72 | --relativize Rewrite all module identifiers to be relative 73 | --follow-requires Scan modules for required dependencies 74 | --cache-dir Alternate directory to use for disk cache 75 | --no-cache-dir Disable the disk cache 76 | --source-charset Charset of source (default: utf8) 77 | --output-charset Charset of output (default: utf8) 78 | ``` 79 | 80 | In a single sentence: the `commonize` command finds modules with the given 81 | module identifiers in the source directory and places a processed copy of 82 | each module into the output directory, along with processed copies of all 83 | required modules. 84 | 85 | If you do not provide any module identifiers, `commonize` will process all 86 | files that it can find under the source directory that have the preferred 87 | file extension (`.js` by default). If your source files have a file 88 | extension other than `.js`, use the `-x` or `--extension` option to 89 | specify it. For example, `--extension coffee` to find `.coffee` files. 90 | 91 | Output 92 | --- 93 | 94 | Commoner prints various status messages to `STDERR`, so that you can see 95 | what it's doing, or figure out why it's not doing what you thought it 96 | would do. 97 | 98 | The only information it prints to `STDOUT` is a JSON array of module 99 | identifiers, which includes the identifiers passed on the command line and 100 | all their dependencies. This array contains no duplicates. 101 | 102 | Internally, each module that Commoner generates has a hash computed from 103 | the module's identifier, source code, and processing steps. Since this 104 | hash can be computed before processing takes place, Commoner is able to 105 | avoid processing a module if it has ever previously processed the same 106 | module in the same way. 107 | 108 | If you dig into [the 109 | code](https://github.com/reactjs/commoner/blob/5e7f65cab2/lib/context.js#L94), 110 | you'll find that Commoner maintains a cache directory (by default, 111 | `~/.commoner/module-cache/`) containing files with names like 112 | `9ffc5c853aac07bc106da1dc1b2486903ca688bf.js`. When Commoner is about to 113 | process a module, it checks its hash against the file names in this 114 | directory. If no match is found, processing procedes and the resulting 115 | file is written to the cache directory with a new hash. If the appropriate 116 | hash file is already present in the cache directory, however, Commoner 117 | merely creates a hard link between the hash file and a file with a more 118 | meaningful name in the output directory. 119 | 120 | When you pass the `--watch` flag to `bin/commonize`, Commoner avoids 121 | exiting after the first build and instead watches for changes to 122 | previously read files, printing a new JSON array of module identifiers to 123 | `STDOUT` each time rebuilding finishes. Thanks to the caching of processed 124 | modules, the time taken to rebuild is roughly proportional to the number 125 | of modified files. 126 | 127 | Customization 128 | --- 129 | 130 | The `bin/commonize` script is actually quite simple, and you can write 131 | similar scripts yourself. Let's have a look: 132 | ```js 133 | #!/usr/bin/env node 134 | 135 | require("commoner").resolve(function(id) { 136 | var context = this; 137 | 138 | return context.getProvidedP().then(function(idToPath) { 139 | // If a module declares its own identifier using @providesModule 140 | // then that identifier will be a key in the idToPath object. 141 | if (idToPath.hasOwnProperty(id)) 142 | return context.readFileP(idToPath[id]); 143 | }); 144 | 145 | }, function(id) { 146 | // Otherwise assume the identifier maps directly to a filesystem path. 147 | // The readModuleP method simply appends the preferred file extension 148 | // (usually .js) to the given module identifier and opens that file. 149 | return this.readModuleP(id); 150 | }); 151 | ``` 152 | The scriptable interface of the `commoner` module abstracts away many of 153 | the annoyances of writing a command-line script. In particular, you don't 154 | have to do any parsing of command-line arguments, and you don't have to 155 | worry about installing any dependencies other than `commoner` in your 156 | `$NODE_PATH`. 157 | 158 | What you are responsible for, at a minimum, is telling Commoner how to 159 | find the source of a module given a module identifier, and you do this by 160 | passing callback functions to `require("commoner").resolve`. The script 161 | above uses two strategies that will be tried in sequence: first, it calls 162 | the helper function `this.getProvidedP` to retrieve an object mapping 163 | identifiers to file paths (more about this below); and, if that doesn't 164 | work, it falls back to interpreting the identifier as a path relative to 165 | the source directory. 166 | 167 | Now, you might not care about `this.getProvidedP`. It's really just a 168 | proof of concept that Commoner can support modules that declare their own 169 | identifiers using the `// @providesModule ` syntax, and I 170 | included it by default because it doesn't make a difference unless you 171 | decide to use `@providesModule`. If you don't like it, you could write an 172 | even simpler script: 173 | ```js 174 | #!/usr/bin/env node 175 | 176 | require("commoner").resolve(function(id) { 177 | return this.readModuleP(id); 178 | }); 179 | ``` 180 | The point is, it's entirely up to you to define how module identifiers are 181 | interpreted. In fact, the source you return doesn't even have to be valid 182 | JavaScript. It could be [CoffeeScript](http://coffeescript.org/), or 183 | [LESS](http://lesscss.org/), or whatever language you prefer to write by 184 | hand. Commoner doesn't care what your source code looks like, because 185 | Commoner allows you to define arbitrary build steps to turn that source 186 | code into plain old CommonJS. 187 | 188 | Let's consider the example of using LESS to write dynamic CSS 189 | modules. First, let's apply what we already know to give special meaning 190 | to `.less` files: 191 | ```js 192 | #!/usr/bin/env node 193 | 194 | require("commoner").resolve(function(id) { 195 | if (isLess(id)) 196 | return this.readFileP(id); 197 | }, function(id) { 198 | return this.readModuleP(id); 199 | }); 200 | 201 | function isLess(id) { 202 | return /\.less$/i.test(id); 203 | } 204 | ``` 205 | All this really accomplishes is to avoid appending the `.js` file 206 | extension to identifiers that already have the `.less` extension. 207 | 208 | Now we need to make sure the contents of `.less` files somehow get 209 | transformed into plain old CommonJS, and for that we need 210 | `require("commoner").process`: 211 | ```js 212 | require("commoner").resolve(function(id) { 213 | if (isLess(id)) 214 | return this.readFileP(id); 215 | }, function(id) { 216 | return this.readModuleP(id); 217 | }).process(function(id, source) { 218 | if (isLess(id)) 219 | return compileLessToJs(source); 220 | return source; 221 | }); 222 | ``` 223 | How should `compileLessToJs` be implemented? At a high level, I propose 224 | that we generate a CommonJS module that will append a new `