jalla 1.0.0-4 → 1.0.0-40
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|