UNPKG

5.24 kBJavaScriptView Raw
1'use strict'
2
3// 确保在文件首部设置环境变量
4process.env.BABEL_ENV = 'production'
5process.env.NODE_ENV = 'production'
6
7process.on('unhandledRejection', err => {
8 throw err
9})
10
11const fs = require('fs-extra')
12const chalk = require('chalk')
13const path = require('path')
14const ora = require('ora')
15const webpack = require('webpack')
16const getEntry = require('../libs/entry')
17const { uploadDir } = require('../libs/ftp')
18const config = require('../config')
19const paths = config.paths
20const getWebpackConfig = require('../webpack/webpack.mc.conf')
21const maraConf = require(paths.marauder)
22const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages')
23const { hybridDevPublish, hybridTestPublish } = require('../libs/hybrid')
24const printBuildError = require('../libs/printBuildError')
25const buildReporter = require('../libs/buildReporter')
26const prehandleConfig = require('../libs/prehandleConfig')
27
28// These sizes are pretty large. We'll warn for bundles exceeding them.
29const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024
30const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024
31
32const spinner = ora('building for production...')
33
34function build({ entryInput, dist }) {
35 let webpackConfig = getWebpackConfig(entryInput)
36 webpackConfig = prehandleConfig('build', webpackConfig)
37 const compiler = webpack(webpackConfig)
38
39 compiler.plugin('compilation', compilation => {
40 // genHybridVer(compilation)
41 genBuildJson(compilation)
42 })
43
44 return new Promise((resolve, reject) => {
45 compiler.run((err, stats) => {
46 let messages
47
48 spinner.stop()
49
50 if (err) {
51 if (!err.message) {
52 return reject(err)
53 }
54 messages = formatWebpackMessages({
55 errors: [err.message],
56 warnings: []
57 })
58 } else {
59 messages = formatWebpackMessages(
60 stats.toJson({ all: false, warnings: true, errors: true })
61 )
62 }
63
64 if (messages.errors.length) {
65 // Only keep the first error. Others are often indicative
66 // of the same problem, but confuse the reader with noise.
67 if (messages.errors.length > 1) {
68 messages.errors.length = 1
69 }
70 return reject(new Error(messages.errors.join('\n\n')))
71 }
72
73 return resolve({
74 entryInput,
75 stats,
76 publicPath: webpackConfig.output.publicPath,
77 outputPath: webpackConfig.output.path,
78 warnings: messages.warnings
79 })
80 })
81 })
82}
83
84function clean(entryInput) {
85 const dist = path.join(paths.dist, entryInput.entry)
86
87 return fs.emptyDir(dist).then(() => ({
88 entryInput,
89 dist
90 }))
91}
92
93function success({ entryInput, stats, publicPath, outputPath, warnings }) {
94 const result = stats.toJson({
95 hash: false,
96 chunks: false,
97 modules: false,
98 chunkModules: false
99 })
100
101 if (warnings.length) {
102 console.log(chalk.yellow('Compiled with warnings:\n'))
103 console.log(warnings.join('\n\n'))
104 }
105
106 console.log(chalk.green(`Build complete in ${result.time}ms\n`))
107 console.log('File sizes after gzip:\n')
108
109 result.assets['__dist'] = outputPath
110
111 buildReporter(
112 // page 为数组
113 { page: [result.assets] },
114 WARN_AFTER_BUNDLE_GZIP_SIZE,
115 WARN_AFTER_CHUNK_GZIP_SIZE
116 )
117
118 console.log()
119 console.log(
120 `The ${chalk.cyan(
121 'dist/' + entryInput.entry
122 )} directory is ready to be deployed.\n`
123 )
124
125 if (publicPath === '/') {
126 console.log(
127 chalk.yellow(
128 `The app is built assuming that it will be deployed at the root of a domain.`
129 )
130 )
131 console.log(
132 chalk.yellow(
133 `If you intend to deploy it under a subpath, update the ${chalk.green(
134 'publicPath'
135 )} option in your project config (${chalk.cyan(
136 `marauder.config.js`
137 )}).\n`
138 )
139 )
140 }
141
142 return entryInput
143}
144
145async function deploy({ entry, ftpBranch, entryArgs, remotePath }) {
146 if (maraConf.hybrid && remotePath) {
147 await hybridDevPublish(entry, remotePath)
148 } else if (entryArgs.test !== null) {
149 await hybridTestPublish(entry, entryArgs.test)
150 }
151}
152
153function error(err) {
154 console.log(chalk.red('\n🕳 Failed to compile.\n'))
155 printBuildError(err)
156 process.exit(1)
157}
158
159function genBuildJson(compilation) {
160 const source = JSON.stringify({
161 debug: maraConf.debug || process.env.MARA_compileModel == 'dev',
162 // 指定缺省场景(undefined)为 web
163 target: process.env.jsbridgeBuildType === 'app' ? 'app' : 'web'
164 })
165
166 compilation.assets['build.json'] = {
167 source: () => source,
168 size: () => source.length
169 }
170}
171
172function ftp({ entry, entryArgs, ftpBranch }) {
173 if (ftpBranch === null)
174 return {
175 entry,
176 entryArgs,
177 ftpBranch
178 }
179
180 return uploadDir(entry, ftpBranch).then(remotePath => ({
181 entry,
182 ftpBranch,
183 entryArgs,
184 remotePath
185 }))
186}
187
188function setup(entryInput) {
189 spinner.start()
190
191 return entryInput
192}
193
194// finally fn
195function done() {
196 const date = new Date()
197 const hour = date.getHours()
198
199 hour > 21 && console.log(chalk.magenta('🚜 marauder loves you'))
200}
201
202module.exports = args => {
203 return getEntry(args)
204 .then(setup)
205 .then(clean)
206 .then(build)
207 .then(success)
208 .then(ftp)
209 .then(deploy)
210 .then(done)
211 .catch(error)
212}