1 | var Emitter = require('events').EventEmitter
|
2 | var debug = require('debug')('bankai')
|
3 | var graph = require('buffer-graph')
|
4 | var assert = require('assert')
|
5 | var path = require('path')
|
6 | var pino = require('pino')
|
7 |
|
8 | var localization = require('./localization')
|
9 | var queue = require('./lib/queue')
|
10 | var utils = require('./lib/utils')
|
11 | var ServerRender = require('./ssr')
|
12 |
|
13 | var assetsNode = require('./lib/graph-assets')
|
14 | var documentNode = require('./lib/graph-document')
|
15 | var faviconNode = require('./lib/graph-favicon')
|
16 | var manifestNode = require('./lib/graph-manifest')
|
17 | var reloadNode = require('./lib/graph-reload')
|
18 | var scriptNode = require('./lib/graph-script')
|
19 | var serviceWorkerNode = require('./lib/graph-service-worker')
|
20 | var styleNode = require('./lib/graph-style')
|
21 |
|
22 | module.exports = Bankai
|
23 |
|
24 | function Bankai (entry, opts) {
|
25 | if (!(this instanceof Bankai)) return new Bankai(entry, opts)
|
26 |
|
27 | Emitter.call(this)
|
28 |
|
29 | opts = opts || {}
|
30 | this.local = localization(opts.language || 'en-US')
|
31 | this.log = pino(opts.logStream || process.stdout)
|
32 |
|
33 | assert.strictEqual(typeof entry, 'string', 'bankai: entry should be type string')
|
34 | assert.ok(path.isAbsolute(entry), 'bankai: entry should be an absolute path. Received: ' + entry)
|
35 | assert.strictEqual(typeof opts, 'object', 'bankai: opts should be type object')
|
36 |
|
37 | var self = this
|
38 | var methods = [
|
39 | 'manifest',
|
40 | 'assets',
|
41 | 'service-worker',
|
42 | 'scripts',
|
43 | 'styles',
|
44 | 'documents'
|
45 | ]
|
46 |
|
47 |
|
48 | var key = Buffer.from('be intolerant of intolerance')
|
49 |
|
50 |
|
51 |
|
52 | this.dirname = path.extname(entry) === '' ? entry : utils.dirname(entry)
|
53 | this.queue = queue(methods)
|
54 | this.graph = graph(key)
|
55 |
|
56 | this.ssr = new ServerRender(entry)
|
57 |
|
58 |
|
59 | this.graph.on('change', function (nodeName, edgeName, state) {
|
60 | self.emit('change', nodeName, edgeName, state)
|
61 | var eventName = nodeName + ':' + edgeName
|
62 | var count = self.metadata.count
|
63 | var queue = self.queue
|
64 |
|
65 | if (eventName === 'assets:list') {
|
66 | count['assets'] = String(self.graph.data.assets.list.buffer).split(',').length
|
67 | queue['assets'].ready()
|
68 | } else if (eventName === 'documents:list') {
|
69 | count['documents'] = String(self.graph.data.documents.list.buffer).split(',').length
|
70 | queue['documents'].ready()
|
71 | } else if (eventName === 'manifest:bundle') {
|
72 | count['manifest'] = 1
|
73 | queue['manifest'].ready()
|
74 | } else if (eventName === 'scripts:bundle') {
|
75 | count['scripts'] = 1
|
76 | queue['scripts'].ready()
|
77 | } else if (eventName === 'service-worker:bundle') {
|
78 | count['service-worker'] = 1
|
79 | queue['service-worker'].ready()
|
80 | } else if (eventName === 'styles:bundle') {
|
81 | count['styles'] = 1
|
82 | queue['styles'].ready()
|
83 | }
|
84 | })
|
85 |
|
86 |
|
87 | this.graph.on('error', function () {
|
88 | var args = ['error']
|
89 | for (var len = arguments.length, i = 0; i < len; i++) {
|
90 | args.push(arguments[i])
|
91 | }
|
92 | self.emit.apply(self, args)
|
93 | })
|
94 |
|
95 | this.graph.on('progress', function (chunk, value) {
|
96 | self.emit('progress', chunk, value)
|
97 | })
|
98 |
|
99 | this.graph.on('ssr', function (result) {
|
100 | self.emit('ssr', result)
|
101 | })
|
102 |
|
103 |
|
104 | var documentDependencies = [ 'assets:list', 'manifest:bundle', 'styles:bundle', 'scripts:bundle', 'favicon:bundle' ]
|
105 |
|
106 | if (opts.reload) {
|
107 | documentDependencies.push('reload:bundle')
|
108 | this.graph.node('reload', reloadNode)
|
109 | }
|
110 | this.graph.node('favicon', faviconNode)
|
111 | this.graph.node('assets', assetsNode)
|
112 | this.graph.node('documents', documentDependencies, documentNode)
|
113 | this.graph.node('manifest', manifestNode)
|
114 | this.graph.node('scripts', scriptNode)
|
115 | this.graph.node('service-worker', [ 'assets:list', 'styles:bundle', 'scripts:bundle', 'documents:list' ], serviceWorkerNode)
|
116 | this.graph.node('styles', [ 'scripts:style', 'scripts:bundle' ], styleNode)
|
117 |
|
118 |
|
119 | this.graph.start({
|
120 | dirname: this.dirname,
|
121 | watch: opts.watch !== false,
|
122 | babelifyDeps: opts.babelifyDeps !== false,
|
123 | fullPaths: opts.fullPaths,
|
124 | reload: Boolean(opts.reload),
|
125 | log: this.log,
|
126 | ssr: this.ssr,
|
127 | watchers: {},
|
128 | entry: entry,
|
129 | opts: opts,
|
130 | count: {
|
131 | assets: 0,
|
132 | documents: 0,
|
133 | manifest: 0,
|
134 | scripts: 0,
|
135 | 'service-worker': 0,
|
136 | style: 0
|
137 | }
|
138 | })
|
139 |
|
140 | this.metadata = this.graph.metadata
|
141 | }
|
142 | Bankai.prototype = Object.create(Emitter.prototype)
|
143 |
|
144 | Bankai.prototype.scripts = function (filename, cb) {
|
145 | assert.strictEqual(typeof filename, 'string')
|
146 | assert.strictEqual(typeof cb, 'function')
|
147 | var stepName = 'scripts'
|
148 | var edgeName = filename.split('.')[0]
|
149 | var self = this
|
150 | this.queue[stepName].add(function () {
|
151 | var data = self.graph.data[stepName][edgeName]
|
152 | if (!data) return cb(new Error(`bankai.scripts: could not find a bundle for "${filename}"`))
|
153 | cb(null, data)
|
154 | })
|
155 | }
|
156 |
|
157 | Bankai.prototype.styles = function (filename, cb) {
|
158 | assert.strictEqual(typeof filename, 'string')
|
159 | assert.strictEqual(typeof cb, 'function')
|
160 | var stepName = 'styles'
|
161 | var edgeName = filename.split('.')[0]
|
162 | var self = this
|
163 | this.queue[stepName].add(function () {
|
164 | var data = self.graph.data[stepName][edgeName]
|
165 | if (!data) return cb(new Error('bankai.styles: could not find bundle'))
|
166 | cb(null, data)
|
167 | })
|
168 | }
|
169 |
|
170 | Bankai.prototype.documents = function (url, cb) {
|
171 | assert.strictEqual(typeof url, 'string')
|
172 | assert.strictEqual(typeof cb, 'function')
|
173 |
|
174 | var filename = url.split('?')[0]
|
175 |
|
176 | if (filename === '/') filename = 'index'
|
177 | var stepName = 'documents'
|
178 | var edgeName = filename.split('.')[0] + '.html'
|
179 | var self = this
|
180 | this.queue[stepName].add(function () {
|
181 | var data = self.graph.data[stepName][edgeName]
|
182 | if (!data) return cb(new Error('bankai.document: could not find a document for ' + filename))
|
183 | cb(null, data)
|
184 | })
|
185 | }
|
186 |
|
187 | Bankai.prototype.manifest = function (cb) {
|
188 | assert.strictEqual(typeof cb, 'function')
|
189 | var stepName = 'manifest'
|
190 | var edgeName = 'bundle'
|
191 | var self = this
|
192 | this.queue[stepName].add(function () {
|
193 | var data = self.graph.data[stepName][edgeName]
|
194 | if (!data) return cb(new Error('bankai.manifest: could not find bundle'))
|
195 | cb(null, data)
|
196 | })
|
197 | }
|
198 |
|
199 | Bankai.prototype.serviceWorker = function (cb) {
|
200 | assert.strictEqual(typeof cb, 'function')
|
201 | var stepName = 'service-worker'
|
202 | var edgeName = 'bundle'
|
203 | var self = this
|
204 | this.queue[stepName].add(function () {
|
205 | var data = self.graph.data[stepName][edgeName]
|
206 | if (!data) return cb(new Error('bankai.serviceWorker: could not find bundle'))
|
207 | cb(null, data)
|
208 | })
|
209 | }
|
210 |
|
211 | Bankai.prototype.assets = function (filename, cb) {
|
212 | assert.strictEqual(typeof filename, 'string')
|
213 | assert.strictEqual(typeof cb, 'function')
|
214 | var stepName = 'assets'
|
215 | var self = this
|
216 | this.queue[stepName].add(function () {
|
217 | filename = path.join(self.dirname, filename)
|
218 | var data = self.metadata.assets[filename]
|
219 | if (!data) return cb(new Error('bankai.asset: could not find a file for ' + filename))
|
220 | cb(null, filename)
|
221 | })
|
222 | }
|
223 |
|
224 | Bankai.prototype.sourceMaps = function (stepName, edgeName, cb) {
|
225 | assert.strictEqual(typeof stepName, 'string')
|
226 | assert.strictEqual(typeof edgeName, 'string')
|
227 | assert.strictEqual(typeof cb, 'function')
|
228 | edgeName = /\.map$/.test(edgeName) ? edgeName : edgeName + '.map'
|
229 | var self = this
|
230 | var data = self.graph.data[stepName][edgeName]
|
231 | if (!data) return cb(new Error('bankai.sourceMaps: could not find a file for ' + stepName + ':' + edgeName))
|
232 | cb(null, data)
|
233 | }
|
234 |
|
235 | Bankai.prototype.close = function () {
|
236 | debug('closing all file watchers')
|
237 | this.ssr.close()
|
238 | this.graph.emit('close')
|
239 | this.emit('close')
|
240 | }
|