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