Permalink
Browse files

Version 1.0.0

  • Loading branch information...
0 parents commit c40ebb74f73a3b83768aced2b0412f09ea86ed9a @domenic committed Nov 14, 2012
@@ -0,0 +1,2 @@
+/node_modules/
+/npm-debug.log
@@ -0,0 +1,19 @@
+{
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "es5": true,
+ "globalstrict": true,
+ "immed": true,
+ "indent": 4,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "node": true,
+ "nonew": true,
+ "nomen": true,
+ "trailing": true,
+ "undef": true,
+ "unused": true,
+ "white": true
+}
@@ -0,0 +1,6 @@
+/node_modules/
+/npm-debug.log
+
+/test/
+/.jshintrc
+/.npmignore
@@ -0,0 +1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2012 Domenic Denicola <domenic@domenicdenicola.com>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
@@ -0,0 +1,64 @@
+# Split Browserify Bundles into Individual Files
+
+Sometimes you work in browsers without `//@ sourceURL` or source maps. But you like using [Browserify][], since it's
+truly amazing. How will you ever debug things? With all your modules squished into one file, it's a disaster.
+
+Enter the **Browserify Deoptimizer**, which will handily “de-optimize” your Browserify bundles by turning them into
+individual files, including files for each module you author.
+
+[browserify]: https://github.com/substack/node-browserify
+
+## Usage
+
+You use the Browserify Deoptimizer by first creating a Browserify bundle, programmatically. Then, instead of creating a
+big string with `bundle.bundle()`, you just deoptimize it!
+
+```js
+var browserify = require("browserify");
+var deoptimize = require("browserify-deoptimizer");
+
+var bundle = browserify({ cache: true });
+bundle.alias("jquery", "jquery-browserify");
+bundle.addEntry("start.js");
+
+var deoptimized = deoptimize(bundle);
+```
+
+Your `deoptimized` variable will then look something like this:
+
+```js
+{
+ "browserify-prelude.js": 'var require = function (file, …',
+ "vm": 'require.define("vm",function(r…',
+ "node_modules/browserify/node_modules/vm-browserify/package.json": 'require.define("/node_modules/…',
+ "node_modules/browserify/node_modules/vm-browserify/index.js": 'require.define("/node_modules/…',
+ "node_modules/jquery-browserify/package.json": 'require.define("/node_modules/…',
+ "node_modules/jquery-browserify/index.js": 'require.define("/node_modules/…',
+ "browserify-aliases.js": 'require.alias("jquery-browseri…',
+ "start.js": 'require.define("/start.js",fun…',
+ "browserify-entry.js": 'require("/start.js");'
+}
+```
+
+You can then use these module IDs to write out the wrapped files to the filesystem, and the appropriate `<script>` tags
+to your `index.html`.
+
+## Special Files
+
+Since Browserify does some magic, we can't just create a single file for each of your modules. We need some magic files
+too. These are:
+
+- `browserify-prelude.js`: contains the definition of `require` and `process`, as well as any prepends with
+ `bundle.prepend`. This will be the first file in the map.
+- `browserify-aliases.js`: Contains any calls to Browserify's `require.alias` to set up module aliases. This is inserted
+ into the map after the entries for the aliased files themselves (e.g. after jquery-browserify's files). If there are
+ no aliases, this file will not exist.
+- `browserify-entry.js`: Contains calls to `require` for all entry files in the bundle. If there are no entry files,
+ this file will not exist.
+
+## Name
+
+This package owes its name to [r.js][], the RequireJS optimizer, which turns multiple AMD modules into a single bundled
+file. Since this package does the opposite, I thought it'd be clever to name it a deoptimizer.
+
+[r.js]: http://requirejs.org/docs/optimization.html
@@ -0,0 +1,118 @@
+"use strict";
+
+var browserify = require("browserify");
+var _ = require("underscore");
+var path = require("path");
+
+var urlize = require("./utils").urlize;
+var isCoreBuiltin = require("./utils").isCoreBuiltin;
+
+function getModuleId(file, filePath) {
+ return file.target || urlize(path.relative(process.cwd(), filePath));
+}
+
+function keyFromModuleId(moduleId) {
+ // Keys in the result map should be a bit more friendly than the raw Browserify module IDs, which often begin with
+ // `/`. This makes them hard to deal with as paths, since they act as absolute paths. Just remove the leading `/`.
+ return moduleId[0] === "/" ? moduleId.substring(1) : moduleId;
+}
+
+function addFilesAndEntries(bundle, result) {
+ // The `bundle.files` and `bundle.entries` properties map absolute file paths to unwrapped module bodies. Use them
+ // to create a map of module IDs to wrapped module bodies.
+ var allFiles = _.extend({}, bundle.files, bundle.entries);
+
+ Object.keys(allFiles).forEach(function (filePath) {
+ if (!isCoreBuiltin(filePath)) {
+ var file = allFiles[filePath];
+ var moduleId = getModuleId(file, filePath);
+ result[keyFromModuleId(moduleId)] = bundle.wrap(moduleId, file.body);
+ }
+ });
+}
+
+function removeNonPreludeStuff(bundle) {
+ // Temporarily move non-core builtins out of `bundle.files` and `bundle.entries`. They will go in individual files.
+ // Also move `bundle.aliases`, since we take care of those in a separate browserify-aliases.js file.
+ var files = Object.create(null);
+ var entries = bundle.entries;
+ var aliases = bundle.aliases;
+
+ for (var fileName in bundle.files) {
+ if (!isCoreBuiltin(fileName)) {
+ files[fileName] = bundle.files[fileName];
+ delete bundle.files[fileName];
+ }
+ }
+ bundle.entries = {};
+ bundle.aliases = {};
+
+ return { files: files, entries: entries, aliases: aliases };
+}
+
+function addBackNonPreludeStuff(bundle, nonPreludeStuff) {
+ for (var movedFileName in nonPreludeStuff.files) {
+ bundle.files[movedFileName] = nonPreludeStuff.files[movedFileName];
+ }
+ bundle.entries = nonPreludeStuff.entries;
+ bundle.aliases = nonPreludeStuff.aliases;
+}
+
+function addPrelude(bundle, result) {
+ var nonPreludeStuff = removeNonPreludeStuff(bundle);
+
+ result["browserify-prelude.js"] = bundle.bundle();
+
+ addBackNonPreludeStuff(bundle, nonPreludeStuff);
+
+ // Since we called `bundle.bundle`, we need to reload the bundle.
+ bundle.reload();
+}
+
+function addAliases(bundle, result) {
+ if (Object.keys(bundle.aliases).length === 0) {
+ return;
+ }
+
+ // Create a bundle with the aliases. It currently contains the prelude, the aliases, and the core built-ins.
+ var tempBundle = browserify({ require: bundle.aliases, cache: true });
+
+ // Add files and entries for this temp bundle: this gets the un-aliased files to be included. I.e. if we alias
+ // jquery-browserify to jquery, this puts jquery-browserify in the result.
+ addFilesAndEntries(tempBundle, result);
+
+ // Now we're going to generate the browserify-aliases.js file. To do this, remove all actual files and the prelude:
+ // we just want the `require.alias` calls.
+ tempBundle.files = {};
+ tempBundle.prepends = [];
+
+ // This will give a string containing the the `require.alias` calls only.
+ result["browserify-aliases.js"] = tempBundle.bundle();
+}
+
+function addEntryRequirer(bundle, result) {
+ if (Object.keys(bundle.entries).length === 0) {
+ return;
+ }
+
+ var entryRequires = Object.keys(bundle.entries).reduce(function (soFar, filePath) {
+ var file = bundle.entries[filePath];
+ var moduleId = getModuleId(file, filePath);
+ return soFar + 'require("' + moduleId + '");\n';
+ }, "");
+ result["browserify-entry.js"] = entryRequires;
+}
+
+module.exports = function (bundle) {
+ var result = Object.create(null);
+
+ // The multi-file nature necessitates forcing all exports, otherwise subsequent files don't know what `require` is.
+ bundle.exports = true;
+
+ addPrelude(bundle, result);
+ addAliases(bundle, result);
+ addFilesAndEntries(bundle, result);
+ addEntryRequirer(bundle, result);
+
+ return result;
+};
@@ -0,0 +1,17 @@
+"use strict";
+
+var path = require("path");
+var _ = require("underscore");
+
+exports.urlize = function (path) {
+ return "/" + path.replace(/\\/g, "/");
+};
+
+exports.isCoreBuiltin = function (filePath) {
+ // The "core" built-in modules must be bundled into the prelude file, since the definitions of Browserify's
+ // `require` depend on them: they cannot be split out into separate files.
+ var pieces = filePath.split(path.sep).slice(-3);
+
+ return _.isEqual(pieces, ["browserify", "builtins", "path.js"]) ||
+ _.isEqual(pieces, ["browserify", "builtins", "__browserify_process.js"]);
+};
@@ -0,0 +1,32 @@
+{
+ "name": "browserify-deoptimizer",
+ "description": "Transforms browserify bundles into a collection of single files",
+ "version": "1.0.0",
+ "author": "Domenic Denicola <domenic@domenicdenicola.com> (http://domenicdenicola.com)",
+ "license": "WTFPL",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/domenic/browserify-deoptimizer.git"
+ },
+ "bugs": {
+ "url": "http://github.com/domenic/browserify-deoptimizer/issues"
+ },
+ "main": "lib/browserify-deoptimizer.js",
+ "directories": {
+ "lib": "lib"
+ },
+ "scripts": {
+ "test": "mocha",
+ "lint": "jshint lib"
+ },
+ "dependencies": {
+ "browserify": ">= 1.16.3 < 2",
+ "underscore": ">= 1.4.2"
+ },
+ "devDependencies": {
+ "coffee-script": ">= 1.4.0",
+ "chai": ">= 1.3.0",
+ "jshint": ">= 0.9.1",
+ "mocha": ">= 1.7.0"
+ }
+}
@@ -0,0 +1,3 @@
+"use strict";
+
+module.exports = "file 1";
@@ -0,0 +1,3 @@
+"use strict";
+
+exports.file1 = require("./1");
@@ -0,0 +1,3 @@
+"use strict";
+
+module.exports = require("underscore2");
@@ -0,0 +1,3 @@
+"use strict";
+
+module.exports = require("assert");
@@ -0,0 +1,3 @@
+"use strict";
+
+module.exports = require("./stuff.jade");
@@ -0,0 +1,2 @@
+.hello-world
+ p This doesn't even get tested for; the file just has to exist.
@@ -0,0 +1,3 @@
+--reporter spec
+--compilers coffee:coffee-script
+--slow 300ms
Oops, something went wrong.

0 comments on commit c40ebb7

Please sign in to comment.