├── .gitignore ├── .npmignore ├── .npmrc ├── .travis.yml ├── LICENSE ├── bin └── cmd.js ├── example ├── compiler-pipeline │ ├── bundle.js │ ├── package.json │ └── src │ │ ├── bar.js │ │ ├── foo.js │ │ └── main.js └── hmr │ ├── main.js │ ├── msg.js │ ├── package.json │ └── public │ └── index.html ├── package.json └── readme.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | hmr/node_modules 2 | hmr/public/bundle.js 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | - "lts/*" 5 | - "4" 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution 3.0 Unported 2 | 3 | License 4 | 5 | THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS 6 | PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR 7 | OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS 8 | LICENSE OR COPYRIGHT LAW IS PROHIBITED. 9 | 10 | BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE 11 | BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED 12 | TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN 13 | CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 14 | 15 | 1. Definitions 16 | 17 | "Adaptation" means a work based upon the Work, or upon the Work and other 18 | pre-existing works, such as a translation, adaptation, derivative work, 19 | arrangement of music or other alterations of a literary or artistic work, or 20 | phonogram or performance and includes cinematographic adaptations or any other 21 | form in which the Work may be recast, transformed, or adapted including in any 22 | form recognizably derived from the original, except that a work that constitutes 23 | a Collection will not be considered an Adaptation for the purpose of this 24 | License. For the avoidance of doubt, where the Work is a musical work, 25 | performance or phonogram, the synchronization of the Work in timed-relation with 26 | a moving image ("synching") will be considered an Adaptation for the purpose of 27 | this License. "Collection" means a collection of literary or artistic works, 28 | such as encyclopedias and anthologies, or performances, phonograms or 29 | broadcasts, or other works or subject matter other than works listed in Section 30 | 1(f) below, which, by reason of the selection and arrangement of their contents, 31 | constitute intellectual creations, in which the Work is included in its entirety 32 | in unmodified form along with one or more other contributions, each constituting 33 | separate and independent works in themselves, which together are assembled into 34 | a collective whole. A work that constitutes a Collection will not be considered 35 | an Adaptation (as defined above) for the purposes of this License. "Distribute" 36 | means to make available to the public the original and copies of the Work or 37 | Adaptation, as appropriate, through sale or other transfer of ownership. 38 | "Licensor" means the individual, individuals, entity or entities that offer(s) 39 | the Work under the terms of this License. "Original Author" means, in the case 40 | of a literary or artistic work, the individual, individuals, entity or entities 41 | who created the Work or if no individual or entity can be identified, the 42 | publisher; and in addition (i) in the case of a performance the actors, singers, 43 | musicians, dancers, and other persons who act, sing, deliver, declaim, play in, 44 | interpret or otherwise perform literary or artistic works or expressions of 45 | folklore; (ii) in the case of a phonogram the producer being the person or legal 46 | entity who first fixes the sounds of a performance or other sounds; and, (iii) 47 | in the case of broadcasts, the organization that transmits the broadcast. "Work" 48 | means the literary and/or artistic work offered under the terms of this License 49 | including without limitation any production in the literary, scientific and 50 | artistic domain, whatever may be the mode or form of its expression including 51 | digital form, such as a book, pamphlet and other writing; a lecture, address, 52 | sermon or other work of the same nature; a dramatic or dramatico-musical work; a 53 | choreographic work or entertainment in dumb show; a musical composition with or 54 | without words; a cinematographic work to which are assimilated works expressed 55 | by a process analogous to cinematography; a work of drawing, painting, 56 | architecture, sculpture, engraving or lithography; a photographic work to which 57 | are assimilated works expressed by a process analogous to photography; a work of 58 | applied art; an illustration, map, plan, sketch or three-dimensional work 59 | relative to geography, topography, architecture or science; a performance; a 60 | broadcast; a phonogram; a compilation of data to the extent it is protected as a 61 | copyrightable work; or a work performed by a variety or circus performer to the 62 | extent it is not otherwise considered a literary or artistic work. "You" means 63 | an individual or entity exercising rights under this License who has not 64 | previously violated the terms of this License with respect to the Work, or who 65 | has received express permission from the Licensor to exercise rights under this 66 | License despite a previous violation. "Publicly Perform" means to perform public 67 | recitations of the Work and to communicate to the public those public 68 | recitations, by any means or process, including by wire or wireless means or 69 | public digital performances; to make available to the public Works in such a way 70 | that members of the public may access these Works from a place and at a place 71 | individually chosen by them; to perform the Work to the public by any means or 72 | process and the communication to the public of the performances of the Work, 73 | including by public digital performance; to broadcast and rebroadcast the Work 74 | by any means including signs, sounds or images. "Reproduce" means to make copies 75 | of the Work by any means including without limitation by sound or visual 76 | recordings and the right of fixation and reproducing fixations of the Work, 77 | including storage of a protected performance or phonogram in digital form or 78 | other electronic medium. 2. Fair Dealing Rights. Nothing in this License is 79 | intended to reduce, limit, or restrict any uses free from copyright or rights 80 | arising from limitations or exceptions that are provided for in connection with 81 | the copyright protection under copyright law or other applicable laws. 82 | 83 | 3. License Grant. Subject to the terms and conditions of this License, Licensor 84 | hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the 85 | duration of the applicable copyright) license to exercise the rights in the Work 86 | as stated below: 87 | 88 | to Reproduce the Work, to incorporate the Work into one or more Collections, and 89 | to Reproduce the Work as incorporated in the Collections; to create and 90 | Reproduce Adaptations provided that any such Adaptation, including any 91 | translation in any medium, takes reasonable steps to clearly label, demarcate or 92 | otherwise identify that changes were made to the original Work. For example, a 93 | translation could be marked "The original work was translated from English to 94 | Spanish," or a modification could indicate "The original work has been 95 | modified."; to Distribute and Publicly Perform the Work including as 96 | incorporated in Collections; and, to Distribute and Publicly Perform 97 | Adaptations. For the avoidance of doubt: 98 | 99 | Non-waivable Compulsory License Schemes. In those jurisdictions in which the 100 | right to collect royalties through any statutory or compulsory licensing scheme 101 | cannot be waived, the Licensor reserves the exclusive right to collect such 102 | royalties for any exercise by You of the rights granted under this License; 103 | Waivable Compulsory License Schemes. In those jurisdictions in which the right 104 | to collect royalties through any statutory or compulsory licensing scheme can be 105 | waived, the Licensor waives the exclusive right to collect such royalties for 106 | any exercise by You of the rights granted under this License; and, Voluntary 107 | License Schemes. The Licensor waives the right to collect royalties, whether 108 | individually or, in the event that the Licensor is a member of a collecting 109 | society that administers voluntary licensing schemes, via that society, from any 110 | exercise by You of the rights granted under this License. The above rights may 111 | be exercised in all media and formats whether now known or hereafter devised. 112 | The above rights include the right to make such modifications as are technically 113 | necessary to exercise the rights in other media and formats. Subject to Section 114 | 8(f), all rights not expressly granted by Licensor are hereby reserved. 115 | 116 | 4. Restrictions. The license granted in Section 3 above is expressly made 117 | subject to and limited by the following restrictions: 118 | 119 | You may Distribute or Publicly Perform the Work only under the terms of this 120 | License. You must include a copy of, or the Uniform Resource Identifier (URI) 121 | for, this License with every copy of the Work You Distribute or Publicly 122 | Perform. You may not offer or impose any terms on the Work that restrict the 123 | terms of this License or the ability of the recipient of the Work to exercise 124 | the rights granted to that recipient under the terms of the License. You may not 125 | sublicense the Work. You must keep intact all notices that refer to this License 126 | and to the disclaimer of warranties with every copy of the Work You Distribute 127 | or Publicly Perform. When You Distribute or Publicly Perform the Work, You may 128 | not impose any effective technological measures on the Work that restrict the 129 | ability of a recipient of the Work from You to exercise the rights granted to 130 | that recipient under the terms of the License. This Section 4(a) applies to the 131 | Work as incorporated in a Collection, but this does not require the Collection 132 | apart from the Work itself to be made subject to the terms of this License. If 133 | You create a Collection, upon notice from any Licensor You must, to the extent 134 | practicable, remove from the Collection any credit as required by Section 4(b), 135 | as requested. If You create an Adaptation, upon notice from any Licensor You 136 | must, to the extent practicable, remove from the Adaptation any credit as 137 | required by Section 4(b), as requested. If You Distribute, or Publicly Perform 138 | the Work or any Adaptations or Collections, You must, unless a request has been 139 | made pursuant to Section 4(a), keep intact all copyright notices for the Work 140 | and provide, reasonable to the medium or means You are utilizing: (i) the name 141 | of the Original Author (or pseudonym, if applicable) if supplied, and/or if the 142 | Original Author and/or Licensor designate another party or parties (e.g., a 143 | sponsor institute, publishing entity, journal) for attribution ("Attribution 144 | Parties") in Licensor's copyright notice, terms of service or by other 145 | reasonable means, the name of such party or parties; (ii) the title of the Work 146 | if supplied; (iii) to the extent reasonably practicable, the URI, if any, that 147 | Licensor specifies to be associated with the Work, unless such URI does not 148 | refer to the copyright notice or licensing information for the Work; and (iv) , 149 | consistent with Section 3(b), in the case of an Adaptation, a credit identifying 150 | the use of the Work in the Adaptation (e.g., "French translation of the Work by 151 | Original Author," or "Screenplay based on original Work by Original Author"). 152 | The credit required by this Section 4 (b) may be implemented in any reasonable 153 | manner; provided, however, that in the case of a Adaptation or Collection, at a 154 | minimum such credit will appear, if a credit for all contributing authors of the 155 | Adaptation or Collection appears, then as part of these credits and in a manner 156 | at least as prominent as the credits for the other contributing authors. For the 157 | avoidance of doubt, You may only use the credit required by this Section for the 158 | purpose of attribution in the manner set out above and, by exercising Your 159 | rights under this License, You may not implicitly or explicitly assert or imply 160 | any connection with, sponsorship or endorsement by the Original Author, Licensor 161 | and/or Attribution Parties, as appropriate, of You or Your use of the Work, 162 | without the separate, express prior written permission of the Original Author, 163 | Licensor and/or Attribution Parties. Except as otherwise agreed in writing by 164 | the Licensor or as may be otherwise permitted by applicable law, if You 165 | Reproduce, Distribute or Publicly Perform the Work either by itself or as part 166 | of any Adaptations or Collections, You must not distort, mutilate, modify or 167 | take other derogatory action in relation to the Work which would be prejudicial 168 | to the Original Author's honor or reputation. Licensor agrees that in those 169 | jurisdictions (e.g. Japan), in which any exercise of the right granted in 170 | Section 3(b) of this License (the right to make Adaptations) would be deemed to 171 | be a distortion, mutilation, modification or other derogatory action prejudicial 172 | to the Original Author's honor and reputation, the Licensor will waive or not 173 | assert, as appropriate, this Section, to the fullest extent permitted by the 174 | applicable national law, to enable You to reasonably exercise Your right under 175 | Section 3(b) of this License (right to make Adaptations) but not otherwise. 5. 176 | Representations, Warranties and Disclaimer 177 | 178 | UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS 179 | THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING 180 | THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT 181 | LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR 182 | PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, 183 | OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME 184 | JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH 185 | EXCLUSION MAY NOT APPLY TO YOU. 186 | 187 | 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN 188 | NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, 189 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS 190 | LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE 191 | POSSIBILITY OF SUCH DAMAGES. 192 | 193 | 7. Termination 194 | 195 | This License and the rights granted hereunder will terminate automatically upon 196 | any breach by You of the terms of this License. Individuals or entities who have 197 | received Adaptations or Collections from You under this License, however, will 198 | not have their licenses terminated provided such individuals or entities remain 199 | in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will 200 | survive any termination of this License. Subject to the above terms and 201 | conditions, the license granted here is perpetual (for the duration of the 202 | applicable copyright in the Work). Notwithstanding the above, Licensor reserves 203 | the right to release the Work under different license terms or to stop 204 | distributing the Work at any time; provided, however that any such election will 205 | not serve to withdraw this License (or any other license that has been, or is 206 | required to be, granted under the terms of this License), and this License will 207 | continue in full force and effect unless terminated as stated above. 8. 208 | Miscellaneous 209 | 210 | Each time You Distribute or Publicly Perform the Work or a Collection, the 211 | Licensor offers to the recipient a license to the Work on the same terms and 212 | conditions as the license granted to You under this License. Each time You 213 | Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a 214 | license to the original Work on the same terms and conditions as the license 215 | granted to You under this License. If any provision of this License is invalid 216 | or unenforceable under applicable law, it shall not affect the validity or 217 | enforceability of the remainder of the terms of this License, and without 218 | further action by the parties to this agreement, such provision shall be 219 | reformed to the minimum extent necessary to make such provision valid and 220 | enforceable. No term or provision of this License shall be deemed waived and no 221 | breach consented to unless such waiver or consent shall be in writing and signed 222 | by the party to be charged with such waiver or consent. This License constitutes 223 | the entire agreement between the parties with respect to the Work licensed here. 224 | There are no understandings, agreements or representations with respect to the 225 | Work not specified here. Licensor shall not be bound by any additional 226 | provisions that may appear in any communication from You. This License may not 227 | be modified without the mutual written agreement of the Licensor and You. The 228 | rights granted under, and the subject matter referenced, in this License were 229 | drafted utilizing the terminology of the Berne Convention for the Protection of 230 | Literary and Artistic Works (as amended on September 28, 1979), the Rome 231 | Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and 232 | Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on 233 | July 24, 1971). These rights and subject matter take effect in the relevant 234 | jurisdiction in which the License terms are sought to be enforced according to 235 | the corresponding provisions of the implementation of those treaty provisions in 236 | the applicable national law. If the standard suite of rights granted under 237 | applicable copyright law includes additional rights not granted under this 238 | License, such additional rights are deemed to be included in the License; this 239 | License is not intended to restrict the license of any rights under applicable 240 | law. Creative Commons Notice 241 | 242 | Creative Commons is not a party to this License, and makes no warranty 243 | whatsoever in connection with the Work. Creative Commons will not be liable to 244 | You or any party on any legal theory for any damages whatsoever, including 245 | without limitation any general, special, incidental or consequential damages 246 | arising in connection to this license. Notwithstanding the foregoing two (2) 247 | sentences, if Creative Commons has expressly identified itself as the Licensor 248 | hereunder, it shall have all rights and obligations of Licensor. 249 | 250 | Except for the limited purpose of indicating to the public that the Work is 251 | licensed under the CCPL, Creative Commons does not authorize the use by either 252 | party of the trademark "Creative Commons" or any related trademark or logo of 253 | Creative Commons without the prior written consent of Creative Commons. Any 254 | permitted use will be in compliance with Creative Commons' then-current 255 | trademark usage guidelines, as may be published on its website or otherwise made 256 | available upon request from time to time. For the avoidance of doubt, this 257 | trademark restriction does not form part of this License. 258 | 259 | Creative Commons may be contacted at http://creativecommons.org/. -------------------------------------------------------------------------------- /bin/cmd.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var fs = require('fs'); 4 | var pager = require('default-pager'); 5 | var through = require('through2'); 6 | var duplexer = require('duplexer2'); 7 | var concat = require('concat-stream'); 8 | var marked = require('marked'); 9 | var MarkedTerminal = require('marked-terminal'); 10 | 11 | marked.setOptions({ 12 | renderer: new MarkedTerminal() 13 | }); 14 | 15 | var moutput = through(); 16 | var minput = concat({ encoding: 'string' }, function (res) { 17 | moutput.end(marked(res)); 18 | }); 19 | var markdown = duplexer(minput, moutput); 20 | 21 | fs.createReadStream(__dirname + '/../readme.markdown') 22 | .pipe(markdown) 23 | .pipe(pager()); 24 | -------------------------------------------------------------------------------- /example/compiler-pipeline/bundle.js: -------------------------------------------------------------------------------- 1 | var browserify = require('browserify'); 2 | var through = require('through2'); 3 | var shasum = require('shasum'); 4 | 5 | var b = browserify(__dirname + '/src/main.js'); 6 | 7 | var hashes = {}; 8 | var hasher = through.obj(function (row, enc, next) { 9 | hashes[row.id] = shasum(row.source); 10 | this.push(row); 11 | next(); 12 | }); 13 | b.pipeline.get('deps').push(hasher); 14 | 15 | var labeler = through.obj(function (row, enc, next) { 16 | row.id = hashes[row.id]; 17 | 18 | Object.keys(row.deps).forEach(function (key) { 19 | row.deps[key] = hashes[row.deps[key]]; 20 | }); 21 | 22 | this.push(row); 23 | next(); 24 | }); 25 | b.pipeline.get('label').splice(0, 1, labeler); 26 | 27 | b.bundle().pipe(process.stdout); 28 | -------------------------------------------------------------------------------- /example/compiler-pipeline/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "browserify": "^16.2.3", 4 | "shasum": "^1.0.0", 5 | "through2": "^3.0.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /example/compiler-pipeline/src/bar.js: -------------------------------------------------------------------------------- 1 | module.exports = function (n) { return n * 100 }; 2 | -------------------------------------------------------------------------------- /example/compiler-pipeline/src/foo.js: -------------------------------------------------------------------------------- 1 | module.exports = function (n) { return n + 1 }; 2 | -------------------------------------------------------------------------------- /example/compiler-pipeline/src/main.js: -------------------------------------------------------------------------------- 1 | var foo = require('./foo.js'); 2 | var bar = require('./bar.js'); 3 | 4 | console.log(foo(3) + bar(4)); 5 | -------------------------------------------------------------------------------- /example/hmr/main.js: -------------------------------------------------------------------------------- 1 | document.body.textContent = require('./msg.js') 2 | 3 | if (module.hot) module.hot.accept() 4 | -------------------------------------------------------------------------------- /example/hmr/msg.js: -------------------------------------------------------------------------------- 1 | module.exports = 'cool' 2 | -------------------------------------------------------------------------------- /example/hmr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browserify-hmr-example", 3 | "dependencies": { 4 | "browserify-hmr": "^0.4.1", 5 | "http-server": "^0.11.1", 6 | "watchify": "^3.9.0" 7 | }, 8 | "scripts": { 9 | "watch": "watchify -p browserify-hmr main.js -o public/bundle.js -dv", 10 | "build": "browserify main.js > public/bundle.js", 11 | "www": "http-server -p 8000 public", 12 | "start": "npm run www & npm run watch" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /example/hmr/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browserify-handbook", 3 | "description": "how to build modular applications with browserify", 4 | "version": "1.9.0", 5 | "author": { 6 | "name": "James Halliday", 7 | "email": "mail@substack.net", 8 | "url": "http://substack.net" 9 | }, 10 | "bin": { 11 | "browserify-handbook": "bin/cmd.js" 12 | }, 13 | "dependencies": { 14 | "concat-stream": "^1.6.2", 15 | "default-pager": "^1.0.1", 16 | "duplexer2": "^0.1.4", 17 | "marked": "^0.6.2", 18 | "marked-terminal": "^3.2.0", 19 | "through2": "^2.0.0" 20 | }, 21 | "engines": { 22 | "node": ">= 4" 23 | }, 24 | "homepage": "https://github.com/browserify/browserify-handbook", 25 | "bugs": "https://github.com/browserify/browserify-handbook/issues", 26 | "keywords": [ 27 | "browserify", 28 | "documentation", 29 | "guide", 30 | "handbook" 31 | ], 32 | "license": "CC-BY-3.0", 33 | "repository": { 34 | "type": "git", 35 | "url": "git://github.com/browserify/browserify-handbook.git" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # introduction 2 | 3 | This document covers how to use [browserify](http://browserify.org) to build 4 | modular applications. 5 | 6 | [![cc-by-3.0](http://i.creativecommons.org/l/by/3.0/80x15.png)](http://creativecommons.org/licenses/by/3.0/) 7 | 8 | browserify is a tool for compiling 9 | [node-flavored](http://nodejs.org/docs/latest/api/modules.html) commonjs modules 10 | for the browser. 11 | 12 | You can use browserify to organize your code and use third-party libraries even 13 | if you don't use [node](http://nodejs.org) itself in any other capacity except 14 | for bundling and installing packages with npm. 15 | 16 | The module system that browserify uses is the same as node, so 17 | packages published to [npm](https://npmjs.org) that were originally intended for 18 | use in node but not browsers will work just fine in the browser too. 19 | 20 | Increasingly, people are publishing modules to npm which are intentionally 21 | designed to work in both node and in the browser using browserify and many 22 | packages on npm are intended for use in just the browser. 23 | [npm is for all javascript](http://maxogden.com/node-packaged-modules.html), 24 | front or backend alike. 25 | 26 | # table of contents 27 | 28 | - [introduction](#introduction) 29 | - [table of contents](#table-of-contents) 30 | - [node packaged manuscript](#node-packaged-manuscript) 31 | - [node packaged modules](#node-packaged-modules) 32 | - [require](#require) 33 | - [exports](#exports) 34 | - [bundling for the browser](#bundling-for-the-browser) 35 | - [how browserify works](#how-browserify-works) 36 | - [how node_modules works](#how-node_modules-works) 37 | - [why concatenate](#why-concatenate) 38 | - [development](#development) 39 | - [source maps](#source-maps) 40 | - [exorcist](#exorcist) 41 | - [auto-recompile](#auto-recompile) 42 | - [watchify](#watchify) 43 | - [beefy](#beefy) 44 | - [wzrd](#wzrd) 45 | - [browserify-middleware, enchilada](#browserify-middleware-enchilada) 46 | - [livereactload](#livereactload) 47 | - [browserify-hmr](#browserify-hmr) 48 | - [budo](#budo) 49 | - [using the api directly](#using-the-api-directly) 50 | - [grunt](#grunt) 51 | - [gulp](#gulp) 52 | - [builtins](#builtins) 53 | - [Buffer](#Buffer) 54 | - [process](#process) 55 | - [global](#global) 56 | - [__filename](#__filename) 57 | - [__dirname](#__dirname) 58 | - [transforms](#transforms) 59 | - [writing your own](#writing-your-own) 60 | - [package.json](#packagejson) 61 | - [browser field](#browser-field) 62 | - [browserify.transform field](#browserifytransform-field) 63 | - [finding good modules](#finding-good-modules) 64 | - [module philosophy](#module-philosophy) 65 | - [organizing modules](#organizing-modules) 66 | - [avoiding ../../../../../../..](#avoiding-) 67 | - [non-javascript assets](#non-javascript-assets) 68 | - [reusable components](#reusable-components) 69 | - [testing in node and the browser](#testing-in-node-and-the-browser) 70 | - [testing libraries](#testing-libraries) 71 | - [code coverage](#code-coverage) 72 | - [testling-ci](#testling-ci) 73 | - [bundling](#bundling) 74 | - [saving bytes](#saving-bytes) 75 | - [tinyify](#tinyify) 76 | - [standalone](#standalone) 77 | - [external bundles](#external-bundles) 78 | - [ignoring and excluding](#ignoring-and-excluding) 79 | - [browserify cdn](#browserify-cdn) 80 | - [shimming](#shimming) 81 | - [browserify-shim](#browserify-shim) 82 | - [partitioning](#partitioning) 83 | - [factor-bundle](#factor-bundle) 84 | - [partition-bundle](#partition-bundle) 85 | - [compiler pipeline](#compiler-pipeline) 86 | - [build your own browserify](#build-your-own-browserify) 87 | - [labeled phases](#labeled-phases) 88 | - [deps](#deps) 89 | - [json](#json) 90 | - [unbom](#unbom) 91 | - [syntax](#syntax) 92 | - [sort](#sort) 93 | - [dedupe](#dedupe) 94 | - [label](#label) 95 | - [emit-deps](#emit-deps) 96 | - [debug](#debug) 97 | - [pack](#pack) 98 | - [wrap](#wrap) 99 | - [browser-unpack](#browser-unpack) 100 | - [plugins](#plugins) 101 | - [using plugins](#using-plugins) 102 | - [authoring plugins](#authoring-plugins) 103 | 104 | # node packaged manuscript 105 | 106 | You can install this handbook with npm, appropriately enough. Just do: 107 | 108 | ``` 109 | npm install -g browserify-handbook 110 | ``` 111 | 112 | Now you will have a `browserify-handbook` command that will open this readme 113 | file in your `$PAGER`. Otherwise, you may continue reading this document as you 114 | are presently doing. 115 | 116 | # node packaged modules 117 | 118 | Before we can dive too deeply into how to use browserify and how it works, it is 119 | important to first understand how the 120 | [node-flavored version](http://nodejs.org/docs/latest/api/modules.html) 121 | of the commonjs module system works. 122 | 123 | ## require 124 | 125 | In node, there is a `require()` function for loading code from other files. 126 | 127 | If you install a module with [npm](https://npmjs.org): 128 | 129 | ``` 130 | npm install uniq 131 | ``` 132 | 133 | Then in a file `nums.js` we can `require('uniq')`: 134 | 135 | ``` 136 | var uniq = require('uniq'); 137 | var nums = [ 5, 2, 1, 3, 2, 5, 4, 2, 0, 1 ]; 138 | console.log(uniq(nums)); 139 | ``` 140 | 141 | The output of this program when run with node is: 142 | 143 | ``` 144 | $ node nums.js 145 | [ 0, 1, 2, 3, 4, 5 ] 146 | ``` 147 | 148 | You can require relative files by requiring a string that starts with a `.`. For 149 | example, to load a file `foo.js` from `main.js`, in `main.js` you can do: 150 | 151 | ``` js 152 | var foo = require('./foo.js'); 153 | console.log(foo(4)); 154 | ``` 155 | 156 | If `foo.js` was in the parent directory, you could use `../foo.js` instead: 157 | 158 | ``` js 159 | var foo = require('../foo.js'); 160 | console.log(foo(4)); 161 | ``` 162 | 163 | or likewise for any other kind of relative path. Relative paths are always 164 | resolved with respect to the invoking file's location. 165 | 166 | Note that `require()` returned a function and we assigned that return value to a 167 | variable called `uniq`. We could have picked any other name and it would have 168 | worked the same. `require()` returns the exports of the module name that you 169 | specify. 170 | 171 | How `require()` works is unlike many other module systems where imports are akin 172 | to statements that expose themselves as globals or file-local lexicals with 173 | names declared in the module itself outside of your control. Under the node 174 | style of code import with `require()`, someone reading your program can easily 175 | tell where each piece of functionality came from. This approach scales much 176 | better as the number of modules in an application grows. 177 | 178 | ## exports 179 | 180 | To export a single thing from a file so that other files may import it, assign 181 | over the value at `module.exports`: 182 | 183 | ``` js 184 | module.exports = function (n) { 185 | return n * 111 186 | }; 187 | ``` 188 | 189 | Now when some module `main.js` loads your `foo.js`, the return value of 190 | `require('./foo.js')` will be the exported function: 191 | 192 | ``` js 193 | var foo = require('./foo.js'); 194 | console.log(foo(5)); 195 | ``` 196 | 197 | This program will print: 198 | 199 | ``` 200 | 555 201 | ``` 202 | 203 | You can export any kind of value with `module.exports`, not just functions. 204 | 205 | For example, this is perfectly fine: 206 | 207 | ``` js 208 | module.exports = 555 209 | ``` 210 | 211 | and so is this: 212 | 213 | ``` js 214 | var numbers = []; 215 | for (var i = 0; i < 100; i++) numbers.push(i); 216 | 217 | module.exports = numbers; 218 | ``` 219 | 220 | There is another form of doing exports specifically for exporting items onto an 221 | object. Here, `exports` is used instead of `module.exports`: 222 | 223 | ``` js 224 | exports.beep = function (n) { return n * 1000 } 225 | exports.boop = 555 226 | ``` 227 | 228 | This program is the same as: 229 | 230 | ``` js 231 | module.exports.beep = function (n) { return n * 1000 } 232 | module.exports.boop = 555 233 | ``` 234 | 235 | because `module.exports` is the same as `exports` and is initially set to an 236 | empty object. 237 | 238 | Note however that you can't do: 239 | 240 | ``` js 241 | // this doesn't work 242 | exports = function (n) { return n * 1000 } 243 | ``` 244 | 245 | because the export value lives on the `module` object, and so assigning a new 246 | value for `exports` instead of `module.exports` masks the original reference. 247 | 248 | Instead if you are going to export a single item, always do: 249 | 250 | ``` js 251 | // instead 252 | module.exports = function (n) { return n * 1000 } 253 | ``` 254 | 255 | If you're still confused, try to understand how modules work in 256 | the background: 257 | 258 | ``` js 259 | var module = { 260 | exports: {} 261 | }; 262 | 263 | // If you require a module, it's basically wrapped in a function 264 | (function(module, exports) { 265 | exports = function (n) { return n * 1000 }; 266 | }(module, module.exports)) 267 | 268 | console.log(module.exports); // it's still an empty object :( 269 | ``` 270 | 271 | Most of the time, you will want to export a single function or constructor with 272 | `module.exports` because it's usually best for a module to do one thing. 273 | 274 | The `exports` feature was originally the primary way of exporting functionality 275 | and `module.exports` was an afterthought, but `module.exports` proved to be much 276 | more useful in practice at being more direct, clear, and avoiding duplication. 277 | 278 | In the early days, this style used to be much more common: 279 | 280 | foo.js: 281 | 282 | ``` js 283 | exports.foo = function (n) { return n * 111 } 284 | ``` 285 | 286 | main.js: 287 | 288 | ``` js 289 | var foo = require('./foo.js'); 290 | console.log(foo.foo(5)); 291 | ``` 292 | 293 | but note that the `foo.foo` is a bit superfluous. Using `module.exports` it 294 | becomes more clear: 295 | 296 | foo.js: 297 | 298 | ``` js 299 | module.exports = function (n) { return n * 111 } 300 | ``` 301 | 302 | main.js: 303 | 304 | ``` js 305 | var foo = require('./foo.js'); 306 | console.log(foo(5)); 307 | ``` 308 | 309 | ## bundling for the browser 310 | 311 | To run a module in node, you've got to start from somewhere. 312 | 313 | In node you pass a file to the `node` command to run a file: 314 | 315 | ``` 316 | $ node robot.js 317 | beep boop 318 | ``` 319 | 320 | In browserify, you do this same thing, but instead of running the file, you 321 | generate a stream of concatenated javascript files on stdout that you can write 322 | to a file with the `>` operator: 323 | 324 | ``` 325 | $ browserify robot.js > bundle.js 326 | ``` 327 | 328 | Now `bundle.js` contains all the javascript that `robot.js` needs to work. 329 | Just plop it into a single script tag in some html: 330 | 331 | ``` html 332 | 333 | 334 | 335 | 336 | 337 | ``` 338 | 339 | Bonus: if you put your script tag right before the ``, you can use all of 340 | the dom elements on the page without waiting for a dom onready event. 341 | 342 | There are many more things you can do with bundling. Check out the bundling 343 | section elsewhere in this document. 344 | 345 | ## how browserify works 346 | 347 | Browserify starts at the entry point files that you give it and searches for any 348 | `require()` calls it finds using 349 | [static analysis](http://npmjs.org/package/detective) 350 | of the source code's 351 | [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree). 352 | 353 | For every `require()` call with a string in it, browserify resolves those module 354 | strings to file paths and then searches those file paths for `require()` calls 355 | recursively until the entire dependency graph is visited. 356 | 357 | Each file is concatenated into a single javascript file with a minimal 358 | `require()` definition that maps the statically-resolved names to internal IDs. 359 | 360 | This means that the bundle you generate is completely self-contained and has 361 | everything your application needs to work with a pretty negligible overhead. 362 | 363 | Note: If your `require()` contains anything other than a string literal (i.e. a variable) then it cannot be read at time of bundling, so the module being required will not be concatenated into your bundle and likely cause a runtime error. 364 | 365 | For more details about how browserify works, check out the compiler pipeline 366 | section of this document. 367 | 368 | ## how node_modules works 369 | 370 | node has a clever algorithm for resolving modules that is unique among rival 371 | platforms. 372 | 373 | Instead of resolving packages from an array of system search paths like how 374 | `$PATH` works on the command line, node's mechanism is local by default. 375 | 376 | If you `require('./foo.js')` from `/beep/boop/bar.js`, node will 377 | look for `foo.js` in `/beep/boop`. Paths that start with a `./` or 378 | `../` are always local to the file that calls `require()`. 379 | 380 | If however you require a non-relative name such as `require('xyz')` from 381 | `/beep/boop/foo.js`, node searches these paths in order, stopping at the first 382 | match and raising an error if nothing is found: 383 | 384 | ``` 385 | /beep/boop/node_modules/xyz 386 | /beep/node_modules/xyz 387 | /node_modules/xyz 388 | ``` 389 | 390 | For each `xyz` directory that exists, node will first look for an 391 | `xyz/package.json` to see if a `"main"` field exists. The `"main"` field defines 392 | which file should take charge if you `require()` the directory path. 393 | 394 | For example, if `/beep/node_modules/xyz` is the first match and 395 | `/beep/node_modules/xyz/package.json` has: 396 | 397 | ``` 398 | { 399 | "name": "xyz", 400 | "version": "1.2.3", 401 | "main": "lib/abc.js" 402 | } 403 | ``` 404 | 405 | then the exports from `/beep/node_modules/xyz/lib/abc.js` will be returned by 406 | `require('xyz')`. 407 | 408 | If there is no `package.json` or no `"main"` field, `index.js` is assumed: 409 | 410 | ``` 411 | /beep/node_modules/xyz/index.js 412 | ``` 413 | 414 | If you need to, you can reach into a package to pick out a particular file. For 415 | example, to load the `lib/clone.js` file from the `dat` package, just do: 416 | 417 | ``` 418 | var clone = require('dat/lib/clone.js') 419 | ``` 420 | 421 | The recursive node_modules resolution will find the first `dat` package up the 422 | directory hierarchy, then the `lib/clone.js` file will be resolved from there. 423 | This `require('dat/lib/clone.js')` approach will work from any location where 424 | you can `require('dat')`. 425 | 426 | node also has a mechanism for searching an array of paths, but this mechanism is 427 | deprecated and you should be using `node_modules/` unless you have a very good 428 | reason not to. 429 | 430 | The great thing about node's algorithm and how npm installs packages is that you 431 | can never have a version conflict, unlike almost every other platform. npm 432 | installs the dependencies of each package into `node_modules`. 433 | 434 | Each library gets its own local `node_modules/` directory where its dependencies 435 | are stored and each dependency's dependencies has its own `node_modules/` 436 | directory, recursively all the way down. 437 | 438 | This means that packages can successfully use different versions of libraries in 439 | the same application, which greatly decreases the coordination overhead 440 | necessary to iterate on APIs. This feature is very important for an ecosystem 441 | like npm where there is no central authority to manage how packages are 442 | published and organized. Everyone may simply publish as they see fit and not 443 | worry about how their dependency version choices might impact other dependencies 444 | included in the same application. 445 | 446 | You can leverage how `node_modules/` works to organize your own local 447 | application modules too. See the `avoiding ../../../../../../..` section for 448 | more. 449 | 450 | ## why concatenate 451 | 452 | Browserify is a build step that you can run before deploying your code. It 453 | generates a single bundle file that has everything in it. 454 | 455 | Here are some other ways of implementing module systems for the browser and what 456 | their strengths and weaknesses are: 457 | 458 | ### window globals 459 | 460 | Instead of a module system, each file defines properties on the window global 461 | object or develops an internal namespacing scheme. 462 | 463 | This approach does not scale well without extreme diligence since each new file 464 | needs an additional ` 1665 | ``` 1666 | 1667 | and load that html in a browser. The output will be in the debug console which 1668 | you can open with F12, ctrl-shift-j, or ctrl-shift-k depending on the browser. 1669 | 1670 | This is a bit cumbersome to run our tests in a browser, but you can install the 1671 | `testling` command to help. First do: 1672 | 1673 | ``` 1674 | npm install -g testling 1675 | ``` 1676 | 1677 | And now just do `browserify test/beep.js | testling`: 1678 | 1679 | ``` 1680 | $ browserify test/beep.js | testling 1681 | 1682 | TAP version 13 1683 | # beep 1684 | ok 1 5*100 === 500 1685 | 1686 | 1..1 1687 | # tests 1 1688 | # pass 1 1689 | 1690 | # ok 1691 | ``` 1692 | 1693 | `testling` will launch a real browser headlessly on your system to run the tests. 1694 | 1695 | Now suppose we want to add another file, `test/boop.js`: 1696 | 1697 | ``` js 1698 | var test = require('tape'); 1699 | var hundreder = require('../'); 1700 | 1701 | test('fraction', function (t) { 1702 | t.plan(1); 1703 | 1704 | hundreder(1/20, function (n) { 1705 | t.equal(n, 5, '1/20th of 100'); 1706 | }); 1707 | }); 1708 | 1709 | test('negative', function (t) { 1710 | t.plan(1); 1711 | 1712 | hundreder(-3, function (n) { 1713 | t.equal(n, -300, 'negative number'); 1714 | }); 1715 | }); 1716 | ``` 1717 | 1718 | Here our test has 2 `test()` blocks. The second test block won't start to 1719 | execute until the first is completely finished, even though it is asynchronous. 1720 | You can even nest test blocks by using `t.test()`. 1721 | 1722 | We can run `test/boop.js` with node directly as with `test/beep.js`, but if we 1723 | want to run both tests, there is a minimal command-runner we can use that comes 1724 | with tape. To get the `tape` command do: 1725 | 1726 | ``` 1727 | npm install -g tape 1728 | ``` 1729 | 1730 | and now you can run: 1731 | 1732 | ``` 1733 | $ tape test/*.js 1734 | TAP version 13 1735 | # beep 1736 | ok 1 5*100 === 500 1737 | # fraction 1738 | ok 2 1/20th of 100 1739 | # negative 1740 | ok 3 negative number 1741 | 1742 | 1..3 1743 | # tests 3 1744 | # pass 3 1745 | 1746 | # ok 1747 | ``` 1748 | 1749 | and you can just pass `test/*.js` to browserify to run your tests in the 1750 | browser: 1751 | 1752 | ``` 1753 | $ browserify test/* | testling 1754 | 1755 | TAP version 13 1756 | # beep 1757 | ok 1 5*100 === 500 1758 | # fraction 1759 | ok 2 1/20th of 100 1760 | # negative 1761 | ok 3 negative number 1762 | 1763 | 1..3 1764 | # tests 3 1765 | # pass 3 1766 | 1767 | # ok 1768 | ``` 1769 | 1770 | Putting together all these steps, we can configure `package.json` with a test 1771 | script: 1772 | 1773 | ``` json 1774 | { 1775 | "name": "hundreder", 1776 | "version": "1.0.0", 1777 | "main": "index.js", 1778 | "devDependencies": { 1779 | "tape": "^2.13.1", 1780 | "testling": "^1.6.1" 1781 | }, 1782 | "scripts": { 1783 | "test": "tape test/*.js", 1784 | "test-browser": "browserify test/*.js | testlingify" 1785 | } 1786 | } 1787 | ``` 1788 | 1789 | Now you can do `npm test` to run the tests in node and `npm run test-browser` to 1790 | run the tests in the browser. You don't need to worry about installing commands 1791 | with `-g` when you use `npm run`: npm automatically sets up the `$PATH` for all 1792 | packages installed locally to the project. 1793 | 1794 | If you have some tests that only run in node and some tests that only run in the 1795 | browser, you could have subdirectories in `test/` such as `test/server` and 1796 | `test/browser` with the tests that run both places just in `test/`. Then you 1797 | could just add the relevant directory to the globs: 1798 | 1799 | ``` json 1800 | { 1801 | "name": "hundreder", 1802 | "version": "1.0.0", 1803 | "main": "index.js", 1804 | "devDependencies": { 1805 | "tape": "^2.13.1", 1806 | "testling": "^1.6.1" 1807 | }, 1808 | "scripts": { 1809 | "test": "tape test/*.js test/server/*.js", 1810 | "test-browser": "browserify test/*.js test/browser/*.js | testling" 1811 | } 1812 | } 1813 | ``` 1814 | 1815 | and now server-specific and browser-specific tests will be run in addition to 1816 | the common tests. 1817 | 1818 | If you want something even slicker, check out 1819 | [prova](https://www.npmjs.org/package/prova) once you have gotten the basic 1820 | concepts. 1821 | 1822 | ### assert 1823 | 1824 | The core assert module is a fine way to write simple tests too, although it can 1825 | sometimes be tricky to ensure that the correct number of callbacks have fired. 1826 | 1827 | You can solve that problem with tools like 1828 | [macgyver](https://www.npmjs.org/package/macgyver) but it is appropriately DIY. 1829 | 1830 | ## code coverage 1831 | 1832 | ### coverify 1833 | 1834 | A simple way to check code coverage in browserify is to use the 1835 | [coverify](https://npmjs.org/package/coverify) transform. 1836 | 1837 | ``` 1838 | $ browserify -t coverify test/*.js | node | coverify 1839 | ``` 1840 | 1841 | or to run your tests in a real browser: 1842 | 1843 | ``` 1844 | $ browserify -t coverify test/*.js | testling | coverify 1845 | ``` 1846 | 1847 | coverify works by transforming the source of each package so that each 1848 | expression is wrapped in a `__coverageWrap()` function. 1849 | 1850 | Each expression in the program gets a unique ID and the `__coverageWrap()` 1851 | function will print `COVERED $FILE $ID` the first time the expression is 1852 | executed. 1853 | 1854 | Before the expressions run, coverify prints a `COVERAGE $FILE $NODES` message to 1855 | log the expression nodes across the entire file as character ranges. 1856 | 1857 | Here's what the output of a full run looks like: 1858 | 1859 | ``` 1860 | $ browserify -t coverify test/whatever.js | node 1861 | COVERAGE "/home/substack/projects/defined/test/whatever.js" [[14,28],[14,28],[0,29],[41,56],[41,56],[30,57],[95,104],[95,105],[126,146],[126,146],[115,147],[160,194],[160,194],[152,195],[200,217],[200,218],[76,220],[59,221],[59,222]] 1862 | COVERED "/home/substack/projects/defined/test/whatever.js" 2 1863 | COVERED "/home/substack/projects/defined/test/whatever.js" 1 1864 | COVERED "/home/substack/projects/defined/test/whatever.js" 0 1865 | COVERAGE "/home/substack/projects/defined/index.js" [[48,49],[55,71],[51,71],[73,76],[92,104],[92,118],[127,139],[120,140],[172,195],[172,196],[0,204],[0,205]] 1866 | COVERED "/home/substack/projects/defined/index.js" 11 1867 | COVERED "/home/substack/projects/defined/index.js" 10 1868 | COVERED "/home/substack/projects/defined/test/whatever.js" 5 1869 | COVERED "/home/substack/projects/defined/test/whatever.js" 4 1870 | COVERED "/home/substack/projects/defined/test/whatever.js" 3 1871 | COVERED "/home/substack/projects/defined/test/whatever.js" 18 1872 | COVERED "/home/substack/projects/defined/test/whatever.js" 17 1873 | COVERED "/home/substack/projects/defined/test/whatever.js" 16 1874 | TAP version 13 1875 | # whatever 1876 | COVERED "/home/substack/projects/defined/test/whatever.js" 7 1877 | COVERED "/home/substack/projects/defined/test/whatever.js" 6 1878 | COVERED "/home/substack/projects/defined/test/whatever.js" 10 1879 | COVERED "/home/substack/projects/defined/test/whatever.js" 9 1880 | COVERED "/home/substack/projects/defined/test/whatever.js" 8 1881 | COVERED "/home/substack/projects/defined/test/whatever.js" 13 1882 | COVERED "/home/substack/projects/defined/test/whatever.js" 12 1883 | COVERED "/home/substack/projects/defined/test/whatever.js" 11 1884 | COVERED "/home/substack/projects/defined/index.js" 0 1885 | COVERED "/home/substack/projects/defined/index.js" 2 1886 | COVERED "/home/substack/projects/defined/index.js" 1 1887 | COVERED "/home/substack/projects/defined/index.js" 5 1888 | COVERED "/home/substack/projects/defined/index.js" 4 1889 | COVERED "/home/substack/projects/defined/index.js" 3 1890 | COVERED "/home/substack/projects/defined/index.js" 7 1891 | COVERED "/home/substack/projects/defined/index.js" 6 1892 | COVERED "/home/substack/projects/defined/test/whatever.js" 15 1893 | COVERED "/home/substack/projects/defined/test/whatever.js" 14 1894 | ok 1 should be equal 1895 | 1896 | 1..1 1897 | # tests 1 1898 | # pass 1 1899 | 1900 | # ok 1901 | ``` 1902 | 1903 | These COVERED and COVERAGE statements are just printed on stdout and they can be 1904 | fed into the `coverify` command to generate prettier output: 1905 | 1906 | ``` 1907 | $ browserify -t coverify test/whatever.js | node | coverify 1908 | TAP version 13 1909 | # whatever 1910 | ok 1 should be equal 1911 | 1912 | 1..1 1913 | # tests 1 1914 | # pass 1 1915 | 1916 | # ok 1917 | 1918 | # /home/substack/projects/defined/index.js: line 6, column 9-32 1919 | 1920 | console.log('whatever'); 1921 | ^^^^^^^^^^^^^^^^^^^^^^^^ 1922 | 1923 | # coverage: 30/31 (96.77 %) 1924 | ``` 1925 | 1926 | To include code coverage into your project, you can add an entry into the 1927 | `package.json` scripts field: 1928 | 1929 | ``` json 1930 | { 1931 | "scripts": { 1932 | "test": "tape test/*.js", 1933 | "coverage": "browserify -t coverify test/*.js | node | coverify" 1934 | } 1935 | } 1936 | ``` 1937 | 1938 | There is also a [covert](https://npmjs.com/package/covert) package that 1939 | simplifies the browserify and coverify setup: 1940 | 1941 | ``` json 1942 | { 1943 | "scripts": { 1944 | "test": "tape test/*.js", 1945 | "coverage": "covert test/*.js" 1946 | } 1947 | } 1948 | ``` 1949 | 1950 | To install coverify or covert as a devDependency, run 1951 | `npm install -D coverify` or `npm install -D covert`. 1952 | 1953 | # bundling 1954 | 1955 | This section covers bundling in more detail. 1956 | 1957 | Bundling is the step where starting from the entry files, all the source files 1958 | in the dependency graph are walked and packed into a single output file. 1959 | 1960 | ## saving bytes 1961 | 1962 | One of the first things you'll want to tweak is how the files that npm installs 1963 | are placed on disk to avoid duplicates. 1964 | 1965 | When you do a clean install in a directory, npm will ordinarily factor out 1966 | similar versions into the topmost directory where 2 modules share a dependency. 1967 | However, as you install more packages, new packages will not be factored out 1968 | automatically. You can however use the `npm dedupe` command to factor out 1969 | packages for an already-installed set of packages in `node_modules/`. You could 1970 | also remove `node_modules/` and install from scratch again if problems with 1971 | duplicates persist. 1972 | 1973 | browserify will not include the same exact file twice, but compatible versions 1974 | may differ slightly. browserify is also not version-aware, it will include the 1975 | versions of packages exactly as they are laid out in `node_modules/` according 1976 | to the `require()` algorithm that node uses. 1977 | 1978 | You can use the `browserify --list` and `browserify --deps` commands to further 1979 | inspect which files are being included to scan for duplicates. 1980 | 1981 | ## tinyify 1982 | 1983 | You can use the [tinyify](https://github.com/browserify/tinyify) plugin to apply 1984 | a decent set of zero-config optimizations to your bundle. It will drastically 1985 | reduce output size. 1986 | 1987 | ``` 1988 | $ browserify foo.js --plugin tinyify > bundle.js 1989 | ``` 1990 | 1991 | tinyify includes [browser-pack-flat](https://github.com/goto-bus-stop/browser-pack-flat), 1992 | which does not follow the Node module loading behaviour as closely as the 1993 | default [browser-pack](https://github.com/browserify/browser-pack) does. If 1994 | there are timing issues in your tinyified bundle output, you can add the 1995 | `--no-flat` flag to revert to the default behaviour: 1996 | 1997 | ``` 1998 | $ browserify foo.js --plugin [ tinyify --no-flat ] > bundle.js 1999 | ``` 2000 | 2001 | All kinds of other optimizations will still be applied so you should still see 2002 | very significant bundle size wins. 2003 | 2004 | ## standalone 2005 | 2006 | You can generate UMD bundles with `--standalone` that will work in node, the 2007 | browser with globals, and AMD environments. 2008 | 2009 | Just add `--standalone NAME` to your bundle command: 2010 | 2011 | ``` 2012 | $ browserify foo.js --standalone xyz > bundle.js 2013 | ``` 2014 | 2015 | This command will export the contents of `foo.js` under the external module name 2016 | `xyz`. If a module system is detected in the host environment, it will be used. 2017 | Otherwise a window global named `xyz` will be exported. 2018 | 2019 | You can use dot-syntax to specify a namespace hierarchy: 2020 | 2021 | ``` 2022 | $ browserify foo.js --standalone foo.bar.baz > bundle.js 2023 | ``` 2024 | 2025 | If there is already a `foo` or a `foo.bar` in the host environment in window 2026 | global mode, browserify will attach its exports onto those objects. The AMD and 2027 | `module.exports` modules will behave the same. 2028 | 2029 | Note however that standalone only works with a single entry or directly-required 2030 | file. 2031 | 2032 | ## external bundles 2033 | 2034 | ## ignoring and excluding 2035 | 2036 | In browserify parlance, "ignore" means: replace the definition of a module with 2037 | an empty object. "exclude" means: remove a module completely from a dependency graph. 2038 | 2039 | Another way to achieve many of the same goals as ignore and exclude is the 2040 | "browser" field in package.json, which is covered elsewhere in this document. 2041 | 2042 | ### ignoring 2043 | 2044 | Ignoring is an optimistic strategy designed to stub in an empty definition for 2045 | node-specific modules that are only used in some code paths. For example, if a 2046 | module requires a library that only works in node but for a specific chunk of 2047 | the code: 2048 | 2049 | ``` js 2050 | var fs = require('fs'); 2051 | var path = require('path'); 2052 | var mkdirp = require('mkdirp'); 2053 | 2054 | exports.convert = convert; 2055 | function convert (src) { 2056 | return src.replace(/beep/g, 'boop'); 2057 | } 2058 | 2059 | exports.write = function (src, dst, cb) { 2060 | fs.readFile(src, function (err, src) { 2061 | if (err) return cb(err); 2062 | mkdirp(path.dirname(dst), function (err) { 2063 | if (err) return cb(err); 2064 | var out = convert(src); 2065 | fs.writeFile(dst, out, cb); 2066 | }); 2067 | }); 2068 | }; 2069 | ``` 2070 | 2071 | browserify already "ignores" the `'fs'` module by returning an empty object, but 2072 | the `.write()` function here won't work in the browser without an extra step like 2073 | a static analysis transform or a runtime storage fs abstraction. 2074 | 2075 | However, if we really want the `convert()` function but don't want to see 2076 | `mkdirp` in the final bundle, we can ignore mkdirp with `b.ignore('mkdirp')` or 2077 | `browserify --ignore mkdirp`. The code will still work in the browser if we 2078 | don't call `write()` because `require('mkdirp')` won't throw an exception, just 2079 | return an empty object. 2080 | 2081 | Generally speaking it's not a good idea for modules that are primarily 2082 | algorithmic (parsers, formatters) to do IO themselves but these tricks can let 2083 | you use those modules in the browser anyway. 2084 | 2085 | To ignore `foo` on the command-line do: 2086 | 2087 | ``` 2088 | browserify --ignore foo 2089 | ``` 2090 | 2091 | To ignore `foo` from the api with some bundle instance `b` do: 2092 | 2093 | ``` js 2094 | b.ignore('foo') 2095 | ``` 2096 | 2097 | ### excluding 2098 | 2099 | Another related thing we might want is to completely remove a module from the 2100 | output so that `require('modulename')` will fail at runtime. This is useful if 2101 | we want to split things up into multiple bundles that will defer in a cascade to 2102 | previously-defined `require()` definitions. 2103 | 2104 | For example, if we have a vendored standalone bundle for jquery that we don't want to appear in 2105 | the primary bundle: 2106 | 2107 | ``` 2108 | $ npm install jquery 2109 | $ browserify -r jquery > jquery-bundle.js 2110 | ``` 2111 | 2112 | then we want to just `require('jquery')` in a `main.js`: 2113 | 2114 | ``` js 2115 | var $ = require('jquery'); 2116 | $(window).click(function () { document.body.bgColor = 'red' }); 2117 | ``` 2118 | 2119 | defering to the jquery dist bundle so that we can write: 2120 | 2121 | ``` html 2122 | 2123 | 2124 | ``` 2125 | 2126 | and not have the jquery definition show up in `bundle.js`, then while compiling 2127 | the `main.js`, you can `--exclude jquery`: 2128 | 2129 | ``` 2130 | browserify main.js --exclude jquery > bundle.js 2131 | ``` 2132 | 2133 | To exclude `foo` on the command-line do: 2134 | 2135 | ``` 2136 | browserify --exclude foo 2137 | ``` 2138 | 2139 | To exclude `foo` from the api with some bundle instance `b` do: 2140 | 2141 | ``` js 2142 | b.exclude('foo') 2143 | ``` 2144 | 2145 | ## browserify cdn 2146 | 2147 | # shimming 2148 | 2149 | Unfortunately, some packages are not written with node-style commonjs exports. 2150 | For modules that export their functionality with globals or AMD, there are 2151 | packages that can help automatically convert these troublesome packages into 2152 | something that browserify can understand. 2153 | 2154 | ## browserify-shim 2155 | 2156 | One way to automatically convert non-commonjs packages is with 2157 | [browserify-shim](https://npmjs.org/package/browserify-shim). 2158 | 2159 | [browserify-shim](https://npmjs.org/package/browserify-shim) is loaded as a 2160 | transform and also reads a `"browserify-shim"` field from `package.json`. 2161 | 2162 | Suppose we need to use a troublesome third-party library we've placed in 2163 | `./vendor/foo.js` that exports its functionality as a window global called 2164 | `FOO`. We can set up our `package.json` with: 2165 | 2166 | ``` json 2167 | { 2168 | "browserify": { 2169 | "transform": "browserify-shim" 2170 | }, 2171 | "browserify-shim": { 2172 | "./vendor/foo.js": "FOO" 2173 | } 2174 | } 2175 | ``` 2176 | 2177 | and now when we `require('./vendor/foo.js')`, we get the `FOO` variable that 2178 | `./vendor/foo.js` tried to put into the global scope, but that attempt was 2179 | shimmed away into an isolated context to prevent global pollution. 2180 | 2181 | We could even use the [browser field](#browser-field) to make `require('foo')` 2182 | work instead of always needing to use a relative path to load `./vendor/foo.js`: 2183 | 2184 | ``` json 2185 | { 2186 | "browser": { 2187 | "foo": "./vendor/foo.js" 2188 | }, 2189 | "browserify": { 2190 | "transform": "browserify-shim" 2191 | }, 2192 | "browserify-shim": { 2193 | "foo": "FOO" 2194 | } 2195 | } 2196 | ``` 2197 | 2198 | Now `require('foo')` will return the `FOO` export that `./vendor/foo.js` tried 2199 | to place on the global scope. 2200 | 2201 | # partitioning 2202 | 2203 | Most of the time, the default method of bundling where one or more entry files 2204 | map to a single bundled output file is perfectly adequate, particularly 2205 | considering that bundling minimizes latency down to a single http request to 2206 | fetch all the javascript assets. 2207 | 2208 | However, sometimes this initial penalty is too high for parts of a website that 2209 | are rarely or never used by most visitors such as an admin panel. 2210 | This partitioning can be accomplished with the technique covered in the 2211 | [ignoring and excluding](#ignoring-and-excluding) section, but factoring out 2212 | shared dependencies manually can be tedious for a large and fluid dependency 2213 | graph. 2214 | 2215 | Luckily, there are plugins that can automatically factor browserify output into 2216 | separate bundle payloads. 2217 | 2218 | ## factor-bundle 2219 | 2220 | [factor-bundle](https://www.npmjs.org/package/factor-bundle) splits browserify 2221 | output into multiple bundle targets based on entry-point. For each entry-point, 2222 | an entry-specific output file is built. Files that are needed by two or more of 2223 | the entry files get factored out into a common bundle. 2224 | 2225 | For example, suppose we have 2 pages: /x and /y. Each page has an entry point, 2226 | `x.js` for /x and `y.js` for /y. 2227 | 2228 | We then generate page-specific bundles `bundle/x.js` and `bundle/y.js` with 2229 | `bundle/common.js` containing the dependencies shared by both `x.js` and `y.js`: 2230 | 2231 | ``` 2232 | browserify x.js y.js -p [ factor-bundle -o bundle/x.js -o bundle/y.js ] \ 2233 | -o bundle/common.js 2234 | ``` 2235 | 2236 | Now we can simply put 2 script tags on each page. On /x we would put: 2237 | 2238 | ``` html 2239 | 2240 | 2241 | ``` 2242 | 2243 | and on page /y we would put: 2244 | 2245 | ``` html 2246 | 2247 | 2248 | ``` 2249 | 2250 | You could also load the bundles asynchronously with ajax or by inserting a 2251 | script tag into the page dynamically but factor-bundle only concerns itself with 2252 | generating the bundles, not with loading them. 2253 | 2254 | ## partition-bundle 2255 | 2256 | [partition-bundle](https://www.npmjs.org/package/partition-bundle) handles 2257 | splitting output into multiple bundles like factor-bundle, but includes a 2258 | built-in loader using a special `loadjs()` function. 2259 | 2260 | partition-bundle takes a json file that maps source files to bundle files: 2261 | 2262 | ``` 2263 | { 2264 | "entry.js": ["./a"], 2265 | "common.js": ["./b"], 2266 | "common/extra.js": ["./e", "./d"] 2267 | } 2268 | ``` 2269 | 2270 | Then partition-bundle is loaded as a plugin and the mapping file, output 2271 | directory, and destination url path (required for dynamic loading) are passed 2272 | in: 2273 | 2274 | ``` 2275 | browserify -p [ partition-bundle --map mapping.json \ 2276 | --output output/directory --url directory ] 2277 | ``` 2278 | 2279 | Now you can add: 2280 | 2281 | ``` html 2282 | 2283 | ``` 2284 | 2285 | to your page to load the entry file. From inside the entry file, you can 2286 | dynamically load other bundles with a `loadjs()` function: 2287 | 2288 | ``` js 2289 | a.addEventListener('click', function() { 2290 | loadjs(['./e', './d'], function(e, d) { 2291 | console.log(e, d); 2292 | }); 2293 | }); 2294 | ``` 2295 | 2296 | # compiler pipeline 2297 | 2298 | Since version 5, browserify exposes its compiler pipeline as a 2299 | [labeled-stream-splicer](https://www.npmjs.org/package/labeled-stream-splicer). 2300 | 2301 | This means that transformations can be added or removed directly into the 2302 | internal pipeline. This pipeline provides a clean interface for advanced 2303 | customizations such as watching files or factoring bundles from multiple entry 2304 | points. 2305 | 2306 | For example, we could replace the built-in integer-based labeling mechanism with 2307 | hashed IDs by first injecting a pass-through transform after the "deps" have 2308 | been calculated to hash source files. Then we can use the hashes we captured to 2309 | create our own custom labeler, replacing the built-in "label" transform: 2310 | 2311 | ``` js 2312 | var browserify = require('browserify'); 2313 | var through = require('through2'); 2314 | var shasum = require('shasum'); 2315 | 2316 | var b = browserify('./main.js'); 2317 | 2318 | var hashes = {}; 2319 | var hasher = through.obj(function (row, enc, next) { 2320 | hashes[row.id] = shasum(row.source); 2321 | this.push(row); 2322 | next(); 2323 | }); 2324 | b.pipeline.get('deps').push(hasher); 2325 | 2326 | var labeler = through.obj(function (row, enc, next) { 2327 | row.id = hashes[row.id]; 2328 | 2329 | Object.keys(row.deps).forEach(function (key) { 2330 | row.deps[key] = hashes[row.deps[key]]; 2331 | }); 2332 | 2333 | this.push(row); 2334 | next(); 2335 | }); 2336 | b.pipeline.get('label').splice(0, 1, labeler); 2337 | 2338 | b.bundle().pipe(process.stdout); 2339 | ``` 2340 | 2341 | Now instead of getting integers for the IDs in the output format, we get file 2342 | hashes: 2343 | 2344 | ``` 2345 | $ node bundle.js 2346 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o bundle.js 2497 | ``` 2498 | 2499 | would load a plugin called `foo`. `foo` is resolved with `require()`, so to load 2500 | a local file as a plugin, preface the path with a `./` and to load a plugin from 2501 | `node_modules/foo`, just do `-p foo`. 2502 | 2503 | You can pass options to plugins with square brackets around the entire plugin 2504 | expression, including the plugin name as the first argument: 2505 | 2506 | ``` 2507 | $ browserify one.js two.js \ 2508 | -p [ factor-bundle -o bundle/one.js -o bundle/two.js ] \ 2509 | > common.js 2510 | ``` 2511 | 2512 | This command-line syntax is parsed by the 2513 | [subarg](https://npmjs.org/package/subarg) package. 2514 | 2515 | To see a list of browserify plugins, browse npm for packages with the keyword 2516 | "browserify-plugin": http://npmjs.org/browse/keyword/browserify-plugin 2517 | 2518 | ## authoring plugins 2519 | 2520 | To author a plugin, write a package that exports a single function that will 2521 | receive a bundle instance and options object as arguments: 2522 | 2523 | ``` js 2524 | // example plugin 2525 | 2526 | module.exports = function (b, opts) { 2527 | // ... 2528 | } 2529 | ``` 2530 | 2531 | Plugins operate on the bundle instance `b` directly by listening for events or 2532 | splicing transforms into the pipeline. Plugins should not overwrite bundle 2533 | methods unless they have a very good reason. 2534 | 2535 | [substack.net/finding_modules]: https://web.archive.org/web/20180624204219/https://substack.net/finding_modules 2536 | [substack.net/task_automation_with_npm_run]: https://web.archive.org/web/20180624203804/http://substack.net/task_automation_with_npm_run 2537 | [substack.net/shared_rendering_in_node_and_the_browser]: https://web.archive.org/web/20180624204233/http://substack.net/shared_rendering_in_node_and_the_browser 2538 | --------------------------------------------------------------------------------