1 | const path = require('path')
|
2 | const EventEmitter = require('events')
|
3 | const yargs = require('yargs')
|
4 | const webpack = require('webpack')
|
5 | const PostCompilePlugin = require('post-compile-webpack-plugin')
|
6 | const webpackMerge = require('webpack-merge')
|
7 | const rm = require('rimraf')
|
8 | const ware = require('ware')
|
9 | const merge = require('lodash.merge')
|
10 | const MemoryFS = require('memory-fs')
|
11 | const webpackUtils = require('./webpack-utils')
|
12 | const createConfig = require('./create-config')
|
13 | const createServer = require('./server')
|
14 | const { promisify, readPkg } = require('./utils')
|
15 |
|
16 | function runWebpack(compiler) {
|
17 | return new Promise((resolve, reject) => {
|
18 | compiler.run((err, stats) => {
|
19 | if (err) return reject(err)
|
20 | resolve(stats)
|
21 | })
|
22 | })
|
23 | }
|
24 |
|
25 | class Poi extends EventEmitter {
|
26 | constructor(options) {
|
27 | super()
|
28 | this.options = Object.assign({
|
29 | cwd: '.',
|
30 | argv: yargs.argv,
|
31 |
|
32 | host: process.env.HOST || '0.0.0.0',
|
33 | port: process.env.PORT || 4000
|
34 | }, options)
|
35 | this.manifest = readPkg()
|
36 | this.webpackConfig = createConfig(this.options)
|
37 | this.webpackConfig.plugin('compile-notifier')
|
38 | .use(PostCompilePlugin, [stats => {
|
39 | if (this.options.mode === 'development' || this.options.mode === 'watch') {
|
40 | this.emit('compile-done', stats)
|
41 | }
|
42 | }])
|
43 | if (this.options.extendWebpack) {
|
44 | this.options.extendWebpack.call(this, this.webpackConfig)
|
45 | }
|
46 | }
|
47 |
|
48 | getWebpackConfig() {
|
49 | const config = this.webpackConfig.toConfig()
|
50 | if (this.options.webpack) {
|
51 | return typeof this.options.webpack === 'function' ?
|
52 | this.options.webpack(config) :
|
53 | webpackMerge(config, this.options.webpack)
|
54 | }
|
55 | return config
|
56 | }
|
57 |
|
58 | build() {
|
59 | return this.process()
|
60 | .then(() => {
|
61 | this.createCompiler()
|
62 | const { filename, path: outputPath } = this.compiler.options.output
|
63 |
|
64 | if (/\[(chunk)?hash:?\d?\]/.test(filename)) {
|
65 | return promisify(rm)(path.join(outputPath, '*'))
|
66 | }
|
67 | })
|
68 | .then(() => runWebpack(this.compiler))
|
69 | }
|
70 |
|
71 | watch() {
|
72 | return this.process()
|
73 | .then(() => {
|
74 | this.createCompiler()
|
75 | return this.compiler.watch({}, () => {})
|
76 | })
|
77 | }
|
78 |
|
79 | dev() {
|
80 | return this.process()
|
81 | .then(() => {
|
82 | this.createCompiler()
|
83 | return createServer(this.compiler, this.options)
|
84 | })
|
85 | }
|
86 |
|
87 | test() {
|
88 | return this.process()
|
89 | }
|
90 |
|
91 | createCompiler(webpackConfig = this.getWebpackConfig()) {
|
92 | this.compiler = webpack(webpackConfig)
|
93 | if (this.options.inMemory) {
|
94 | this.compiler.outputFileSystem = new MemoryFS()
|
95 | }
|
96 | return this
|
97 | }
|
98 |
|
99 | process(mode = this.options.mode) {
|
100 | const middlewares = []
|
101 |
|
102 | const presetContext = {
|
103 | mode: (modes, fn) => {
|
104 | const wildcard = modes === '*'
|
105 | const isMode = typeof modes === 'string' && modes === mode
|
106 | const hasMode = Array.isArray(modes) && modes.indexOf(mode) > -1
|
107 | if (wildcard || isMode || hasMode) {
|
108 | middlewares.push(fn)
|
109 | }
|
110 | },
|
111 | webpackConfig: this.webpackConfig,
|
112 | options: this.options,
|
113 | argv: this.options.argv,
|
114 | manifest: this.manifest,
|
115 | webpackUtils,
|
116 | runWebpack,
|
117 | merge
|
118 | }
|
119 |
|
120 | const presets = this.options.presets
|
121 | if (presets) {
|
122 | if (Array.isArray(presets)) {
|
123 | presets.forEach(preset => preset(presetContext))
|
124 | } else {
|
125 | presets(presetContext)
|
126 | }
|
127 | }
|
128 |
|
129 | if (!middlewares || middlewares.length === 0) {
|
130 | return Promise.resolve()
|
131 | }
|
132 |
|
133 | return new Promise((resolve, reject) => {
|
134 | ware()
|
135 | .use(middlewares)
|
136 | .run(err => {
|
137 | if (err) return reject(err)
|
138 |
|
139 | resolve()
|
140 | })
|
141 | })
|
142 | }
|
143 | }
|
144 |
|
145 | module.exports = options => new Poi(options)
|