UNPKG

5.33 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.prod.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 // add new line
105 console.log()
106 }
107
108 console.log(chalk.green(`Build complete in ${result.time}ms\n`))
109 console.log('File sizes after gzip:\n')
110
111 result.assets['__dist'] = outputPath
112
113 buildReporter(
114 // page 为数组
115 { page: [result.assets] },
116 WARN_AFTER_BUNDLE_GZIP_SIZE,
117 WARN_AFTER_CHUNK_GZIP_SIZE
118 )
119
120 console.log()
121 console.log(
122 `The ${chalk.cyan(
123 'dist/' + entryInput.entry
124 )} directory is ready to be deployed.\n`
125 )
126
127 if (publicPath === '/') {
128 console.log(
129 chalk.yellow(
130 `The app is built assuming that it will be deployed at the root of a domain.`
131 )
132 )
133 console.log(
134 chalk.yellow(
135 `If you intend to deploy it under a subpath, update the ${chalk.green(
136 'publicPath'
137 )} option in your project config (${chalk.cyan(
138 `marauder.config.js`
139 )}).\n`
140 )
141 )
142 }
143
144 return entryInput
145}
146
147async function deploy({ entry, ftpBranch, entryArgs, remotePath }) {
148 if (maraConf.hybrid && remotePath) {
149 await hybridDevPublish(entry, remotePath)
150 } else if (entryArgs.test !== null) {
151 await hybridTestPublish(entry, entryArgs.test)
152 }
153}
154
155function error(err) {
156 console.log(chalk.red('\n🕳 Failed to compile.\n'))
157 printBuildError(err)
158 process.exit(1)
159}
160
161function genBuildJson(compilation) {
162 const source = JSON.stringify({
163 debug: maraConf.debug || process.env.MARA_compileModel == 'dev',
164 // 指定缺省场景(undefined)为 web
165 target: process.env.jsbridgeBuildType === 'app' ? 'app' : 'web',
166 marax: require(paths.ownPackageJson).version
167 })
168
169 compilation.assets['build.json'] = {
170 source: () => source,
171 size: () => source.length
172 }
173}
174
175function ftp({ entry, entryArgs, ftpBranch }) {
176 if (ftpBranch === null)
177 return {
178 entry,
179 entryArgs,
180 ftpBranch
181 }
182
183 return uploadDir(entry, ftpBranch).then(remotePath => ({
184 entry,
185 ftpBranch,
186 entryArgs,
187 remotePath
188 }))
189}
190
191function setup(entryInput) {
192 spinner.start()
193
194 return entryInput
195}
196
197// finally fn
198function done() {
199 const date = new Date()
200 const hour = date.getHours()
201
202 hour > 21 && console.log(chalk.magenta('🚜 marauder loves you'))
203}
204
205module.exports = args => {
206 return getEntry(args)
207 .then(setup)
208 .then(clean)
209 .then(build)
210 .then(success)
211 .then(ftp)
212 .then(deploy)
213 .then(done)
214 .catch(error)
215}