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