jalla 1.0.0-4 → 1.0.0-40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -17
- package/bin.js +18 -15
- package/index.js +46 -33
- package/lib/app.js +49 -19
- package/lib/build.js +13 -129
- package/lib/compile.js +6 -3
- package/lib/document.js +77 -50
- package/lib/manifest.js +3 -5
- package/lib/pipeline.js +13 -10
- package/lib/render.js +53 -33
- package/lib/script.js +51 -30
- package/lib/service-worker.js +14 -7
- package/lib/style.js +7 -2
- package/lib/ui.js +15 -8
- package/package.json +46 -46
package/README.md
CHANGED
@@ -28,7 +28,7 @@ compiled using [Documentify][documentify]. And it's all configured for you.
|
|
28
28
|
- [`ctx.assets`](#ctxassets)
|
29
29
|
- [Assets](#assets)
|
30
30
|
- [Manifest](#manifest)
|
31
|
-
|
31
|
+
- [Service Workers](#service-workers)
|
32
32
|
- [Advanced Usage](#advanced-usage)
|
33
33
|
- [Configuration](#configuration)
|
34
34
|
- [JavaScript](#javascript)
|
@@ -70,6 +70,7 @@ $ NODE_ENV=production jalla index.js
|
|
70
70
|
- __`--css`__ explicitly include a css file in the build
|
71
71
|
- __`--service-worker, --sw`__ entry point for a service worker
|
72
72
|
- __`--base, -b`__ base path where app will be served
|
73
|
+
- __`--skip, -s`__ skip transform for file/glob (excluding optimizations)
|
73
74
|
- __`--watch, -w`__ watch files for changes (default in `development`)
|
74
75
|
- __`--dir, -d`__ output directory, use with [build](#build) and [serve](#serve)
|
75
76
|
- __`--quiet, -q`__ disable printing to console
|
@@ -178,11 +179,13 @@ before issuing another render pass using the state generated the first time.
|
|
178
179
|
|
179
180
|
```javascript
|
180
181
|
// store.js
|
182
|
+
var fetch = require('node-fetch')
|
183
|
+
|
181
184
|
module.exports = function (state, emitter) {
|
182
185
|
state.data = state.data || null
|
183
186
|
|
184
187
|
emitter.on('fetch', function () {
|
185
|
-
var request =
|
188
|
+
var request = fetch('/my/api')
|
186
189
|
.then((res) => res.json())
|
187
190
|
.then(function (data) {
|
188
191
|
state.data = data
|
@@ -258,7 +261,7 @@ A bare-bones application manifest is generated based on the projects
|
|
258
261
|
`package.json`. You can either place a custom `manifest.json` in the
|
259
262
|
[assets](#assets) folder or you can generate one using a custom middleware.
|
260
263
|
|
261
|
-
|
264
|
+
## Service Workers
|
262
265
|
By supplying the path to a service worker entry file with the `sw` option, jalla
|
263
266
|
will build and serve it's bundle from that path.
|
264
267
|
|
@@ -313,7 +316,13 @@ self.addEventListener('install', function oninstall (event) {
|
|
313
316
|
|
314
317
|
self.addEventListener('activate', function onactivate (event) {
|
315
318
|
// clear old caches on activate
|
316
|
-
event.waitUntil(clear().then(()
|
319
|
+
event.waitUntil(clear().then(function () {
|
320
|
+
if (!self.registration.navigationPreload) return self.clients.claim()
|
321
|
+
// enable navigation preload
|
322
|
+
return self.registration.navigationPreload.enable().then(function () {
|
323
|
+
return self.clients.claim()
|
324
|
+
})
|
325
|
+
}))
|
317
326
|
})
|
318
327
|
|
319
328
|
self.addEventListener('fetch', function onfetch (event) {
|
@@ -321,14 +330,14 @@ self.addEventListener('fetch', function onfetch (event) {
|
|
321
330
|
event.respondWith(caches.open(CACHE_KEY).then(async function (cache) {
|
322
331
|
try {
|
323
332
|
var cached = await cache.match(req)
|
324
|
-
var response = self.fetch(event.request)
|
325
|
-
if (req.method.toUpperCase() === 'GET') {
|
333
|
+
var response = await (event.preloadResponse || self.fetch(event.request))
|
334
|
+
if (response.ok && req.method.toUpperCase() === 'GET') {
|
326
335
|
await cache.put(req, response.clone())
|
327
336
|
}
|
328
337
|
return response
|
329
338
|
} catch (err) {
|
330
339
|
if (cached) return cached
|
331
|
-
|
340
|
+
return err
|
332
341
|
}
|
333
342
|
}))
|
334
343
|
})
|
@@ -369,24 +378,32 @@ is compiling the app. The pipline steps are called in series, and have access
|
|
369
378
|
to the assets and dependencies of all prior steps.
|
370
379
|
|
371
380
|
```javascript
|
372
|
-
var
|
381
|
+
var path = require('path')
|
373
382
|
var jalla = require('jalla')
|
383
|
+
var csv = require('csvtojson')
|
374
384
|
var app = jalla('index.js')
|
375
385
|
|
376
|
-
// include data.csv as
|
386
|
+
// convert and include data.csv as a JSON file
|
377
387
|
app.pipeline.get('assets').push(function (state, emit) {
|
378
|
-
return function (cb) {
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
cb()
|
388
|
+
return async function (cb) {
|
389
|
+
if (state.assets.has('data.json')) return cb()
|
390
|
+
emit('progress', 'data.json')
|
391
|
+
var json = await csv.fromFile(path.resolve(state.entry, 'data.csv'))
|
392
|
+
emit('asset', 'data.json', Buffer.from(JSON.stringify(json)), {
|
393
|
+
mime: 'application/json
|
385
394
|
})
|
395
|
+
cb()
|
386
396
|
}
|
387
397
|
})
|
388
398
|
|
389
|
-
|
399
|
+
if (process.env.BUILD) {
|
400
|
+
app.build(path.resolve(__dirname, 'dist'), function (err) {
|
401
|
+
if (err) console.error(err)
|
402
|
+
process.exit(err ? 1 : 0)
|
403
|
+
})
|
404
|
+
} else {
|
405
|
+
app.listen(8080)
|
406
|
+
}
|
390
407
|
```
|
391
408
|
|
392
409
|
## Configuration
|
package/bin.js
CHANGED
@@ -8,7 +8,6 @@ var assert = require('assert')
|
|
8
8
|
var dedent = require('dedent')
|
9
9
|
var getPort = require('get-port')
|
10
10
|
var minimist = require('minimist')
|
11
|
-
var App = require('./lib/app')
|
12
11
|
var jalla = require('./index')
|
13
12
|
|
14
13
|
var COMMANDS = ['start', 'build', 'serve']
|
@@ -16,14 +15,15 @@ var COMMANDS = ['start', 'build', 'serve']
|
|
16
15
|
var argv = minimist(process.argv.slice(2), {
|
17
16
|
alias: {
|
18
17
|
'service-worker': 'sw',
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
18
|
+
dir: 'd',
|
19
|
+
quiet: 'q',
|
20
|
+
inspect: 'i',
|
21
|
+
skip: 's',
|
22
|
+
base: 'b',
|
23
|
+
watch: 'w',
|
24
|
+
port: 'p',
|
25
|
+
help: 'h',
|
26
|
+
version: 'v'
|
27
27
|
},
|
28
28
|
default: {
|
29
29
|
port: process.env.PORT || 8080
|
@@ -49,6 +49,7 @@ if (argv.help) {
|
|
49
49
|
--css entry point for CSS
|
50
50
|
--service-worker, --sw entry point for service worker
|
51
51
|
--base, -b base path where app will be mounted
|
52
|
+
--skip, -s skip transform for file/glob (excluding optimizations)
|
52
53
|
--watch, -w enable watch mode (default in development)
|
53
54
|
--dir, -d output directory, use with ${chalk.bold('build')} and ${chalk.bold('serve')}
|
54
55
|
--quiet, -q disable printing to console
|
@@ -95,14 +96,16 @@ if (typeof argv.watch !== 'undefined') opts.watch = Boolean(argv.watch)
|
|
95
96
|
|
96
97
|
if (command === 'build') {
|
97
98
|
opts.watch = false
|
98
|
-
|
99
|
-
|
100
|
-
app.build(path.resolve(process.cwd(), dir)
|
101
|
-
process.exit(
|
99
|
+
const app = jalla(path.resolve(process.cwd(), entry), opts)
|
100
|
+
const dir = typeof argv.dir === 'string' ? argv.dir : 'dist'
|
101
|
+
app.build(path.resolve(process.cwd(), dir)).then(function () {
|
102
|
+
process.exit(0)
|
103
|
+
}, function () {
|
104
|
+
process.exit(1)
|
102
105
|
})
|
103
106
|
} else {
|
104
|
-
|
105
|
-
getPort({ port: argv.port }).then(function (port) {
|
107
|
+
const app = jalla(path.resolve(process.cwd(), entry), opts)
|
108
|
+
getPort({ port: argv.port || 8080 }).then(function (port) {
|
106
109
|
app.listen(port)
|
107
110
|
})
|
108
111
|
}
|
package/index.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
var path = require('path')
|
2
2
|
var assert = require('assert')
|
3
3
|
var serve = require('koa-static')
|
4
|
+
var { Minimatch } = require('minimatch')
|
4
5
|
var App = require('./lib/app')
|
5
6
|
var render = require('./lib/render')
|
6
7
|
|
@@ -14,11 +15,24 @@ function start (entry, opts = {}) {
|
|
14
15
|
var dist = opts.dist
|
15
16
|
if (!dist) dist = typeof opts.serve === 'string' ? opts.serve : 'dist'
|
16
17
|
|
18
|
+
var swPath = opts.sw
|
19
|
+
? path.resolve(dir, dist, 'public', path.relative(dir, opts.sw))
|
20
|
+
: null
|
21
|
+
|
22
|
+
if (opts.skip) {
|
23
|
+
const input = Array.isArray(opts.skip) ? opts.skip : [opts.skip]
|
24
|
+
var skip = input.map(normalizeSkip)
|
25
|
+
}
|
26
|
+
|
17
27
|
opts = Object.assign({}, opts, {
|
18
28
|
dist: absolute(dist, dir),
|
19
29
|
serve: Boolean(opts.serve),
|
20
30
|
sw: opts.sw && absolute(opts.sw, dir),
|
21
|
-
css: opts.css && absolute(opts.css, dir)
|
31
|
+
css: opts.css && absolute(opts.css, dir),
|
32
|
+
skip (file) {
|
33
|
+
if (!skip) return false
|
34
|
+
return skip.reduce((res, test) => res || test(file), false)
|
35
|
+
}
|
22
36
|
})
|
23
37
|
|
24
38
|
var app = new App(entry, opts)
|
@@ -29,45 +43,44 @@ function start (entry, opts = {}) {
|
|
29
43
|
app.emit('timing', Date.now() - start, ctx)
|
30
44
|
})
|
31
45
|
|
32
|
-
if (opts.serve) {
|
33
|
-
let pub = path.resolve(opts.dist, 'public')
|
34
|
-
app.use(serve(pub, { setHeaders }))
|
35
|
-
} else {
|
36
|
-
let state = Object.assign({
|
37
|
-
env: app.env,
|
38
|
-
base: opts.base || '',
|
39
|
-
watch: typeof opts.watch === 'undefined'
|
40
|
-
? app.env === 'development'
|
41
|
-
: opts.watch
|
42
|
-
}, opts)
|
43
|
-
let init = new Promise(function (resolve, reject) {
|
44
|
-
app.pipeline.bundle(entry, state, resolve)
|
45
|
-
})
|
46
|
-
|
47
|
-
app.use((ctx, next) => init.then(next))
|
48
|
-
app.use(app.pipeline.middleware())
|
49
|
-
app.use(function (ctx, next) {
|
50
|
-
if (ctx.body) {
|
51
|
-
let cache = state.env !== 'development' && !state.watch
|
52
|
-
let maxAge = cache ? 60 * 60 * 24 * 365 : 0
|
53
|
-
let value = `${cache ? 'public, ' : ''}max-age=${maxAge}`
|
54
|
-
ctx.set('Cache-Control', value)
|
55
|
-
}
|
56
|
-
return next()
|
57
|
-
})
|
58
|
-
}
|
59
|
-
|
60
46
|
app.use(require('koa-conditional-get')())
|
61
47
|
app.use(require('koa-etag')())
|
62
48
|
app.use(render(app))
|
63
49
|
|
50
|
+
if (opts.serve) {
|
51
|
+
app.use(serve(path.resolve(opts.dist, 'public'), { setHeaders }))
|
52
|
+
} else {
|
53
|
+
app.use(app.pipeline.middleware(app.state))
|
54
|
+
}
|
55
|
+
|
64
56
|
return app
|
57
|
+
|
58
|
+
// set static asset headers
|
59
|
+
// (obj, str, obj) -> void
|
60
|
+
function setHeaders (res, filepath, stats) {
|
61
|
+
if (filepath === swPath) {
|
62
|
+
res.setHeader('Cache-Control', 'max-age=0')
|
63
|
+
} else {
|
64
|
+
res.setHeader('Cache-Control', `public, max-age=${60 * 60 * 24 * 365}`)
|
65
|
+
}
|
66
|
+
}
|
65
67
|
}
|
66
68
|
|
67
|
-
//
|
68
|
-
//
|
69
|
-
function
|
70
|
-
|
69
|
+
// ensure skip input is a function
|
70
|
+
// any -> fn
|
71
|
+
function normalizeSkip (val) {
|
72
|
+
if (val instanceof RegExp) {
|
73
|
+
return val.test.bind(val)
|
74
|
+
} else if (typeof val === 'function') {
|
75
|
+
return val
|
76
|
+
} else if (typeof val === 'string') {
|
77
|
+
var minimatch = new Minimatch(val)
|
78
|
+
return function (str) {
|
79
|
+
return str.includes(val) || minimatch.match(str)
|
80
|
+
}
|
81
|
+
} else {
|
82
|
+
throw new Error('jalla: skip should be either RegExp, function or string')
|
83
|
+
}
|
71
84
|
}
|
72
85
|
|
73
86
|
// resolve file path (relative to dir) to absolute path
|
package/lib/app.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
var fs = require('fs')
|
1
2
|
var Koa = require('koa')
|
2
3
|
var path = require('path')
|
3
4
|
var assert = require('assert')
|
4
|
-
var
|
5
|
+
var browserslist = require('browserslist')
|
5
6
|
var ui = require('./ui')
|
6
7
|
var build = require('./build')
|
7
8
|
var style = require('./style')
|
@@ -12,28 +13,37 @@ var manifest = require('./manifest')
|
|
12
13
|
var Pipeline = require('./pipeline')
|
13
14
|
var serviceWorker = require('./service-worker')
|
14
15
|
|
16
|
+
var DEFAULT_BROWSERS = [
|
17
|
+
'last 2 Chrome versions',
|
18
|
+
'last 2 Firefox versions',
|
19
|
+
'last 2 Safari versions',
|
20
|
+
'last 2 Edge versions',
|
21
|
+
'> 1%'
|
22
|
+
]
|
23
|
+
|
15
24
|
module.exports = class App extends Koa {
|
16
25
|
constructor (entry, opts) {
|
17
26
|
super()
|
18
27
|
|
19
|
-
this.base = opts.base || ''
|
20
|
-
|
21
28
|
var bundled = []
|
22
29
|
if (opts.serve) {
|
23
30
|
try {
|
24
31
|
// pick up stat of existing build
|
25
|
-
|
32
|
+
const stat = require(path.resolve(opts.dist, 'stat.json'))
|
26
33
|
bundled = stat.assets.map(function (asset) {
|
27
34
|
return Object.assign({}, asset, {
|
28
35
|
hash: Buffer.from(asset.hash, 'hex'),
|
29
36
|
file: path.resolve(opts.dist, 'public', asset.file)
|
30
37
|
})
|
31
38
|
})
|
32
|
-
|
33
|
-
entry = path.resolve(opts.dist, path.basename(entry))
|
39
|
+
this.browsers = stat.browsers
|
34
40
|
} catch (err) {
|
35
41
|
this.emit('error', Error('Failed to load stat from serve directory'))
|
36
42
|
}
|
43
|
+
} else {
|
44
|
+
const dir = path.dirname(entry)
|
45
|
+
const browsers = browserslist.loadConfig({ path: dir, env: this.env })
|
46
|
+
this.browsers = browsers || DEFAULT_BROWSERS
|
37
47
|
}
|
38
48
|
|
39
49
|
var pipeline = new Pipeline([
|
@@ -45,6 +55,8 @@ module.exports = class App extends Koa {
|
|
45
55
|
['build']
|
46
56
|
], bundled)
|
47
57
|
|
58
|
+
this.bundled = false
|
59
|
+
this.base = opts.base || ''
|
48
60
|
this.entry = entry
|
49
61
|
this._opts = opts
|
50
62
|
this.pipeline = pipeline
|
@@ -62,20 +74,26 @@ module.exports = class App extends Koa {
|
|
62
74
|
else this.silent = true
|
63
75
|
}
|
64
76
|
|
77
|
+
get state () {
|
78
|
+
return Object.assign({
|
79
|
+
browsers: this.browsers,
|
80
|
+
base: this.base,
|
81
|
+
env: this.env,
|
82
|
+
watch: this.env === 'development'
|
83
|
+
}, this._opts)
|
84
|
+
}
|
85
|
+
|
65
86
|
// write assets to disk
|
66
87
|
// (str, fn) -> void
|
67
88
|
build (dir, state) {
|
68
89
|
assert(typeof dir === 'string', 'jalla:build dir should be type string')
|
69
90
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
watch: false,
|
74
|
-
dist: dir
|
75
|
-
}, this._opts, state)
|
91
|
+
if (!path.isAbsolute(dir)) dir = path.resolve(dir)
|
92
|
+
|
93
|
+
state = Object.assign({}, this.state, state, { dist: dir, watch: false })
|
76
94
|
|
77
95
|
return new Promise((resolve, reject) => {
|
78
|
-
|
96
|
+
fs.mkdir(dir, { recursive: true }, (err) => {
|
79
97
|
if (err) return reject(err)
|
80
98
|
var index = this.pipeline.get('build').push(build)
|
81
99
|
this.pipeline.bundle(this.entry, state, (err) => {
|
@@ -87,12 +105,24 @@ module.exports = class App extends Koa {
|
|
87
105
|
})
|
88
106
|
}
|
89
107
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
108
|
+
bundle () {
|
109
|
+
this.bundled = true
|
110
|
+
var init = new Promise((resolve, reject) => {
|
111
|
+
this.pipeline.bundle(this.entry, this.state, function (err) {
|
112
|
+
if (err) return reject(err)
|
113
|
+
resolve()
|
114
|
+
})
|
115
|
+
})
|
116
|
+
this.middleware.unshift((ctx, next) => init.then(next))
|
117
|
+
return init
|
118
|
+
}
|
119
|
+
|
120
|
+
listen (port = 8080, cb) {
|
121
|
+
var self = this
|
122
|
+
if (!this.state.serve && !this.bundled) this.bundle()
|
123
|
+
return super.listen(port, function () {
|
124
|
+
self.emit('start', port)
|
125
|
+
if (typeof cb === 'function') return cb.apply(this, arguments)
|
96
126
|
})
|
97
127
|
}
|
98
128
|
}
|
package/lib/build.js
CHANGED
@@ -1,86 +1,14 @@
|
|
1
1
|
var fs = require('fs')
|
2
2
|
var util = require('util')
|
3
3
|
var path = require('path')
|
4
|
-
var brfs = require('brfs')
|
5
|
-
var mkdirp = require('mkdirp')
|
6
|
-
var crypto = require('crypto')
|
7
|
-
var tfilter = require('tfilter')
|
8
|
-
var through = require('through2')
|
9
|
-
var babelify = require('babelify')
|
10
|
-
var exorcist = require('exorcist')
|
11
|
-
var uglifyify = require('uglifyify')
|
12
|
-
var browserify = require('browserify')
|
13
|
-
var unassertify = require('unassertify')
|
14
|
-
var shakeify = require('common-shakeify')
|
15
|
-
var splitRequire = require('split-require')
|
16
|
-
var babelPresetEnv = require('@babel/preset-env')
|
17
|
-
var inject = require('./inject')
|
18
4
|
|
19
|
-
var createDir = util.promisify(
|
5
|
+
var createDir = util.promisify(fs.mkdir)
|
20
6
|
var writeFile = util.promisify(fs.writeFile)
|
21
7
|
|
22
|
-
module.exports =
|
23
|
-
|
24
|
-
function ssr (state, emit) {
|
25
|
-
var name = path.basename(state.entry)
|
26
|
-
var b = browserify(state.entry, {
|
27
|
-
node: true,
|
28
|
-
debug: true,
|
29
|
-
ignoreMissing: true,
|
30
|
-
// preserve paths for split-require to resolve during runtime
|
31
|
-
fullPaths: true,
|
32
|
-
standalone: name
|
33
|
-
})
|
34
|
-
|
35
|
-
capture()
|
36
|
-
b.on('reset', capture)
|
37
|
-
|
38
|
-
b.plugin(splitRequire, {
|
39
|
-
public: state.dist,
|
40
|
-
filename: dynamicBundleName,
|
41
|
-
output: bundleDynamicBundle
|
42
|
-
})
|
43
|
-
|
44
|
-
b.on('split.pipeline', function (pipeline, entry, name) {
|
45
|
-
var map = path.resolve(state.dist, name + '.map')
|
46
|
-
pipeline.get('wrap').push(exorcist(map))
|
47
|
-
})
|
48
|
-
|
49
|
-
b.transform(tfilter(babelify, { exclude: /node_modules/ }), {
|
50
|
-
plugins: ['dynamic-import-split-require'],
|
51
|
-
babelrc: false,
|
52
|
-
presets: [
|
53
|
-
[babelPresetEnv, {
|
54
|
-
targets: { node: 'current' }
|
55
|
-
}]
|
56
|
-
]
|
57
|
-
})
|
58
|
-
|
59
|
-
b.transform(brfs)
|
60
|
-
b.transform(inject('source-map-support/register', state.entry))
|
61
|
-
|
62
|
-
if (state.env !== 'development') {
|
63
|
-
b.transform(unassertify, { global: true })
|
64
|
-
b.transform(uglifyify, { global: true })
|
65
|
-
b.plugin(shakeify)
|
66
|
-
}
|
67
|
-
|
68
|
-
b.on('reset', function restart () {
|
69
|
-
emit('progress', name, 0)
|
70
|
-
})
|
8
|
+
module.exports = build
|
71
9
|
|
10
|
+
function build (state, emit) {
|
72
11
|
return function bundle (cb) {
|
73
|
-
var map = path.resolve(state.dist, name + '.map')
|
74
|
-
var ssr = new Promise(function (resolve, reject) {
|
75
|
-
b.bundle().on('error', reject)
|
76
|
-
// can't run terser in tandem due it generating octal escaped sequences
|
77
|
-
// in template strings which it then can't parse
|
78
|
-
// .pipe(state.env !== 'development' ? minify() : through())
|
79
|
-
.pipe(state.env !== 'development' ? exorcist(map) : through())
|
80
|
-
.pipe(fs.createWriteStream(path.resolve(state.dist, name), 'utf8'))
|
81
|
-
.on('close', resolve)
|
82
|
-
})
|
83
|
-
|
84
12
|
var re = new RegExp(`^(?:${state.base.replace(/\//g, '\\/')})?\\/`)
|
85
13
|
var assets = Array.from(state.assets.values(), function (asset) {
|
86
14
|
asset.file = asset.url.replace(re, '')
|
@@ -88,70 +16,26 @@ function ssr (state, emit) {
|
|
88
16
|
})
|
89
17
|
|
90
18
|
var stat = JSON.stringify({
|
91
|
-
|
19
|
+
browsers: state.browsers,
|
92
20
|
assets: assets
|
93
21
|
}, stringify, 2)
|
94
22
|
|
95
23
|
emit('progress', 'stat.json', 0)
|
96
24
|
|
97
25
|
Promise.all([
|
98
|
-
|
99
|
-
|
100
|
-
...assets.map(async function (asset) {
|
101
|
-
var dest = path.resolve(state.dist, 'public', asset.file)
|
26
|
+
Promise.all(assets.map(async function (asset) {
|
27
|
+
var file = path.resolve(state.dist, 'public', asset.file)
|
102
28
|
emit('progress', asset.id, 0)
|
103
|
-
|
104
|
-
|
105
|
-
|
29
|
+
try {
|
30
|
+
await createDir(path.dirname(file), { recursive: true })
|
31
|
+
} catch (err) {
|
32
|
+
// Ignore failed `mkdir` and try writing file anyway
|
33
|
+
}
|
34
|
+
return writeFile(file, asset.buffer)
|
35
|
+
})),
|
106
36
|
writeFile(path.resolve(state.dist, 'stat.json'), stat)
|
107
37
|
]).then(cb.bind(undefined, null), cb)
|
108
38
|
}
|
109
|
-
|
110
|
-
// copy template file to dist
|
111
|
-
// () -> Promise
|
112
|
-
function template () {
|
113
|
-
return new Promise(function (resolve, reject) {
|
114
|
-
var dir = path.join(path.dirname(state.entry), 'index')
|
115
|
-
resolve('.', { basedir: dir, extensions: ['.html'] }, function (err, file) {
|
116
|
-
if (err) return resolve()
|
117
|
-
emit('progress', file, 0)
|
118
|
-
fs.readFile(file, function (err, buf) {
|
119
|
-
if (err) return reject(err)
|
120
|
-
resolve(writeFile(path.resolve(state.dist, 'index.html'), buf))
|
121
|
-
})
|
122
|
-
})
|
123
|
-
})
|
124
|
-
}
|
125
|
-
|
126
|
-
// capture bundle dependencies from pipeline
|
127
|
-
// () -> void
|
128
|
-
function capture () {
|
129
|
-
emit('reset')
|
130
|
-
b.pipeline.get('deps').push(through.obj(function (row, enc, next) {
|
131
|
-
var file = row.expose ? b._expose[row.id] : row.file
|
132
|
-
emit('dep', file)
|
133
|
-
this.push(row)
|
134
|
-
next()
|
135
|
-
}))
|
136
|
-
}
|
137
|
-
|
138
|
-
// generate name for dýnamic bundle
|
139
|
-
// obj -> str
|
140
|
-
function dynamicBundleName (record) {
|
141
|
-
var basename = path.basename(record.sourceFile, '.js')
|
142
|
-
var isIndex = basename === 'index'
|
143
|
-
var id = basename
|
144
|
-
if (isIndex) id = path.dirname(record.sourceFile).split('/').slice(-1)[0]
|
145
|
-
var buff = Buffer.from(record.source)
|
146
|
-
var hash = crypto.createHash('sha512').update(buff).digest('buffer')
|
147
|
-
return `${id}-${hash.toString('hex').slice(0, 16)}.js`
|
148
|
-
}
|
149
|
-
|
150
|
-
// handle dynamic bundle
|
151
|
-
// str -> stream.Writable
|
152
|
-
function bundleDynamicBundle (name) {
|
153
|
-
return fs.createWriteStream(path.resolve(state.dist, name), 'utf8')
|
154
|
-
}
|
155
39
|
}
|
156
40
|
|
157
41
|
// JSON.stringify replacer
|
package/lib/compile.js
CHANGED
@@ -3,6 +3,7 @@ var { addHook } = require('pirates')
|
|
3
3
|
var clearModule = require('clear-module')
|
4
4
|
|
5
5
|
var SCRIPT = /\.js$/
|
6
|
+
var NODE_MODULES = /node_modules/
|
6
7
|
|
7
8
|
module.exports = compile
|
8
9
|
|
@@ -10,14 +11,16 @@ function compile (state, emit) {
|
|
10
11
|
addHook(hook, { matcher })
|
11
12
|
|
12
13
|
return function (cb) {
|
13
|
-
for (
|
14
|
-
if (SCRIPT.test(dep))
|
14
|
+
for (const dep of state.deps) {
|
15
|
+
if (SCRIPT.test(dep) && !NODE_MODULES.test(dep) && !state.skip(dep)) {
|
16
|
+
clearModule(dep)
|
17
|
+
}
|
15
18
|
}
|
16
19
|
cb()
|
17
20
|
}
|
18
21
|
|
19
22
|
function matcher (file) {
|
20
|
-
if (
|
23
|
+
if (NODE_MODULES.test(file) || state.skip(file)) return false
|
21
24
|
return state.deps.has(file)
|
22
25
|
}
|
23
26
|
|