neex 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +226 -39
- package/dist/src/cli.js +113 -28
- package/dist/src/dev-runner.js +21 -15
- package/feet.txt +16 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
</picture>
|
|
7
7
|
</a>
|
|
8
8
|
|
|
9
|
-
# Neex v0.1.
|
|
9
|
+
# Neex v0.1.6
|
|
10
10
|
|
|
11
11
|
### 🚀 Neex: The Modern Build System for Polyrepo-in-Monorepo Architecture
|
|
12
12
|
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
|
|
21
21
|
next + express = neex 🌱
|
|
22
22
|
|
|
23
|
-
Neex is a modern build system designed
|
|
23
|
+
Neex is a modern build system and script runner designed for **Polyrepo-in-Monorepo** architectures, but powerful enough for any project. It simplifies managing and running multiple scripts across your project, whether they are microservices, frontend applications, or build tasks. Neex offers robust features like parallel and sequential execution, live-reloading for development (`watch`), optimized server running (`servers`), and even basic process management (`pm2`-like commands), all aimed at making your development workflow more efficient, organized, and visually clear.
|
|
24
24
|
|
|
25
25
|
## ✨ Key Features
|
|
26
26
|
|
|
27
27
|
- 🎨 **Colored Output** - Distinguish commands with unique colors
|
|
28
|
-
- ⚡ **Dual Execution Modes** - Run commands in parallel (`
|
|
28
|
+
- ⚡ **Dual Execution Modes** - Run commands in parallel (`px`) or sequence (`s`, `run`)
|
|
29
29
|
- ⏱️ **Smart Timing** - Track execution time for each command
|
|
30
30
|
- 🛑 **Error Control** - Stop on first error (perfect for CI/CD)
|
|
31
31
|
- 🔢 **Parallel Control** - Limit concurrent processes with `--max-parallel`
|
|
@@ -34,7 +34,24 @@ Neex is a modern build system designed to bridge the gap between polyrepo and mo
|
|
|
34
34
|
- 🤫 **Flexible Display** - Control prefixes, timing, and output visibility
|
|
35
35
|
- 🧰 **Node.js API** - Programmatic usage in your applications
|
|
36
36
|
|
|
37
|
-
##
|
|
37
|
+
## 🚀 Installation
|
|
38
|
+
|
|
39
|
+
Install Neex globally to use it anywhere, or locally in your project.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Global install
|
|
43
|
+
npm install -g neex
|
|
44
|
+
|
|
45
|
+
# Local install
|
|
46
|
+
npm install --save-dev neex # npm
|
|
47
|
+
yarn add --dev neex # yarn
|
|
48
|
+
pnpm add --save-dev neex # pnpm
|
|
49
|
+
bun add --dev neex # bun
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
When installed locally, you can run Neex commands using `npx neex ...` or by adding them to your `package.json` scripts.
|
|
53
|
+
|
|
54
|
+
## 🖥️ Usage
|
|
38
55
|
|
|
39
56
|
```bash
|
|
40
57
|
# Global install
|
|
@@ -49,35 +66,147 @@ bun add -D neex # bun
|
|
|
49
66
|
|
|
50
67
|
## 🖥️ Usage
|
|
51
68
|
|
|
52
|
-
### Commands
|
|
69
|
+
### Core Commands
|
|
70
|
+
|
|
71
|
+
Neex provides several commands to manage and run your scripts:
|
|
72
|
+
|
|
73
|
+
- **`px <commands...>`** (*default command*)
|
|
74
|
+
- Runs specified commands in **parallel** by default.
|
|
75
|
+
- Use the `-q` or `--sequential` flag to run them sequentially.
|
|
76
|
+
- Ideal for build steps, tests, or any tasks that can run concurrently.
|
|
77
|
+
|
|
78
|
+
- **`run <commands...>`** (alias: `s`)
|
|
79
|
+
- Runs specified commands **sequentially**.
|
|
80
|
+
- Useful for tasks that depend on the completion of previous ones (e.g., build then deploy).
|
|
53
81
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
82
|
+
- **`servers <commands...>`** (alias: `srv`)
|
|
83
|
+
- Optimized for running multiple development **servers** (e.g., backend API, frontend app) in parallel.
|
|
84
|
+
- Provides grouped and clear output for each server, making it easy to monitor logs.
|
|
85
|
+
- Detects and displays server ports and URLs.
|
|
56
86
|
|
|
57
|
-
|
|
87
|
+
- **`watch <commands...>`** (alias: `w`)
|
|
88
|
+
- Runs commands and **watches for file changes** to automatically restart them (Nodemon-like functionality).
|
|
89
|
+
- Highly configurable with options for watched paths, ignored patterns, extensions, and restart delays.
|
|
90
|
+
- Perfect for development workflows where you need instant feedback on code changes.
|
|
91
|
+
|
|
92
|
+
- **Process Management Commands**
|
|
93
|
+
- Neex provides built-in process management capabilities, similar to PM2, for long-running applications. These commands operate directly under `neex`:
|
|
94
|
+
- **`start <script_path_or_command> [--name <name>] [--watch] [-- <args...>]`**: Start a new process.
|
|
95
|
+
- **`stop <name_or_id>`**: Stop a running process.
|
|
96
|
+
- **`restart <name_or_id>`**: Restart a running process.
|
|
97
|
+
- **`delete <name_or_id>`**: Stop and delete a process from the list.
|
|
98
|
+
- **`list`** (aliases: `ls`, `status`): List all managed processes.
|
|
99
|
+
- **`logs [name_or_id] [--lines <number>] [--follow]`**: Display logs for a specific process or all if no ID is given.
|
|
100
|
+
- **`monit`**: Launch a monitoring interface for all managed processes.
|
|
101
|
+
- **`save`**: Save the current list of running processes.
|
|
102
|
+
- **`resurrect`**: Restart processes that were previously saved.
|
|
103
|
+
- **`startup`**: Generate a sample startup script (e.g., for systemd).
|
|
104
|
+
|
|
105
|
+
### General Command Examples
|
|
58
106
|
|
|
59
107
|
```bash
|
|
60
|
-
# Parallel execution (default)
|
|
61
|
-
neex
|
|
108
|
+
# Parallel execution (default behavior for px)
|
|
109
|
+
neex px "npm run build:api" "npm run build:frontend" "npm run lint"
|
|
110
|
+
# px is the command for parallel execution
|
|
111
|
+
neex px "npm run test:unit" "npm run test:integration"
|
|
62
112
|
|
|
63
113
|
# Sequential execution
|
|
64
|
-
neex
|
|
114
|
+
neex run "npm run clean" "npm run build" "npm run deploy"
|
|
115
|
+
# Alias for sequential
|
|
116
|
+
neex s "echo First" "echo Second" "echo Third"
|
|
117
|
+
|
|
118
|
+
# Run 'px' commands sequentially using the -q flag
|
|
119
|
+
neex px -q "npm run step1" "npm run step2"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `servers` Command Examples
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Start frontend and backend development servers
|
|
126
|
+
neex servers "cd frontend && npm start" "cd backend && npm start"
|
|
65
127
|
|
|
66
|
-
#
|
|
67
|
-
neex
|
|
128
|
+
# Group output for better readability
|
|
129
|
+
neex servers --group-output "npm run dev:service-a" "npm run dev:service-b"
|
|
68
130
|
```
|
|
69
131
|
|
|
70
|
-
###
|
|
132
|
+
### `watch` Command Examples
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Watch for changes in './src' and restart 'npm run build'
|
|
136
|
+
neex watch "npm run build" -w ./src
|
|
137
|
+
|
|
138
|
+
# Watch for .ts file changes in 'services/' and restart two commands, ignoring 'node_modules'
|
|
139
|
+
neex watch "npm run start:service1" "npm run start:service2" -w services/ -e ts -i node_modules/**
|
|
71
140
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
141
|
+
# Clear console on restart and set a delay
|
|
142
|
+
neex watch "node server.js" --clear --delay 1500
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Process Management Command Examples
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Start a Node.js app and give it a name
|
|
149
|
+
neex start server.js --name my-app
|
|
150
|
+
|
|
151
|
+
# Start an app and watch for file changes
|
|
152
|
+
neex start api/index.js --name my-api --watch
|
|
153
|
+
|
|
154
|
+
# List all running processes managed by neex
|
|
155
|
+
neex list
|
|
156
|
+
|
|
157
|
+
# View logs for 'my-app'
|
|
158
|
+
neex logs my-app
|
|
159
|
+
|
|
160
|
+
# Stop 'my-api'
|
|
161
|
+
neex stop my-api
|
|
162
|
+
|
|
163
|
+
# Restart 'my-app'
|
|
164
|
+
neex restart my-app
|
|
165
|
+
|
|
166
|
+
# Delete 'my-api' from neex management
|
|
167
|
+
neex delete my-api
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 🛠️ Global Options (for `run`, `px`, `servers`)
|
|
171
|
+
|
|
172
|
+
These options can be used with `run`, `px`, and `servers` commands:
|
|
173
|
+
|
|
174
|
+
| Flag | Alias | Description | Default |
|
|
175
|
+
|--------------------------|-------|---------------------------------------------------|----------------|
|
|
176
|
+
| `--no-color` | `-c` | Disable colored output | `true` (color on) |
|
|
177
|
+
| `--no-timing` | `-t` | Hide timing information for each command | `true` (timing on) |
|
|
178
|
+
| `--no-prefix` | `-p` | Hide command prefix in output | `true` (prefix on) |
|
|
179
|
+
| `--stop-on-error` | `-s` | Stop all further execution if a command fails | `false` |
|
|
180
|
+
| `--no-output` | `-o` | Hide all `stdout` and `stderr` from commands | `true` (output on) |
|
|
181
|
+
| `--minimal` | | Use minimal output format (less verbose) | `false` |
|
|
182
|
+
| `--max-parallel <number>`| | Maximum number of commands to run in parallel | CPU count |
|
|
183
|
+
| `--sequential` | `-q` | (For `px`) Run commands sequentially instead of parallel | `false` |
|
|
184
|
+
| `--retry <count>` | | Number of times to retry a failed command | `0` |
|
|
185
|
+
| `--retry-delay <ms>` | | Delay in milliseconds between retries | `1000` |
|
|
186
|
+
| `--group-output` | `-g` | (For `servers`) Group output by server | `false` |
|
|
187
|
+
|
|
188
|
+
### `watch` Command Options
|
|
189
|
+
|
|
190
|
+
| Flag | Alias | Description | Default |
|
|
191
|
+
|-----------------------------|-------|------------------------------------------------------|--------------------------------------------|
|
|
192
|
+
| `--watch <paths...>` | `-w` | Paths/glob patterns to watch | `['./']` |
|
|
193
|
+
| `--ignore <patterns...>` | `-i` | Paths/glob patterns to ignore | `['node_modules/**', '.git/**', ...]` |
|
|
194
|
+
| `--ext <extensions...>` | `-e` | File extensions to watch | `['js', 'mjs', 'json', 'ts', 'tsx', 'jsx']`|
|
|
195
|
+
| `--delay <ms>` | `-d` | Delay in milliseconds before restarting after a change | `1000` |
|
|
196
|
+
| `--clear` | | Clear console on restart | `false` |
|
|
197
|
+
| `--verbose` | | Show verbose output from the watcher | `false` |
|
|
198
|
+
| `--signal <signal>` | | Signal to send to processes on restart | `SIGTERM` |
|
|
199
|
+
| *Global options also apply* | | `no-color`, `no-timing`, etc. | |
|
|
200
|
+
|
|
201
|
+
### `start` Command Options
|
|
202
|
+
|
|
203
|
+
| Flag | Description | Default |
|
|
204
|
+
|-----------------------------|--------------------------------------------------|-----------|
|
|
205
|
+
| `--name <name>` | Specify a name for the process | Script name |
|
|
206
|
+
| `--watch` | Enable file watching and auto-restart | `false` |
|
|
207
|
+
| `--ignore-watch <paths...>` | Paths/patterns to ignore when watching | |
|
|
208
|
+
| `--watch-delay <ms>` | Delay for watch restarts | `1000` |
|
|
209
|
+
| `-- <args...>` | Arguments to pass to the script | |
|
|
81
210
|
|
|
82
211
|
|
|
83
212
|
### Advanced Example
|
|
@@ -115,17 +244,38 @@ async function main() {
|
|
|
115
244
|
}
|
|
116
245
|
```
|
|
117
246
|
|
|
118
|
-
### API Options
|
|
247
|
+
### API Options (`RunOptions`)
|
|
248
|
+
|
|
249
|
+
When using Neex programmatically, you can pass an options object to the `run` function:
|
|
119
250
|
|
|
120
251
|
```typescript
|
|
121
|
-
interface RunOptions {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
printOutput
|
|
128
|
-
|
|
252
|
+
export interface RunOptions {
|
|
253
|
+
// Run in parallel or sequentially
|
|
254
|
+
parallel: boolean;
|
|
255
|
+
// Maximum number of parallel processes (default: CPU count)
|
|
256
|
+
maxParallel?: number;
|
|
257
|
+
// Show command output (default: true)
|
|
258
|
+
printOutput: boolean;
|
|
259
|
+
// Color output (default: true)
|
|
260
|
+
color: boolean;
|
|
261
|
+
// Show timing information (default: true)
|
|
262
|
+
showTiming: boolean;
|
|
263
|
+
// Show command prefix (default: true)
|
|
264
|
+
prefix: boolean;
|
|
265
|
+
// Stop on error (default: false)
|
|
266
|
+
stopOnError: boolean;
|
|
267
|
+
// Use minimal output format (default: false)
|
|
268
|
+
minimalOutput: boolean;
|
|
269
|
+
// Group output by command (default: false, mainly for server mode)
|
|
270
|
+
groupOutput: boolean;
|
|
271
|
+
// Use server mode formatting (default: false)
|
|
272
|
+
isServerMode: boolean;
|
|
273
|
+
// Number of times to retry a failed command (default: 0)
|
|
274
|
+
retry?: number;
|
|
275
|
+
// Delay in milliseconds between retries (default: 1000)
|
|
276
|
+
retryDelay?: number;
|
|
277
|
+
// Callback to register a cleanup function, called on SIGINT/SIGTERM
|
|
278
|
+
registerCleanup?: (cleanupFn: () => void) => void;
|
|
129
279
|
}
|
|
130
280
|
```
|
|
131
281
|
|
|
@@ -141,17 +291,54 @@ steps:
|
|
|
141
291
|
run: neex p -s -m 4 "npm run lint" "npm test" "npm run e2e"
|
|
142
292
|
```
|
|
143
293
|
|
|
144
|
-
## 💡 Real-world
|
|
294
|
+
## 💡 Real-world Scenarios & `package.json` Integration
|
|
295
|
+
|
|
296
|
+
Neex shines when integrated into your `package.json` scripts.
|
|
297
|
+
|
|
298
|
+
**Example `package.json` scripts:**
|
|
299
|
+
|
|
300
|
+
```json
|
|
301
|
+
{
|
|
302
|
+
"scripts": {
|
|
303
|
+
"dev:frontend": "cd packages/frontend && npm run dev",
|
|
304
|
+
"dev:backend": "cd packages/api && npm run dev",
|
|
305
|
+
"dev": "neex servers \"npm run dev:frontend\" \"npm run dev:backend\" --group-output",
|
|
306
|
+
|
|
307
|
+
"build:ui": "cd packages/ui-library && npm run build",
|
|
308
|
+
"build:app": "cd packages/main-app && npm run build",
|
|
309
|
+
"build": "neex runx \"npm run build:ui\" \"npm run build:app\"",
|
|
310
|
+
|
|
311
|
+
"test": "neex runx -s \"npm run test:unit\" \"npm run test:e2e\"",
|
|
312
|
+
"test:unit": "jest",
|
|
313
|
+
"test:e2e": "playwright test",
|
|
314
|
+
|
|
315
|
+
"lint": "eslint .",
|
|
316
|
+
"format": "prettier --write .",
|
|
317
|
+
"check-all": "neex p \"npm run lint\" \"npm run format -- --check\" \"npm run test\"",
|
|
318
|
+
|
|
319
|
+
"start:prod": "neex pm2 start dist/server.js --name my-prod-app",
|
|
320
|
+
"watch:build": "neex watch \"npm run build:app\" -w packages/main-app/src -e ts,tsx"
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Running these scripts:**
|
|
145
326
|
|
|
146
327
|
```bash
|
|
147
|
-
#
|
|
148
|
-
|
|
328
|
+
# Start all development servers with grouped output
|
|
329
|
+
npm run dev
|
|
330
|
+
|
|
331
|
+
# Build UI library and main application in parallel
|
|
332
|
+
npm run build
|
|
333
|
+
|
|
334
|
+
# Run linters, format check, and all tests in parallel
|
|
335
|
+
npm run check-all
|
|
149
336
|
|
|
150
|
-
#
|
|
151
|
-
|
|
337
|
+
# Start the production application using neex's pm2
|
|
338
|
+
npm run start:prod
|
|
152
339
|
|
|
153
|
-
#
|
|
154
|
-
|
|
340
|
+
# Watch for changes in the main app's src and rebuild it
|
|
341
|
+
npm run watch:build
|
|
155
342
|
```
|
|
156
343
|
|
|
157
344
|
## 🤝 Contributing
|
package/dist/src/cli.js
CHANGED
|
@@ -34,7 +34,49 @@ const process_manager_js_1 = require("./process-manager.js");
|
|
|
34
34
|
const chalk_1 = __importDefault(require("chalk"));
|
|
35
35
|
const figures_1 = __importDefault(require("figures"));
|
|
36
36
|
const path = __importStar(require("path"));
|
|
37
|
+
const fs = __importStar(require("fs/promises")); // Added for reading package.json
|
|
37
38
|
const { version } = require('../../package.json');
|
|
39
|
+
// Helper function to find default command from package.json
|
|
40
|
+
async function findDefaultCommand() {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
try {
|
|
43
|
+
const packageJsonPath = path.join(process.cwd(), 'package.json');
|
|
44
|
+
await fs.access(packageJsonPath);
|
|
45
|
+
const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
|
|
46
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
47
|
+
if ((_a = packageJson.scripts) === null || _a === void 0 ? void 0 : _a.dev) {
|
|
48
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "dev" script from package.json: npm run dev`));
|
|
49
|
+
return 'npm run dev';
|
|
50
|
+
}
|
|
51
|
+
if ((_b = packageJson.scripts) === null || _b === void 0 ? void 0 : _b.start) {
|
|
52
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} No command provided. Using "start" script from package.json: npm run start`));
|
|
53
|
+
return 'npm run start';
|
|
54
|
+
}
|
|
55
|
+
if (packageJson.main) {
|
|
56
|
+
const mainFile = packageJson.main;
|
|
57
|
+
const mainFilePath = path.resolve(process.cwd(), mainFile);
|
|
58
|
+
try {
|
|
59
|
+
await fs.access(mainFilePath);
|
|
60
|
+
if (mainFile.endsWith('.ts') || mainFile.endsWith('.mts') || mainFile.endsWith('.cts')) {
|
|
61
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (TypeScript): npx ts-node ${mainFile}`));
|
|
62
|
+
return `npx ts-node ${mainFile}`;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} No command or script found. Using "main" field (JavaScript): node ${mainFile}`));
|
|
66
|
+
return `node ${mainFile}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
// Main file doesn't exist, do nothing, will fall through to return null
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
// package.json doesn't exist or other error, do nothing
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
38
80
|
function cli() {
|
|
39
81
|
const program = new commander_1.Command();
|
|
40
82
|
let cleanupRunner = null;
|
|
@@ -80,9 +122,8 @@ function cli() {
|
|
|
80
122
|
});
|
|
81
123
|
// runx command: parallel execution by default (with alias 'p'), can run sequentially with -q
|
|
82
124
|
program
|
|
83
|
-
.command('
|
|
84
|
-
.
|
|
85
|
-
.description('Run commands in parallel (default) or sequentially with -q. Alias: p')
|
|
125
|
+
.command('px <commands...>', { isDefault: true })
|
|
126
|
+
.description('Run commands in parallel (default) or sequentially with -q. This is the default command.')
|
|
86
127
|
.option('-c, --no-color', 'Disable colored output')
|
|
87
128
|
.option('-t, --no-timing', 'Hide timing information')
|
|
88
129
|
.option('-p, --no-prefix', 'Hide command prefix')
|
|
@@ -158,7 +199,7 @@ function cli() {
|
|
|
158
199
|
});
|
|
159
200
|
// Watch command (Nodemon functionality)
|
|
160
201
|
program
|
|
161
|
-
.command('watch
|
|
202
|
+
.command('watch [commands...]') // Made commands optional
|
|
162
203
|
.alias('w')
|
|
163
204
|
.description('Run commands with file watching (nodemon functionality)')
|
|
164
205
|
.option('-c, --no-color', 'Disable colored output')
|
|
@@ -176,21 +217,66 @@ function cli() {
|
|
|
176
217
|
.option('--signal <signal>', 'Signal to send to processes on restart', 'SIGTERM')
|
|
177
218
|
.action(async (commands, options) => {
|
|
178
219
|
try {
|
|
179
|
-
|
|
220
|
+
let effectiveCommands = commands;
|
|
221
|
+
if (!effectiveCommands || effectiveCommands.length === 0) {
|
|
222
|
+
const foundCommand = await findDefaultCommand();
|
|
223
|
+
if (foundCommand) {
|
|
224
|
+
effectiveCommands = [foundCommand];
|
|
225
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} No command specified for 'neex w', using default: "${foundCommand}"`));
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
console.error(chalk_1.default.red(`${figures_1.default.cross} No command specified for 'neex w' and no default script (dev, start) or main file found in package.json.`));
|
|
229
|
+
console.error(chalk_1.default.yellow(`${figures_1.default.pointer} Please specify a command to run (e.g., neex w "npm run dev") or define a "dev" or "start" script in your package.json.`));
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else { // At least one command/argument is provided
|
|
234
|
+
const firstArg = effectiveCommands[0];
|
|
235
|
+
const remainingArgs = effectiveCommands.slice(1);
|
|
236
|
+
const isLikelyCommandOrScript = firstArg.includes(' ') || firstArg.startsWith('npm') || firstArg.startsWith('yarn') || firstArg.startsWith('pnpm');
|
|
237
|
+
if (!isLikelyCommandOrScript) {
|
|
238
|
+
const filePath = path.resolve(process.cwd(), firstArg);
|
|
239
|
+
try {
|
|
240
|
+
await fs.access(filePath); // Check if file exists
|
|
241
|
+
let commandToExecute = '';
|
|
242
|
+
if (firstArg.endsWith('.js') || firstArg.endsWith('.mjs') || firstArg.endsWith('.cjs')) {
|
|
243
|
+
commandToExecute = `node ${firstArg}`;
|
|
244
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .js file, prepending with node.`));
|
|
245
|
+
}
|
|
246
|
+
else if (firstArg.endsWith('.ts') || firstArg.endsWith('.mts') || firstArg.endsWith('.cts')) {
|
|
247
|
+
commandToExecute = `npx ts-node ${firstArg}`;
|
|
248
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} Detected .ts file, prepending with npx ts-node.`));
|
|
249
|
+
}
|
|
250
|
+
if (commandToExecute) {
|
|
251
|
+
effectiveCommands = [commandToExecute, ...remainingArgs];
|
|
252
|
+
console.log(chalk_1.default.cyan(`${figures_1.default.pointer} Executing: ${effectiveCommands.join(' ')}`));
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// Not a .js or .ts file, or file doesn't exist but doesn't look like a command either.
|
|
256
|
+
// We'll let it try to run as is. If it was meant to be a file, it will likely fail.
|
|
257
|
+
// If it was a command like 'echo', it will run.
|
|
258
|
+
console.log(chalk_1.default.yellow(`${figures_1.default.warning} First argument "${firstArg}" is not a recognized .js/.ts file and doesn't look like a script. Attempting to run as is.`));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (e) {
|
|
262
|
+
// File doesn't exist. Could be a command like 'echo foo' where 'echo' is firstArg.
|
|
263
|
+
// Or could be 'my-script --arg' where 'my-script' is not found.
|
|
264
|
+
// We'll let it try to run as is. DevRunner will handle if the command is not found.
|
|
265
|
+
console.log(chalk_1.default.yellow(`${figures_1.default.warning} File "${firstArg}" not found. Attempting to run as command.`));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// If isLikelyCommandOrScript is true, or if the file auto-detection didn't apply,
|
|
269
|
+
// effectiveCommands remains as the user provided it (joined later by DevRunner).
|
|
270
|
+
}
|
|
271
|
+
console.log(chalk_1.default.blue(`${figures_1.default.info} Starting development server with file watching (neex w) for command(s): ${effectiveCommands.map(cmd => `"${cmd}"`).join(' && ')}...`));
|
|
180
272
|
const watchPaths = options.watch || ['./'];
|
|
181
273
|
const ignorePatterns = options.ignore || [
|
|
182
|
-
'node_modules/**',
|
|
183
|
-
'.
|
|
184
|
-
'*.log',
|
|
185
|
-
'dist/**',
|
|
186
|
-
'build/**',
|
|
187
|
-
'coverage/**',
|
|
188
|
-
'.nyc_output/**',
|
|
189
|
-
'*.tmp',
|
|
190
|
-
'*.temp'
|
|
274
|
+
'node_modules/**', '.git/**', '*.log', 'dist/**', 'build/**',
|
|
275
|
+
'coverage/**', '.nyc_output/**', '*.tmp', '*.temp'
|
|
191
276
|
];
|
|
192
277
|
const extensions = options.ext || ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'];
|
|
193
278
|
devRunner = new dev_runner_js_1.DevRunner({
|
|
279
|
+
runnerName: 'neex w',
|
|
194
280
|
parallel: false,
|
|
195
281
|
color: options.color,
|
|
196
282
|
showTiming: options.timing,
|
|
@@ -207,9 +293,9 @@ function cli() {
|
|
|
207
293
|
signal: options.signal,
|
|
208
294
|
restartOnChange: true,
|
|
209
295
|
groupOutput: false,
|
|
210
|
-
isServerMode: false
|
|
296
|
+
isServerMode: false
|
|
211
297
|
});
|
|
212
|
-
await devRunner.start(
|
|
298
|
+
await devRunner.start(effectiveCommands);
|
|
213
299
|
}
|
|
214
300
|
catch (error) {
|
|
215
301
|
if (error instanceof Error) {
|
|
@@ -221,10 +307,9 @@ function cli() {
|
|
|
221
307
|
process.exit(1);
|
|
222
308
|
}
|
|
223
309
|
});
|
|
224
|
-
//
|
|
225
|
-
const pm2Group = program.command('pm2').description('Process management commands (PM2 alternative)');
|
|
310
|
+
// Process management commands
|
|
226
311
|
// Start command
|
|
227
|
-
|
|
312
|
+
program
|
|
228
313
|
.command('start <script>')
|
|
229
314
|
.description('Start a new process')
|
|
230
315
|
.option('-n, --name <name>', 'Process name')
|
|
@@ -270,7 +355,7 @@ function cli() {
|
|
|
270
355
|
}
|
|
271
356
|
});
|
|
272
357
|
// Stop command
|
|
273
|
-
|
|
358
|
+
program
|
|
274
359
|
.command('stop <id>')
|
|
275
360
|
.description('Stop a process')
|
|
276
361
|
.action(async (id) => {
|
|
@@ -299,7 +384,7 @@ function cli() {
|
|
|
299
384
|
}
|
|
300
385
|
});
|
|
301
386
|
// Restart command
|
|
302
|
-
|
|
387
|
+
program
|
|
303
388
|
.command('restart <id>')
|
|
304
389
|
.description('Restart a process')
|
|
305
390
|
.action(async (id) => {
|
|
@@ -328,7 +413,7 @@ function cli() {
|
|
|
328
413
|
}
|
|
329
414
|
});
|
|
330
415
|
// Delete command
|
|
331
|
-
|
|
416
|
+
program
|
|
332
417
|
.command('delete <id>')
|
|
333
418
|
.description('Delete a process')
|
|
334
419
|
.action(async (id) => {
|
|
@@ -357,7 +442,7 @@ function cli() {
|
|
|
357
442
|
}
|
|
358
443
|
});
|
|
359
444
|
// List/Status command
|
|
360
|
-
|
|
445
|
+
program
|
|
361
446
|
.command('list')
|
|
362
447
|
.alias('status')
|
|
363
448
|
.alias('ls')
|
|
@@ -403,7 +488,7 @@ function cli() {
|
|
|
403
488
|
}
|
|
404
489
|
});
|
|
405
490
|
// Logs command
|
|
406
|
-
|
|
491
|
+
program
|
|
407
492
|
.command('logs [id]')
|
|
408
493
|
.description('Show process logs')
|
|
409
494
|
.option('-f, --follow', 'Follow log output')
|
|
@@ -442,7 +527,7 @@ function cli() {
|
|
|
442
527
|
}
|
|
443
528
|
});
|
|
444
529
|
// Save command
|
|
445
|
-
|
|
530
|
+
program
|
|
446
531
|
.command('save')
|
|
447
532
|
.description('Save current process list')
|
|
448
533
|
.action(async () => {
|
|
@@ -465,7 +550,7 @@ function cli() {
|
|
|
465
550
|
}
|
|
466
551
|
});
|
|
467
552
|
// Startup command (placeholder for system startup configuration)
|
|
468
|
-
|
|
553
|
+
program
|
|
469
554
|
.command('startup')
|
|
470
555
|
.description('Generate startup script')
|
|
471
556
|
.action(() => {
|
|
@@ -492,7 +577,7 @@ WantedBy=multi-user.target
|
|
|
492
577
|
`));
|
|
493
578
|
});
|
|
494
579
|
// Resurrect command (start saved processes)
|
|
495
|
-
|
|
580
|
+
program
|
|
496
581
|
.command('resurrect')
|
|
497
582
|
.description('Resurrect previously saved processes')
|
|
498
583
|
.action(async () => {
|
|
@@ -527,7 +612,7 @@ WantedBy=multi-user.target
|
|
|
527
612
|
}
|
|
528
613
|
});
|
|
529
614
|
// Monit command (monitoring interface)
|
|
530
|
-
|
|
615
|
+
program
|
|
531
616
|
.command('monit')
|
|
532
617
|
.description('Launch monitoring interface')
|
|
533
618
|
.action(async () => {
|
package/dist/src/dev-runner.js
CHANGED
|
@@ -44,6 +44,7 @@ class DevRunner {
|
|
|
44
44
|
ext: ['js', 'mjs', 'json', 'ts', 'tsx', 'jsx'],
|
|
45
45
|
delay: 1000,
|
|
46
46
|
verbose: false,
|
|
47
|
+
runnerName: 'watch', // Default runner name if not specified
|
|
47
48
|
};
|
|
48
49
|
this.options = {
|
|
49
50
|
...defaultOptions,
|
|
@@ -66,7 +67,8 @@ class DevRunner {
|
|
|
66
67
|
});
|
|
67
68
|
}
|
|
68
69
|
async handleFileChange(event) {
|
|
69
|
-
|
|
70
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
71
|
+
logger_1.default.printLine(`${prefix} File changed: ${chalk_1.default.yellow(event.relativePath)}`, 'info');
|
|
70
72
|
if (this.options.clearConsole) {
|
|
71
73
|
console.clear();
|
|
72
74
|
}
|
|
@@ -87,17 +89,18 @@ class DevRunner {
|
|
|
87
89
|
}
|
|
88
90
|
}
|
|
89
91
|
printDevBanner() {
|
|
90
|
-
var _a;
|
|
92
|
+
var _a, _b;
|
|
93
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
91
94
|
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
92
95
|
const uptimeStr = this.formatUptime(uptime);
|
|
93
|
-
console.log('\n' + chalk_1.default.bgGreen.black(
|
|
96
|
+
console.log('\n' + chalk_1.default.bgGreen.black(` ${(_a = this.options.runnerName) === null || _a === void 0 ? void 0 : _a.toUpperCase()} MODE `) + '\n');
|
|
94
97
|
if (this.restartCount > 0) {
|
|
95
|
-
console.log(chalk_1.default.green(`${figures_1.default.arrowUp} Restarted ${this.restartCount} times`));
|
|
98
|
+
console.log(`${prefix} ${chalk_1.default.green(`${figures_1.default.arrowUp} Restarted ${this.restartCount} times`)}`);
|
|
96
99
|
}
|
|
97
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`));
|
|
98
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Watching: ${((
|
|
100
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Uptime: ${uptimeStr}`)}`);
|
|
101
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Watching: ${((_b = this.options.watch) === null || _b === void 0 ? void 0 : _b.join(', ')) || 'current directory'}`)}`);
|
|
99
102
|
if (this.options.ext && this.options.ext.length > 0) {
|
|
100
|
-
console.log(chalk_1.default.blue(`${figures_1.default.info} Extensions: ${this.options.ext.join(', ')}`));
|
|
103
|
+
console.log(`${prefix} ${chalk_1.default.blue(`${figures_1.default.info} Extensions: ${this.options.ext.join(', ')}`)}`);
|
|
101
104
|
}
|
|
102
105
|
console.log('');
|
|
103
106
|
}
|
|
@@ -129,18 +132,20 @@ class DevRunner {
|
|
|
129
132
|
await this.fileWatcher.start();
|
|
130
133
|
}
|
|
131
134
|
// Run initial commands
|
|
132
|
-
|
|
135
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
136
|
+
logger_1.default.printLine(`${prefix} Starting development server...`, 'info');
|
|
133
137
|
await this.runCommands();
|
|
134
138
|
// Set up graceful shutdown
|
|
135
139
|
this.setupGracefulShutdown();
|
|
136
|
-
logger_1.default.printLine(
|
|
137
|
-
logger_1.default.printLine(
|
|
140
|
+
logger_1.default.printLine(`${prefix} Development server started. Watching for changes...`, 'info');
|
|
141
|
+
logger_1.default.printLine(`${prefix} Press ${chalk_1.default.cyan('Ctrl+C')} to stop`, 'info');
|
|
138
142
|
}
|
|
139
143
|
async restart() {
|
|
144
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
140
145
|
if (!this.isRunning) {
|
|
141
146
|
return;
|
|
142
147
|
}
|
|
143
|
-
logger_1.default.printLine(
|
|
148
|
+
logger_1.default.printLine(`${prefix} Restarting due to file changes...`, 'info');
|
|
144
149
|
this.restartCount++;
|
|
145
150
|
// Stop current processes
|
|
146
151
|
if (this.runner) {
|
|
@@ -152,13 +157,14 @@ class DevRunner {
|
|
|
152
157
|
this.printDevBanner();
|
|
153
158
|
// Run commands again
|
|
154
159
|
await this.runCommands();
|
|
155
|
-
logger_1.default.printLine(
|
|
160
|
+
logger_1.default.printLine(`${prefix} Restart completed. Watching for changes...`, 'info');
|
|
156
161
|
}
|
|
157
162
|
async stop() {
|
|
163
|
+
const prefix = chalk_1.default.cyan(`[${this.options.runnerName}]`);
|
|
158
164
|
if (!this.isRunning) {
|
|
159
165
|
return;
|
|
160
166
|
}
|
|
161
|
-
logger_1.default.printLine(
|
|
167
|
+
logger_1.default.printLine(`${prefix} Stopping development server...`, 'info');
|
|
162
168
|
this.isRunning = false;
|
|
163
169
|
// Stop file watcher
|
|
164
170
|
if (this.fileWatcher) {
|
|
@@ -170,9 +176,9 @@ class DevRunner {
|
|
|
170
176
|
}
|
|
171
177
|
const uptime = Math.floor((Date.now() - this.startTime.getTime()) / 1000);
|
|
172
178
|
const uptimeStr = this.formatUptime(uptime);
|
|
173
|
-
logger_1.default.printLine(
|
|
179
|
+
logger_1.default.printLine(`${prefix} ${this.options.runnerName} development server stopped after ${uptimeStr}`, 'info');
|
|
174
180
|
if (this.restartCount > 0) {
|
|
175
|
-
logger_1.default.printLine(
|
|
181
|
+
logger_1.default.printLine(`${prefix} Total restarts: ${this.restartCount}`, 'info');
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
setupGracefulShutdown() {
|
package/feet.txt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
نمیشه توی این cli که ترکیب nodemon cuncurently pm2 هست بهش یک قابلیت اضافه کنم که یک چیز شبیه به nginx باشه که اگر بدونی هنگام دیپلوی بهینه pm2 با nginx استفاده میکنن منم میخوام وقتی neex دارن توی حالت production به عنوان pm2 ازش استفاده میکنن یک چیزی باشه که توی پروژه های شبیه به nginx درونی در neex که وظیفه نقش: وب سرور معکوس (Reverse Proxy)
|
|
3
|
+
|
|
4
|
+
کارهایی که NGINX انجام میدهد:
|
|
5
|
+
|
|
6
|
+
مدیریت درخواستها به پورت 80 یا 443 (HTTP/HTTPS)
|
|
7
|
+
|
|
8
|
+
به طور پیشفرض، اپلیکیشنهای Node روی پورتهایی مثل 3000 یا 5000 کار میکنند. NGINX روی پورتهای استاندارد (مثل 80 برای HTTP) گوش میدهد و درخواستها را به اپلیکیشن Node فوروارد میکند. لود بالانسینگ (در صورت نیاز)
|
|
9
|
+
|
|
10
|
+
اگر چند نسخه از اپلیکیشن را اجرا کردهاید (مثلاً با PM2 در حالت cluster)، NGINX میتواند بین آنها توزیع بار انجام دهد.
|
|
11
|
+
|
|
12
|
+
سرویسدهی فایلهای استاتیک
|
|
13
|
+
|
|
14
|
+
مثلاً فایلهای HTML، CSS، JS یا تصاویر میتوانند مستقیماً از طریق NGINX سرو شوند بدون درگیر کردن Node.js.
|
|
15
|
+
|
|
16
|
+
مثال کانفیگ ساده در /etc/nginx/sites-available/default: این توی پروژه های neex انجام بده این یک جوری حرفه ای بهش اضافه کن تا به خوبی اتوماتیک این داشته باشه neex
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neex",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
"start": "node dist/bin/neex.js",
|
|
13
13
|
"prepublishOnly": "npm run build",
|
|
14
14
|
"test": "jest",
|
|
15
|
-
"
|
|
15
|
+
"dev": "neex w \"ts-node src/server.ts\"",
|
|
16
|
+
"w": "neex w \"ts-node src/server.ts\"",
|
|
17
|
+
"test:dev": "node ./dist/bin/neex.js px \"echo Starting frontend\" \"echo Starting backend\"",
|
|
16
18
|
"test:parallel": "node ./dist/src/cli.js parallel \"echo Building frontend\" \"echo Building backend\"",
|
|
17
19
|
"test:sequence": "node ./dist/src/cli.js run \"echo Step 1\" \"echo Step 2\" \"echo Step 3\""
|
|
18
20
|
},
|