UNPKG

6.14 kBJavaScriptView Raw
1var unpack = require('browser-unpack')
2var builtins = require('builtins')
3var through = require('through')
4var flatten = require('flatten')
5var duplex = require('duplexer')
6var pluck = require('plucker')
7var uniq = require('uniq')
8
9var commondir = require('commondir')
10var fileTree = require('file-tree')
11var path = require('path')
12var fs = require('fs')
13var bl = require('bl')
14
15var versions = require('./lib/versions')
16
17module.exports = createStream
18createStream.json = json
19createStream.bundle = bundle
20
21function createStream(opts) {
22 opts = opts || {}
23
24 var buffer = bl(function(err, content) {
25 if (err) return stream.emit('error', err)
26
27 bundle(content, opts, function(err, html) {
28 if (err) return stream.emit('error', err)
29
30 output.queue(html)
31 output.queue(null)
32 })
33 })
34
35 var output = through()
36 var stream = duplex(buffer, output)
37
38 return stream
39}
40
41function json(bundles, callback) {
42 var modules = flatten(bundles
43 .map(String)
44 .map(unpack)
45 ).map(function(module) {
46 if (typeof module === 'undefined') return callback(new Error(
47 'Unable to compile one of the supplied bundles!'
48 ))
49
50 if (typeof module.id !== 'number') return module
51
52 return callback(new Error(
53 'Please recompile this browserify bundle using the --full-paths flag ' +
54 '(when using the command-line interface) or with the fullPaths option ' +
55 'set to true (when using the JavaScript API).'
56 ))
57 })
58
59 modules = modules.filter(function(module) {
60 return module && !isEmpty(module)
61 })
62
63 if (!modules.length) return
64
65 var browserifyModules = modules.filter(fromBrowserify(true))
66 var otherModules = modules.filter(function(module) {
67 if (path.basename(module.id) === '_empty.js') return false
68 if (browserifyModules.indexOf(module) === -1) return true
69 })
70
71 var root = commondir(otherModules.map(pluck('id')))
72
73 browserifyModules.forEach(function(module) {
74 var regex = /^.+\/node_modules\/browserify\/(?:node_modules\/)(.+)$/g
75
76 module.id = module.id.replace(regex, function(_, subpath) {
77 return path.resolve(root, 'browserify-core/' + subpath)
78 })
79
80 return module
81 })
82
83 uniq(modules, function(a, b) {
84 return a.id === b.id ? 0 : 1
85 }, true)
86
87 var ids = modules.map(pluck('id'))
88 var main = path.basename(root)
89
90 var byid = modules.reduce(function(memo, mod) {
91 memo[mod.id] = mod
92 return memo
93 }, {})
94
95 fileTree(ids, function(id, next) {
96 var row = byid[id]
97
98 next(null, {
99 size: row.source.length
100 , deps: Object.keys(row.deps).length
101 , path: id
102 })
103 }, function(err, tree) {
104 if (err) return callback(err)
105
106 tree = { name: main, children: tree }
107 dirsizes(tree)
108 versions(tree)
109 callback(null, tree)
110 })
111}
112
113function bundle(bundles, opts, callback) {
114 bundles = Array.isArray(bundles)
115 ? bundles
116 : bundles ? [bundles] : []
117
118 if (typeof opts === 'function') {
119 callback = opts
120 opts = {}
121 }
122
123 opts = opts || {}
124 callback = callback || noop
125
126 var header = opts.header || opts.button || ''
127 var footer = opts.footer || ''
128
129 return json(bundles, function(err, data) {
130 if (err) return callback(err)
131
132 data.mode = opts.mode || 'size'
133 data = '<script type="text/javascript">'
134 + ';window.disc = ('
135 + JSON.stringify(data)
136 + ');</script>'
137
138 var script = '<script type="text/javascript">'
139 + bundled().replace(/\/script/gi, '\\/script')
140 + '</script>'
141
142 callback(null, template()({
143 scripts: script
144 , styles: styles()
145 , markdown: footer
146 , header: header
147 , data: data
148 }))
149 })
150}
151
152function template() {
153 if (template.text) return template.text
154 return template.text = require('./lib/lazy-template')(
155 fs.readFileSync(__dirname + '/src/base.html', 'utf8')
156 )
157}
158
159function styles() {
160 if (styles.text) return styles.text
161 return styles.text = fs.readFileSync(__dirname + '/build/style.css', 'utf8')
162}
163
164function bundled() {
165 if (bundled.text) return bundled.text
166 return bundled.text = fs.readFileSync(__dirname + '/build/bundle.js', 'utf8')
167}
168
169function dirsizes(child) {
170 return child.size = "size" in child ? child.size : child.children.reduce(function(size, child) {
171 return size + ("size" in child ? child.size : dirsizes(child))
172 }, 0)
173}
174
175function noop(){}
176
177function fromBrowserify(yes) {
178 var existsCache = {}
179 var no = !yes
180
181 return function(module) {
182 var search = '/node_modules/browserify'
183 var idx = module.id.indexOf(search)
184 var from = idx !== -1
185
186 if (!from) return no
187
188 // special case for process.js
189 // from insert-module-globals
190 if (
191 module.id.indexOf('insert-module-globals') !== -1 &&
192 module.id.split(path.sep).slice(-2).join('/') === 'process/browser.js'
193 ) return yes
194
195 // Look up browserify's builtins file to
196 // determine if this file is part of browserify
197 // core.
198 var builtinFile = (
199 module.id.slice(0, idx + search.length) +
200 '/lib/builtins.js'
201 )
202
203 if (!(builtinFile in existsCache)) {
204 existsCache[builtinFile] = values(
205 fs.existsSync(builtinFile) &&
206 require(builtinFile) || {}
207 )
208 }
209
210 var localBuiltins = existsCache[builtinFile]
211 var bidx = localBuiltins.indexOf(module.id)
212
213 if (bidx !== -1) return yes
214
215 // Guess remaining helper files based on module
216 // name: this should probably be improved in the
217 // future.
218 var split = module.id.split(path.sep)
219 var j = split.length - 1
220
221 while (split[--j] !== 'node_modules');;
222
223 var dir = split.slice(j + 1)[0].replace(/\-(?:browser(?:ify)?|es3)$/g, '')
224 if (dir === 'Base64') return yes
225 if (dir === 'base64-js') return yes
226 if (dir === 'inherits') return yes
227 if (dir === 'process') return yes
228 if (dir === 'ieee754') return yes
229 if (builtins.indexOf(dir) !== -1) return yes
230
231 return no
232 }
233}
234
235function values(object) {
236 return Object.keys(object).map(function(key) {
237 return object[key]
238 })
239}
240
241function isEmpty(module) {
242 return (
243 path.basename(module.id) === '_empty.js' &&
244 (!fs.existsSync(module.id) || !fs.statSync(module.id).size)
245 )
246}