UNPKG

8.33 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3const fs = require('fs-extra')
4const path = require('path')
5// const util = require('util')
6// const exec = util.promisify(require('child_process').exec)
7const { spawn } = require('child_process')
8
9const program = require('commander')
10const npmRunScript = require('npm-run-script')
11const chalk = require('chalk')
12
13const before = require('./_before')
14
15const {
16 filenameBuildFail,
17} = require('../defaults/before-build')
18const sleep = require('../utils/sleep')
19// const readBuildConfigFile = require('../utils/read-build-config-file')
20const spinner = require('../utils/spinner')
21const setEnvFromCommand = require('../utils/set-env-from-command')
22const getAppType = require('../utils/get-app-type')
23const validateConfig = require('../libs/validate-config')
24const validateConfigDist = require('../libs/validate-config-dist')
25// const __ = require('../utils/translate')
26// const getCwd = require('../utils/get-cwd')
27// const emptyTempConfigDir = require('../libs/empty-temp-config-dir')
28const getDirTemp = require('../libs/get-dir-tmp')
29
30program
31 .version(require('../package').version, '-v, --version')
32 .usage('[options]')
33 .option('--no-build', 'Don\'t build')
34 // .option('--pm2', 'Start with pm2')
35 .option('--dest <destination-path>', 'Set destination directory')
36 .option('--config <config-file-path>', 'Set config file')
37 .option('--type <project-type>', 'Set project type')
38 .option('--port <port>', 'Set server port')
39 .option('--koot-test', 'Koot test mode')
40 .parse(process.argv)
41
42/**
43 * 打包生产环境,并启动服务器(如果可用)
44 */
45const run = async () => {
46 // console.log('================')
47
48 const {
49 build,
50 dest,
51 config,
52 type,
53 port,
54 kootTest = false
55 } = program
56
57 if (!kootTest)
58 // 清空 log
59 process.stdout.write('\x1B[2J\x1B[0f')
60
61 setEnvFromCommand({
62 config, type, port
63 })
64
65 process.env.KOOT_TEST_MODE = JSON.stringify(kootTest)
66
67 await before(program)
68
69 // 读取构建配置
70 const kootConfig = await validateConfig()
71 await getAppType()
72 if (dest) kootConfig.dist = validateConfigDist(dest)
73 const { dist } = kootConfig
74
75 const afterBuild = async () => {
76 // 清理临时目录
77 await fs.remove(getDirTemp())
78 // 删除过程中创建的临时文件
79 // emptyTempConfigDir()
80 }
81
82 // 打包
83 if (build) {
84 // const building = spinner(chalk.yellowBright('[koot/build] ') + __('build.building'))
85 const fileBuildFail = path.resolve(dist, filenameBuildFail)
86
87 /** @type {String} build 命令的附加参数 */
88 const buildCmdArgs = '--env prod'
89 + (typeof dest === 'string' ? ` --dest ${dest}` : '')
90 + (typeof config === 'string' ? ` --config ${config}` : '')
91 + (typeof type === 'string' ? ` --type ${type}` : '')
92 + (kootTest ? ` --koot-test` : '')
93
94 let stderr = ''
95 await new Promise(resolve => {
96 const child = spawn(
97 'koot-build',
98 buildCmdArgs.split(' '),
99 {
100 stdio: 'inherit',
101 shell: true,
102 }
103 )
104 child.on('close', () => {
105 resolve()
106 })
107 // child.on('error', (err) => {
108 // stderr = err
109 // resolve()
110 // })
111 // child.stderr.on('data', (data) => {
112 // console.log(`stderr: ${data}`);
113 // stderr += data
114 // })
115 })
116 // const { stderr } = await exec(
117 // `koot-build ${buildCmdArgs}`, {
118 // env: {
119 // KOOT_COMMAND_START: JSON.stringify(true)
120 // }
121 // }
122 // )
123 // await new Promise((resolve, reject) => {
124 // const child = npmRunScript(
125 // `koot-build`, {
126 // // stdio: 'ignore',
127 // env: {
128 // KOOT_COMMAND_START: JSON.stringify(true)
129 // }
130 // }
131 // )
132 // // child.stdin.pipe(process.stdin)
133 // // child.stdout.pipe(process.stdout)
134 // // child.stderr.pipe(process.stderr)
135 // // child.stderr.on('data', err => {
136 // // console.trace(err)
137 // // })
138 // child.once('error', (error) => {
139 // console.trace(error)
140 // process.exit(1)
141 // reject(error)
142 // })
143 // child.once('exit', (exitCode) => {
144 // // console.trace('exit in', exitCode)
145 // resolve(exitCode)
146 // // process.exit(exitCode)
147 // })
148 // console.log(child.stderr)
149 // })
150
151 // 打包过程中遭遇错误
152 if (
153 fs.existsSync(fileBuildFail) &&
154 stderr && stderr !== ' '
155 ) {
156 await afterBuild()
157
158 // 标记 spinner 为出错
159 // building.fail()
160
161 // console.log(typeof stderr)
162
163 // 打出错误报告
164 console.log('')
165 console.trace(stderr)
166
167 // 终止流程
168 return
169 }
170 // building.succeed()
171 await sleep(100)
172 }
173
174 await afterBuild()
175
176 // 运行服务器
177 const pathServerJS = path.resolve(dist, 'server/index.js')
178
179 if (!fs.existsSync(pathServerJS) || !fs.readFileSync(pathServerJS)) {
180 console.log('\n\n')
181 spinner(chalk.yellowBright('[koot/build]')).fail()
182 return
183 }
184 // if (pm2) {
185 // // PM2 方式
186 // console.log('--- pm2 ---')
187 // const pm2 = require('pm2')
188 // const packageInfo = await fs.readJson(path.resolve(getCwd(), 'package.json'))
189 // const name = `${packageInfo.name}-server`
190 // // const cmd = `pm2`
191 // // + ` pm2.json --only ${name}`
192 // pm2.start(pathServerJS, {
193 // name,
194 // "script": pathServerJS,
195 // "max_memory_restart": "300M",
196 // "instances": 1,
197 // "exec_mode": "cluster",
198 // "out_file": path.resolve(getCwd(), "logs/dev/server.log"),
199 // "error_file": path.resolve(getCwd(), "logs/dev/server-error.log")
200 // })
201 // } else {
202 // 正常方式
203 const cmd = `node ${pathServerJS.replace(/\\/g, '/')}`
204 // console.log('cmd', cmd)
205 const child = npmRunScript(cmd, {})
206 // console.log('child', child)
207 await new Promise((resolve, reject) => {
208 child.once('error', (error) => {
209 console.trace(error)
210 process.exit(1)
211 reject(error)
212 })
213 child.once('exit', (exitCode) => {
214 // console.trace('exit in', exitCode)
215 resolve(exitCode)
216 // process.exit(exitCode)
217 })
218 })
219 // }
220
221 /*
222 await new Promise((resolve, reject) => {
223 console.log({
224 'process.env': process.env
225 })
226 const cmd = `node ${pathServerJS.replace(/\\/g, '/')}`
227 const child = spawn(
228 'node',
229 [`${pathServerJS.replace(/\\/g, '/')}`]
230 )
231
232 // child.stdin.pipe(process.stdin)
233 child.stdout.pipe(process.stdout)
234 // child.stderr.pipe(process.stderr)
235 console.log(process.cwd())
236 console.log(cmd)
237
238 // const child = npmRunScript(cmd, {})
239 child.once('error', (error) => {
240 console.trace(error)
241 process.exit(1)
242 reject(error)
243 })
244 child.once('exit', (exitCode) => {
245 // console.trace('exit in', exitCode)
246 resolve(exitCode)
247 // process.exit(exitCode)
248 })
249 })
250 */
251 const exitHandler = (/*options, err*/) => {
252 child.kill('SIGINT')
253 process.exit(0)
254 }
255
256 // do something when app is closing
257 process.on('exit', exitHandler);
258 // catches ctrl+c event
259 process.on('SIGINT', exitHandler);
260 // catches "kill pid" (for example: nodemon restart)
261 process.on('SIGUSR1', exitHandler);
262 process.on('SIGUSR2', exitHandler);
263 // catches uncaught exceptions
264 process.on('uncaughtException', exitHandler);
265}
266
267run()