1 | var debug = require('debug')('bankai.node-script')
|
2 | var concat = require('concat-stream')
|
3 | var exorcist = require('exorcist')
|
4 | var tfilter = require('tfilter')
|
5 | var assert = require('assert')
|
6 |
|
7 | var babelPresetEnv = require('babel-preset-env')
|
8 | var splitRequire = require('split-require')
|
9 | var browserslist = require('browserslist')
|
10 | var cssExtract = require('css-extract')
|
11 | var browserify = require('browserify')
|
12 | var babelify = require('babelify')
|
13 | var watchify = require('watchify')
|
14 | var sheetify = require('sheetify')
|
15 | var nanohtml = require('nanohtml')
|
16 | var tinyify = require('tinyify')
|
17 | var glslify = require('glslify')
|
18 | var envify = require('envify/custom')
|
19 | var brfs = require('brfs')
|
20 |
|
21 | var ttyError = require('./tty-error')
|
22 | var exorcise = require('./exorcise')
|
23 |
|
24 | var defaultBrowsers = [
|
25 | 'last 2 Chrome versions',
|
26 | 'last 2 Firefox versions',
|
27 | 'last 2 Safari versions',
|
28 | 'last 2 Edge versions',
|
29 | '> 1%'
|
30 | ]
|
31 |
|
32 | module.exports = node
|
33 |
|
34 | function node (state, createEdge) {
|
35 | assert.strictEqual(typeof state.metadata.entry, 'string', 'state.metadata.entries should be type string')
|
36 |
|
37 | this.emit('progress', 'scripts', 0)
|
38 |
|
39 | var self = this
|
40 | var entry = state.metadata.entry
|
41 | var fullPaths = Boolean(state.metadata.fullPaths)
|
42 | var b = browserify(browserifyOpts([entry], fullPaths))
|
43 | var shouldMinify = !state.metadata.watch
|
44 |
|
45 |
|
46 | var browsers = browserslist(null, { path: entry })
|
47 | if (!browsers.length) browsers = defaultBrowsers
|
48 |
|
49 | if (state.metadata.watch) {
|
50 | b = watchify(b)
|
51 | debug('watching ' + entry)
|
52 | this.on('close', function () {
|
53 | debug('closing file watcher')
|
54 | b.close()
|
55 | })
|
56 | }
|
57 |
|
58 | b.ignore('sheetify/insert')
|
59 | b.transform(sheetify)
|
60 | b.transform(glslify)
|
61 |
|
62 | if (state.metadata.babelifyDeps) {
|
63 |
|
64 | b.transform(tfilter(babelify, { include: /node_modules/ }), {
|
65 | global: true,
|
66 | babelrc: false,
|
67 | presets: [
|
68 | [babelPresetEnv, {
|
69 |
|
70 |
|
71 |
|
72 | modules: false,
|
73 | targets: { browsers: browsers }
|
74 | }]
|
75 | ]
|
76 | })
|
77 | }
|
78 |
|
79 | b.transform(tfilter(babelify, { exclude: /node_modules/ }), {
|
80 | global: true,
|
81 | babelrc: true,
|
82 | presets: [
|
83 | [babelPresetEnv, {
|
84 | targets: { browsers: browsers }
|
85 | }]
|
86 | ]
|
87 | })
|
88 |
|
89 | b.transform(brfs, { global: true })
|
90 | b.transform(nanohtml, { global: true })
|
91 |
|
92 | if (!fullPaths) b.plugin(cssExtract, { out: bundleStyles })
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | if (!fullPaths) {
|
98 | b.plugin(splitRequire, {
|
99 | filename: function (record) {
|
100 | return 'bundle-' + record.index + '.js'
|
101 | },
|
102 | output: bundleDynamicBundle,
|
103 | sri: 'sha512'
|
104 | })
|
105 |
|
106 |
|
107 | b.on('split.pipeline', function (pipeline, entry, name) {
|
108 | pipeline.get('wrap').push(exorciseDynamicBundle(name))
|
109 | })
|
110 | }
|
111 |
|
112 | if (shouldMinify) {
|
113 | b.plugin(tinyify)
|
114 | b.on('split.pipeline', function (pipeline) {
|
115 | tinyify.applyToPipeline(pipeline, b._options)
|
116 | })
|
117 | } else {
|
118 | var env = Object.assign({
|
119 | NODE_ENV: 'development'
|
120 | }, process.env)
|
121 | b.transform(envify(env), { global: true })
|
122 | }
|
123 |
|
124 | bundleScripts()
|
125 | b.on('update', bundleScripts)
|
126 |
|
127 | var dynamicBundles
|
128 | function bundleScripts (files) {
|
129 | if (files) debug('triggering update because of changes in', files)
|
130 | self.emit('progress', 'scripts', 30)
|
131 |
|
132 | dynamicBundles = []
|
133 | b.bundle(function (err, bundle) {
|
134 | if (err) {
|
135 | delete err.stream
|
136 | err = ttyError('scripts', 'browserify.bundle', err)
|
137 | return self.emit('error', 'scripts', 'browserify.bundle', err)
|
138 | }
|
139 | var mapName = 'bundle.js.map'
|
140 | exorcise(bundle, mapName, function (err, bundle, map) {
|
141 | if (err) return self.emit('error', 'scripts', 'exorcise', err)
|
142 | createEdge(mapName, Buffer.from(map), {
|
143 | mime: 'application/json'
|
144 | })
|
145 | createEdge('bundle', bundle, {
|
146 | mime: 'application/javascript',
|
147 | dynamicBundles: dynamicBundles
|
148 | })
|
149 | self.emit('progress', 'scripts', 100)
|
150 | })
|
151 | })
|
152 | }
|
153 |
|
154 | function exorciseDynamicBundle (bundleName) {
|
155 | var mapName = bundleName + '.map'
|
156 | return exorcist(concat({ encoding: 'buffer' }, function (map) {
|
157 | createEdge(mapName, map, {
|
158 | mime: 'application/json'
|
159 | })
|
160 | }), mapName)
|
161 | }
|
162 |
|
163 | function bundleDynamicBundle (bundleName) {
|
164 | var edgeName = bundleName.replace(/\.js$/, '')
|
165 | var stream = concat({ encoding: 'buffer' }, function (bundle) {
|
166 | dynamicBundles.push(bundleName)
|
167 | createEdge(edgeName, bundle, {
|
168 | mime: 'application/javascript'
|
169 | })
|
170 |
|
171 |
|
172 | stream.emit('name', state.scripts[edgeName].hash.toString('hex').slice(0, 16) + '/' + bundleName)
|
173 | })
|
174 | return stream
|
175 | }
|
176 |
|
177 | function bundleStyles () {
|
178 | return concat({ encoding: 'buffer' }, function (buf) {
|
179 | createEdge('style', buf, {
|
180 | mime: 'text/css'
|
181 | })
|
182 | })
|
183 | }
|
184 | }
|
185 |
|
186 | function browserifyOpts (entries, fullPaths) {
|
187 | assert.ok(Array.isArray(entries), 'browserifyOpts: entries should be an array')
|
188 | return {
|
189 | debug: true,
|
190 | fullPaths: fullPaths,
|
191 | entries: entries,
|
192 | packageCache: {},
|
193 | cache: {}
|
194 | }
|
195 | }
|