Skip to content

Commit 4a3d414

Browse files
committed
chore: update version to 4.0.0-beta.1 and enhance development command with nodemon integration
1 parent c424153 commit 4a3d414

2 files changed

Lines changed: 89 additions & 33 deletions

File tree

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@expressots/cli",
3-
"version": "3.0.0",
3+
"version": "4.0.0-beta.1",
44
"description": "Expressots CLI - modern, fast, lightweight nodejs web framework (@cli)",
55
"author": "Richard Zampieri",
66
"license": "MIT",
@@ -57,6 +57,7 @@
5757
"glob": "10.4.5",
5858
"inquirer": "8.2.6",
5959
"mustache": "4.2.0",
60+
"nodemon": "3.1.9",
6061
"semver": "7.6.3",
6162
"ts-node": "10.9.2",
6263
"yargs": "17.7.2"

src/commands/project.commands.ts

Lines changed: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -40,42 +40,95 @@ function getOutDir(): string {
4040
}
4141

4242
/**
43-
* Load the configuration from the compiler
44-
* @param compiler The compiler to load the configuration from
45-
* @returns The configuration
43+
* Build the tsx arguments for running TypeScript files.
44+
* Used by nodemon to execute the TypeScript entry point.
45+
*
46+
* @param opinionated - Whether to use opinionated configuration (tsconfig-paths)
47+
* @returns The tsx arguments array
4648
*/
47-
async function opinionatedConfig(): Promise<Array<string>> {
49+
async function buildTsxArgs(opinionated: boolean): Promise<Array<string>> {
4850
const { entryPoint } = await Compiler.loadConfig();
49-
const config = [
51+
52+
if (opinionated) {
53+
return ["-r", "tsconfig-paths/register", `./src/${entryPoint}.ts`];
54+
}
55+
56+
return [`./src/${entryPoint}.ts`];
57+
}
58+
59+
/**
60+
* Build the nodemon arguments for development mode.
61+
* Uses nodemon for file watching and tsx for TypeScript execution.
62+
* This combination ensures proper signal handling for graceful shutdown.
63+
*
64+
* Options:
65+
* - --quiet: Suppress nodemon verbose output, show only ExpressoTS logs (default)
66+
* - --signal SIGTERM: Ensure proper signal forwarding for graceful shutdown
67+
* - --delay 500ms: Debounce file changes to avoid rapid restarts
68+
*
69+
* @param opinionated - Whether to use opinionated configuration
70+
* @param verbose - Whether to show verbose nodemon output (for debugging)
71+
* @returns The nodemon arguments array
72+
*/
73+
async function buildDevArgs(
74+
opinionated: boolean,
75+
verbose: boolean = false,
76+
): Promise<Array<string>> {
77+
const tsxArgs = await buildTsxArgs(opinionated);
78+
79+
const args: Array<string> = [];
80+
81+
// Suppress nodemon output unless verbose mode is enabled
82+
if (!verbose) {
83+
args.push("--quiet");
84+
}
85+
86+
// Core nodemon configuration
87+
args.push(
88+
"--signal",
89+
"SIGTERM", // Use SIGTERM for graceful shutdown
90+
"--delay",
91+
"500ms", // Debounce rapid file changes
5092
"--watch",
51-
"-r",
52-
"tsconfig-paths/register",
53-
`./src/${entryPoint}.ts`,
54-
];
55-
return config;
93+
"src",
94+
"--ext",
95+
"ts,json",
96+
"--ignore",
97+
"src/**/*.spec.ts",
98+
"--ignore",
99+
"src/**/*.test.ts",
100+
"--exec",
101+
`tsx ${tsxArgs.join(" ")}`,
102+
);
103+
104+
return args;
56105
}
57106

58107
/**
59-
* Load the configuration from the compiler
60-
* @param compiler The compiler to load the configuration from
61-
* @returns The configuration
108+
* Dev command options interface
62109
*/
63-
async function nonOpinionatedConfig(): Promise<Array<string>> {
64-
const { entryPoint } = await Compiler.loadConfig();
65-
const config = ["--watch", `./src/${entryPoint}.ts`];
66-
return config;
110+
interface DevCommandOptions {
111+
verbose?: boolean;
67112
}
68113

69114
/**
70115
* Dev command module
71-
* @type {CommandModule<object, object>}
116+
* @type {CommandModule<object, DevCommandOptions>}
72117
* @returns The command module
73118
*/
74-
export const devCommand: CommandModule<object, object> = {
119+
export const devCommand: CommandModule<object, DevCommandOptions> = {
75120
command: "dev",
76121
describe: "Start development server.",
77-
handler: async () => {
78-
await runCommand({ command: "dev" });
122+
builder: {
123+
verbose: {
124+
alias: "v",
125+
type: "boolean",
126+
default: false,
127+
description: "Show verbose nodemon output for debugging",
128+
},
129+
},
130+
handler: async (argv) => {
131+
await runCommand({ command: "dev", verbose: argv.verbose });
79132
},
80133
};
81134

@@ -179,27 +232,29 @@ const clearScreen = () => {
179232
spawn(command, { stdio: "inherit", shell: true });
180233
};
181234

235+
/**
236+
* Run command options
237+
*/
238+
interface RunCommandOptions {
239+
command: string;
240+
verbose?: boolean;
241+
}
242+
182243
/**
183244
* Helper function to run a command
184-
* @param command The command to run
245+
* @param options The command options
185246
*/
186247
export const runCommand = async ({
187248
command,
188-
}: {
189-
command: string;
190-
}): Promise<void> => {
249+
verbose = false,
250+
}: RunCommandOptions): Promise<void> => {
191251
const { opinionated, entryPoint } = await Compiler.loadConfig();
192252
const outDir = getOutDir();
193253

194254
try {
195255
switch (command) {
196256
case "dev":
197-
execCmd(
198-
"tsx",
199-
opinionated
200-
? await opinionatedConfig()
201-
: await nonOpinionatedConfig(),
202-
);
257+
await execCmd("nodemon", await buildDevArgs(opinionated, verbose));
203258
break;
204259
case "build":
205260
if (!outDir) {
@@ -233,7 +288,7 @@ export const runCommand = async ({
233288
config = [`./${outDir}/${entryPoint}.js`];
234289
}
235290
clearScreen();
236-
execCmd("node", config);
291+
await execCmd("node", config);
237292
break;
238293
}
239294
default:

0 commit comments

Comments
 (0)