1 | const fs = require('fs')
|
2 | const path = require('path')
|
3 | const { EventEmitter } = require('events')
|
4 |
|
5 | const mkdirp = require('mkdirp')
|
6 | const minimatch = require('minimatch')
|
7 | const babel = require('@babel/core')
|
8 | const chokidar = require('chokidar')
|
9 |
|
10 | const DEFAULT_OPTIONS = {
|
11 | persistent: true,
|
12 | delete: true,
|
13 | babel: {},
|
14 | glob: '**/*.js'
|
15 | }
|
16 |
|
17 | class BabelCompiler extends EventEmitter {
|
18 | constructor(src, dest, options) {
|
19 | super()
|
20 |
|
21 | const optionsWithDefault = Object.assign({}, DEFAULT_OPTIONS, options)
|
22 |
|
23 | this.src = src
|
24 | this.dest = dest
|
25 | this.options = optionsWithDefault
|
26 | this.ready = false
|
27 |
|
28 | mkdirp.sync(dest)
|
29 |
|
30 | const chokidarOptions = {
|
31 | cwd: src,
|
32 | persistent: optionsWithDefault.persistent
|
33 | }
|
34 |
|
35 | this.watcher = chokidar
|
36 | .watch('**/*.*', chokidarOptions)
|
37 | .on('all', (event, filepath) => this.onWatchEvent(event, filepath))
|
38 | .on('error', e => this.onError(e))
|
39 | .on('ready', () => this.onReady())
|
40 | }
|
41 |
|
42 | onWatchEvent(event, filepath = '.') {
|
43 | const srcPath = path.join(this.src, filepath)
|
44 | const destPath = path.join(this.dest, filepath)
|
45 |
|
46 | if (event === 'add' || event === 'change') {
|
47 | mkdirp.sync(path.dirname(destPath))
|
48 | if (minimatch(filepath, this.options.glob)) {
|
49 | this.compileJsFile(filepath, srcPath, destPath)
|
50 | } else {
|
51 | this.copyFile(filepath, srcPath, destPath)
|
52 | }
|
53 | }
|
54 |
|
55 | if (event === 'unlink') {
|
56 | if (this.options.delete) return
|
57 | fs.removeSync(destPath)
|
58 | this.emit('delete', filepath)
|
59 | }
|
60 |
|
61 | if (event === 'unlinkDir') {
|
62 | if (!this.options.delete) return
|
63 | fs.removeSync(destPath)
|
64 | }
|
65 | }
|
66 |
|
67 | onReady() {
|
68 | this.emit('ready')
|
69 | }
|
70 |
|
71 | onError(e) {
|
72 | this.emit('error', e)
|
73 | }
|
74 |
|
75 | compileJsFile(filepath, srcPath, destPath) {
|
76 | const babelOptions = this.options.sourceMaps
|
77 | ? {
|
78 | ...this.options.babel,
|
79 | sourceMaps: 'inline',
|
80 | sourceFileName: srcPath
|
81 | }
|
82 | : this.options.babel
|
83 |
|
84 | let result
|
85 | try {
|
86 | result = babel.transformFileSync(srcPath, babelOptions)
|
87 | } catch (error) {
|
88 | this.emit('error', filepath, error)
|
89 | return
|
90 | }
|
91 |
|
92 | fs.writeFileSync(destPath, result.code)
|
93 | this.emit('success', filepath)
|
94 | }
|
95 |
|
96 | copyFile(filepath, srcPath, destPath) {
|
97 | fs.copyFileSync(srcPath, destPath)
|
98 | this.emit('copy', filepath)
|
99 | }
|
100 |
|
101 | close() {
|
102 | this.watcher.close()
|
103 | this.removeAllListeners()
|
104 | }
|
105 | }
|
106 |
|
107 | module.exports = BabelCompiler
|