UNPKG

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