Created
August 14, 2020 05:29
-
-
Save gseok/646c1fae9045e42fa44f1da425962185 to your computer and use it in GitHub Desktop.
run-server-watch-with
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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