Skip to content

Commit

Permalink
2.0.0 ready, switched from parcel to webpack and updated CLI argument
Browse files Browse the repository at this point in the history
names
  • Loading branch information
couetilc committed Mar 18, 2021
1 parent 57dbe4d commit db61948
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 321 deletions.
101 changes: 36 additions & 65 deletions api.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const { spawn } = require('child_process');
const http = require('http');
const path = require('path');
const serveStatic = require('serve-static');
Expand All @@ -10,6 +9,7 @@ const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackDevServer = require('webpack-dev-server');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { ESLint } = require('eslint');

const log = console.log.bind(console); // eslint-disable-line no-console
const error = console.error.bind(console); // eslint-disable-line no-console
Expand All @@ -18,41 +18,47 @@ let VERBOSE = false;
const PORT = 61000;
const HOST = 'localhost';

// TODO get rid of outpdf everywhere, rename outdir to build-directory or something,
// and outhtml will be the out folder like output-subdirectory or something.
const commands = {
dev({ infile, outdir, outhtml, outpdf, }) {
dev({ inFile, buildDir, outDir, }) {
const config = getWebpackConfig({
mode: 'development', infile, outdir, outhtml, outpdf,
mode: 'development', inFile, buildDir, outDir,
});
const compiler = webpack(config);
const devServer = new WebpackDevServer(compiler, config.devServer);
const fileWatcher = chokidar.watch(path.join(outdir, outhtml, 'index.html'));
const fileWatcher = chokidar.watch(path.join(buildDir, outDir, 'index.html'));
fileWatcher.on('change', () => pdf({
fromUrl: `http://${config.devServer.host}:${config.devServer.port}`,
toFile: path.join(outdir, outhtml, 'resume.pdf')
toFile: path.join(buildDir, outDir, 'resume.pdf')
}));
devServer.listen(config.devServer.port, config.devServer.host);
},
test() {
// TODO this doesn't exit with a non-zero code when the eslint fails, at least in GitHub actions
spawnWrapper('npx', ['eslint', '.'])
.catch(() => {
throw new Error("ERROR: tests failed")
});
async test() {
try {
const eslint = new ESLint();
const results = await eslint.lintFiles('.');
const formatter = await eslint.loadFormatter("stylish");
const resultText = formatter.format(results);
log(resultText);
if (ESLint.getErrorResults(results).length > 0) {
throw new Error("Failed lint test");
}
} catch (e) {
error(e);
process.exit(1);
}
},
build({ infile, outdir, outhtml, outpdf, publicUrl }) {
build({ inFile, buildDir, outDir, publicUrl }) {
const compiler = webpack(
getWebpackConfig({ infile, outdir, outhtml, outpdf, publicUrl })
getWebpackConfig({ inFile, buildDir, outDir, publicUrl })
);
compiler.run((err, stats) => {
if (handleWebpackCompileErrors(err, stats)) return;
const server = startStaticServer(outdir);
const server = startStaticServer(buildDir);
server.on('listening', async () => {
try {
await pdf({
fromUrl: `http://localhost:${server.address().port}${publicUrl}`,
toFile: path.join(outdir, outhtml, 'resume.pdf')
toFile: path.join(buildDir, outDir, 'resume.pdf')
});
} catch (e) {
error(e);
Expand All @@ -62,8 +68,8 @@ const commands = {
});
});
},
serve({ outdir }) {
const server = startStaticServer(path.join(__dirname, outdir), PORT, HOST);
serve({ buildDir }) {
const server = startStaticServer(path.join(__dirname, buildDir), PORT, HOST);
server.on('listening', () => {
log('listening at %o', server.address());
});
Expand All @@ -72,10 +78,9 @@ const commands = {

function run(command, options = {}) {
const {
infile = path.join(__dirname, 'src/index.html'),
outdir = 'dist',
outhtml = '.',
outpdf = 'resume.pdf',
inFile = path.join(__dirname, 'src/index.html'),
buildDir = 'dist',
outDir = '.',
publicUrl = '/',
verbose = 0,
} = options;
Expand All @@ -84,10 +89,10 @@ function run(command, options = {}) {

if (VERBOSE) {
log('node version %o', process.version);
log('arguments: %o', { command, infile, outdir, outhtml, outpdf, publicUrl, verbose });
log('arguments: %o', { command, inFile, buildDir, outDir, publicUrl, verbose });
}

return commands[command]({ infile, outdir, outhtml, outpdf, publicUrl, verbose });
return commands[command]({ inFile, buildDir, outDir, publicUrl, verbose });
}

class Timer {
Expand Down Expand Up @@ -122,7 +127,7 @@ async function pdf({ fromUrl, toFile }) {
log('🖨️ %o created in %o', toFile, timer.seconds + 's');
}

function startStaticServer(dir, port = PORT, host = HOST) {
function startStaticServer(dir, port, host) {
const serve = serveStatic(dir);
const server = http.createServer((req, res) => {
serve(req, res, finalhandler(req, res));
Expand All @@ -131,38 +136,6 @@ function startStaticServer(dir, port = PORT, host = HOST) {
return server;
}

function spawnWrapper(...args) {
return new Promise((resolve, reject) => {
const proc = spawn(...args);
proc.stdout.on('data', data => {
process.stdout.write(data.toString());
});
proc.stderr.on('data', data => {
process.stderr.write(data.toString());
});
proc.on('close', (code, signal) => {
if (code === 0) {
if (VERBOSE) error({ code, signal, args });
resolve();
} else {
reject(signal);
}
});
proc.on('exit', (code, signal) => {
if (code === 0) {
if (VERBOSE) error({ code, signal, args });
resolve();
} else {
reject(signal);
}
});
proc.on('error', (err) => {
error('Error %o', err);
reject(err);
});
});
}

function handleWebpackCompileErrors(err, stats) {
if (err) {
error(err.stack || err);
Expand All @@ -184,15 +157,13 @@ function handleWebpackCompileErrors(err, stats) {
}

function getWebpackConfig({
// TODO change publicUrl to publicPath here and in CLI?
mode = 'production', infile, outdir, outhtml, outpdf, publicUrl
mode = 'production', inFile, buildDir, outDir, publicUrl
}) {
// TODO what ot do with outpdf and publicUrl?
return {
entry: path.join(path.dirname(infile), 'index.js'),
entry: path.join(path.dirname(inFile), 'index.js'),
mode,
output: {
path: path.resolve(outdir, outhtml),
path: path.resolve(buildDir, outDir),
filename: 'index.js',
publicPath: publicUrl,
},
Expand All @@ -219,7 +190,7 @@ function getWebpackConfig({
new MiniCssExtractPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: infile,
template: inFile,
inject: true,
})
],
Expand All @@ -230,7 +201,7 @@ function getWebpackConfig({
port: PORT,
writeToDisk: file => /index.html/ui.test(file),
useLocalIp: false,
contentBase: outdir,
contentBase: buildDir,
watchContentBase: false,
}
};
Expand Down
58 changes: 32 additions & 26 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,46 @@ function parseCliArguments(argv = process.argv) {
const command = args[0];
const options = {};

if (command === 'help' || !run.COMMANDS.includes(command)) {
if (command === 'help') {
exitWithHelp();
}

if (!run.COMMANDS.includes(command)) {
dieWithHelp("ERROR: unknown command %o", command);
}

for (args.shift(); args.length > 0; args.shift()) {
switch (args[0]) {
case '-h':
case '--help':
exitWithHelp();
break;
case '-v':
case '--verbose':
options.verbose = 1;
break;
case '--in':
if (args[1]) {
options.infile = args[1];
options.inFile = args[1];
args.shift();
} else {
dieWithHelp('ERROR: "--in" requires an non-empty argument.');
}
break;
case '--out':
case '--build':
if (args[1]) {
options.outdir = args[1];
options.buildDir = args[1];
args.shift();
} else {
dieWithHelp('ERROR: "--out" requires an non-empty argument.');
dieWithHelp('ERROR: "--build" requires an non-empty argument.');
}
break;
case '--out-html':
if (args[1]) {
options.outhtml = args[1];
args.shift();
} else {
dieWithHelp('ERROR: "--out-html" requires an non-empty argument.');
}
break;
case '--out-pdf':
case '--out':
if (args[1]) {
options.outpdf = args[1];
options.outDir = args[1];
args.shift();
} else {
dieWithHelp('ERROR: "--out-pdf" requires an non-empty argument.');
dieWithHelp('ERROR: "--out" requires an non-empty argument.');
}
break;
case '--public-url':
Expand All @@ -74,8 +74,14 @@ function parseCliArguments(argv = process.argv) {
return [command, options];
}

function exitWithHelp(...messages) {
if (messages.length) log(...messages);
help()
process.exit(0);
}

function dieWithHelp(...messages) {
error(...messages);
if (messages.length) error(...messages);
help()
process.exit(1);
}
Expand All @@ -88,7 +94,7 @@ function help() {
log(`
Usage:
${filename(process.argv[1])} <command> [--in ${ul('input-html-file')}] [--out ${ul('root-build-directory')}] [--out-html ${ul('output-html-directory')}] [--out-pdf ${ul('output-pdf-file')}] [--public-url ${ul('url')}] [--verbose]
${filename(process.argv[1])} <command> [--in ${ul('input-html-file')}] [--build ${ul('root-build-directory')}] [--out ${ul('output-html-directory')}] [--public-url ${ul('url-or-path')}] [-v|--verbose]
Description:
Expand All @@ -104,13 +110,13 @@ Commands:
Options:
--in path to the resume HTML file. Defaults to Connor's resume
--out root build directory for the project. Defaults to "dist/"
--out-html directory to output the built HTML file, relative to the root
build directory. Defaults to "."
--out-pdf path to output the resume PDF file, relative to the root build
directory. Defaults to "resume.pdf"
--public-url path where the resume's HTML assets will be hosted.
--verbose enable debug logging
--in path to the resume HTML file used as a template by Webpack.
Defaults to Connor's resume
--build root build directory for the project. Defaults to "dist/"
--out directory to output the built HTML file, relative to the root
build directory. Defaults to "."
--public-url url or path where the resume's HTML assets will be hosted.
Defaults to "/"
-v,--verbose enable debug logging
`)
}
Loading

0 comments on commit db61948

Please sign in to comment.