Skip to content

Instantly share code, notes, and snippets.

@gseok
Created August 14, 2020 05:29
Show Gist options
  • Save gseok/646c1fae9045e42fa44f1da425962185 to your computer and use it in GitHub Desktop.
Save gseok/646c1fae9045e42fa44f1da425962185 to your computer and use it in GitHub Desktop.
run-server-watch-with
#!/usr/bin/env node
const fs = require('fs');
const yargs = require('yargs');
const inquirer = require('inquirer');
const webpack = require('webpack');
const getConfig = require('./build/webpack.config');
const { spawn } = require('child_process');
let ps = null;
const startServer = (env, isWatch = false) => {
if (ps) return;
const psCommand = isWatch ?`${__dirname}/../node_modules/.bin/nodemon` : 'node';
const psArgs = isWatch ? [
'--inspect=127.0.0.1:9331',
`${__dirname}/../dist/server/server.js`,
'--watch',
`${__dirname}/../dist/server`
] : [`${__dirname}/../dist/server/server.js`];
const psOptions = { env };
ps = spawn(psCommand, psArgs, psOptions);
ps.stdout.on('data', (data) => { process.stdout.write(`${data}`); });
ps.stderr.on('data', (data) => { process.stdout.write(`${data}`); });
ps.on('close', (code) => { process.stdout.write(`child process exited with code ${code}`); });
if (isWatch) {
setTimeout(
(async () => {
const open = require('open');
await open(`http://127.0.0.1:3131`);
}),
1000
);
}
}
const getWebpackConfigs = (targetAndPhaseList) => {
return targetAndPhaseList.map((targetAndPhase) => getConfig(targetAndPhase));
}
const webpackCompilerCb = (resolve, reject, progress) => {
return (err, stats) => {
process.stdout.write('\n\r');
clearInterval(progress);
const message = stats.toString({ chunks: false, colors: true });
process.stdout.write(`${message}\n\r`);
if (err || stats.hasErrors()) {
return reject(message);
}
return resolve(message);
};
}
const buildProgress = () => {
process.stdout.write('Build is in progress');
return setInterval(() => process.stdout.write('.'), 500);
}
const runBuild = (configs) => {
const progress = buildProgress();
const compiler = webpack(configs);
return new Promise((resolve, reject) => {
compiler.run(webpackCompilerCb(resolve, reject, progress));
});
}
const runBuildWithStart = (configs, isWatch = false) => {
const pm = !isWatch ? runBuild(configs) : new Promise((resolve, reject) => {
const progress = buildProgress();
const compiler = webpack(configs);
compiler.watch({ aggregateTimeout: 300, poll: undefined }, webpackCompilerCb(resolve, reject, progress));
});
return pm.then(() => startServer(process.env, isWatch)).catch(console.error);
}
const clearDist = () => {
return new Promise((resolve) => {
const distPath = `${__dirname}/../dist`;
ps = spawn('rm', ['-rf', distPath]);
ps.stdout.on('data', (data) => { process.stdout.write(`${data}`); });
ps.stderr.on('data', (data) => { process.stdout.write(`${data}`); });
ps.on('close', () => {
ps = null;
resolve();
});
});
}
const runProgramByUserInteraction = () => {
return inquirer
.prompt([{
type: 'list',
name: 'type',
message: 'Select a run type:',
choices: [{
name: 'start:local (Server and Client All build and start by local phase)',
value: 'start:local',
}, {
name: 'start:real (Server and Client All build and start by real phase)',
value: 'start:real',
},{
name: 'build:local (Server and Client All build by local phase)',
value: 'build:local',
},{
name: 'build:real (Server and Client All build by real phase)',
value: 'build:real',
}, {
name: 'build:client:local',
value: 'build:client:local',
}, {
name: 'build:client:real',
value: 'build:client:real',
}, {
name: 'build:server:local',
value: 'build:server:local',
}, {
name: 'build:server:real',
value: 'build:server:real',
}]
}])
.then(({ type }) => {
const parsedType = type.split(':');
const actionType = parsedType[0];
if (parsedType.length === 3 && actionType === 'build') {
const target = parsedType[1];
const phase = parsedType[2];
return runBuild(getWebpackConfigs([{ target, phase }])).catch(console.error);
}
if (parsedType.length === 2) {
const phase = parsedType[1];
const configs = getWebpackConfigs([{ target: 'client', phase }, { target: 'server', phase }]);
if (actionType === 'build') return runBuild(configs).catch(console.error);
if (actionType === 'start') return runBuildWithStart(configs, phase === 'local');
}
});
}
const runProgramByCLIOption = (type) => {
const actionType = type.startsWith('s') ? 'start' : 'build';
const phase = type.includes('real') ? 'real' : 'local';
const target = (() => {
const t = type.substr(1, type.length).replace(phase, '');
if (t === 's') return 'server';
if (t === 'c') return 'client';
return '';
})();
if (target && actionType === 'build') {
return runBuild(getWebpackConfigs([{ target, phase }])).catch(console.error);
}
if (!target) {
const configs = getWebpackConfigs([{ target: 'client', phase }, { target: 'server', phase }]);
if (actionType === 'build') return runBuild(configs).catch(console.error);
if (actionType === 'start') return runBuildWithStart(configs, phase === 'local');
}
}
const run = () => {
const options = yargs
.usage("Usage: -t <type> -h <help>")
.option('t', {
alias: 'type',
describe:
`미리 정의된 type으로 build&start을 수행합니다.
slocal, sreal - 한번에 Server, Clinet build&start
blocal, breal - 한번에 Server, Client build
bclocal, bcreal - Client build
bslocal, bsreal - Server build
`,
type: 'string',
demandOption: false
})
.example('$0 -t slocal', '한번에 Server, Clinet build&start, 페이즈 local')
.example('$0 -t sreal', '한번에 Server, Clinet build&start, 페이즈 real')
.example('$0 -t blocal', '한번에 Server, Client build, 페이즈 local')
.example('$0 -t breal', '한번에 Server, Client build, 페이즈 real')
.example('$0 -t bclocal', 'Client build, 페이즈 local')
.example('$0 -t bcreal', 'Clinet build, 페이지 real')
.example('$0 -t bslocal', 'Server build, 페이즈 local')
.example('$0 -t bsreal', 'Server build, 페이즈 real')
.alias('help', 'h')
.argv;
return clearDist()
.then(() => {
return options.type ? runProgramByCLIOption(options.type) : runProgramByUserInteraction();
});
}
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment