@fecommunity/reactpress-server 1.0.3-beta.0 → 1.0.5-beta.0
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 +395 -0
- package/bin/reactpress-server.js +302 -0
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# @fecommunity/reactpress-server
|
|
2
|
+
|
|
3
|
+
NestJS-based backend API server for ReactPress - A modern React-based CMS platform.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# For new projects
|
|
9
|
+
npm install @fecommunity/reactpress-server @fecommunity/reactpress-config
|
|
10
|
+
|
|
11
|
+
# Using yarn
|
|
12
|
+
yarn add @fecommunity/reactpress-server @fecommunity/reactpress-config
|
|
13
|
+
|
|
14
|
+
# Using pnpm in workspace root (add -w flag)
|
|
15
|
+
pnpm add -w @fecommunity/reactpress-server @fecommunity/reactpress-config
|
|
16
|
+
|
|
17
|
+
# Using pnpm in standalone project
|
|
18
|
+
pnpm add @fecommunity/reactpress-server @fecommunity/reactpress-config
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- 🚀 **NestJS Framework** - Built on modern, scalable Node.js framework
|
|
24
|
+
- 🔐 **Authentication & Authorization** - JWT-based auth with role management
|
|
25
|
+
- 📝 **Content Management** - Full CRUD for articles, categories, tags, and comments
|
|
26
|
+
- 🗃️ **Database Integration** - MySQL support with TypeORM
|
|
27
|
+
- 📁 **File Upload** - Local and cloud storage support (Ali OSS)
|
|
28
|
+
- 🌍 **Internationalization** - Multi-language support
|
|
29
|
+
- 📚 **API Documentation** - Auto-generated Swagger docs
|
|
30
|
+
- 🔒 **Security** - Rate limiting, CORS, Helmet integration
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### 1. Initialize Server
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Using npx (recommended for first-time use)
|
|
38
|
+
npx @fecommunity/reactpress-server init
|
|
39
|
+
|
|
40
|
+
# Or if installed globally
|
|
41
|
+
reactpress-server init
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This will create configuration files and set up your environment.
|
|
45
|
+
|
|
46
|
+
### 2. Start Development Server
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Using npx
|
|
50
|
+
npx @fecommunity/reactpress-server dev
|
|
51
|
+
|
|
52
|
+
# Or if installed globally
|
|
53
|
+
reactpress-server dev
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The server will start on `http://localhost:3002` with API documentation at `http://localhost:3002/api`.
|
|
57
|
+
|
|
58
|
+
### 3. Start Production Server
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Using npx
|
|
62
|
+
npx @fecommunity/reactpress-server start
|
|
63
|
+
|
|
64
|
+
# Or if installed globally
|
|
65
|
+
reactpress-server start
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## CLI Commands
|
|
69
|
+
|
|
70
|
+
The package includes a powerful CLI for server management:
|
|
71
|
+
|
|
72
|
+
### Initialize Project
|
|
73
|
+
```bash
|
|
74
|
+
# Using npx (recommended)
|
|
75
|
+
npx @fecommunity/reactpress-server init [options]
|
|
76
|
+
|
|
77
|
+
# Or if installed globally
|
|
78
|
+
reactpress-server init [options]
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
-p, --port <port> Server port (default: 3002)
|
|
82
|
+
--api-prefix <prefix> API prefix (default: /api)
|
|
83
|
+
--db-host <host> Database host (default: localhost)
|
|
84
|
+
--db-port <port> Database port (default: 3306)
|
|
85
|
+
--db-name <name> Database name (default: reactpress)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Development Mode
|
|
89
|
+
```bash
|
|
90
|
+
# Using npx
|
|
91
|
+
npx @fecommunity/reactpress-server dev [options]
|
|
92
|
+
|
|
93
|
+
# Or if installed globally
|
|
94
|
+
reactpress-server dev [options]
|
|
95
|
+
|
|
96
|
+
Options:
|
|
97
|
+
-p, --port <port> Server port (default: 3002)
|
|
98
|
+
--no-open Don't open browser automatically
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Production Mode
|
|
102
|
+
```bash
|
|
103
|
+
# Using npx
|
|
104
|
+
npx @fecommunity/reactpress-server start [options]
|
|
105
|
+
|
|
106
|
+
# Or if installed globally
|
|
107
|
+
reactpress-server start [options]
|
|
108
|
+
|
|
109
|
+
Options:
|
|
110
|
+
-p, --port <port> Server port (default: 3002)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Build Project
|
|
114
|
+
```bash
|
|
115
|
+
# Using npx
|
|
116
|
+
npx @fecommunity/reactpress-server build
|
|
117
|
+
|
|
118
|
+
# Or if installed globally
|
|
119
|
+
reactpress-server build
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Environment Configuration
|
|
123
|
+
|
|
124
|
+
Create a `.env` file in your project root:
|
|
125
|
+
|
|
126
|
+
```env
|
|
127
|
+
# Server Configuration
|
|
128
|
+
SERVER_PORT=3002
|
|
129
|
+
SERVER_API_PREFIX=/api
|
|
130
|
+
NODE_ENV=development
|
|
131
|
+
|
|
132
|
+
# Database Configuration
|
|
133
|
+
DB_HOST=localhost
|
|
134
|
+
DB_PORT=3306
|
|
135
|
+
DB_USERNAME=root
|
|
136
|
+
DB_PASSWORD=your_password
|
|
137
|
+
DB_DATABASE=reactpress
|
|
138
|
+
|
|
139
|
+
# JWT Configuration
|
|
140
|
+
JWT_SECRET=your_jwt_secret_key
|
|
141
|
+
JWT_EXPIRES_IN=7d
|
|
142
|
+
|
|
143
|
+
# File Upload (Optional - Ali OSS)
|
|
144
|
+
OSS_ACCESS_KEY_ID=your_access_key_id
|
|
145
|
+
OSS_ACCESS_KEY_SECRET=your_access_key_secret
|
|
146
|
+
OSS_BUCKET=your_bucket_name
|
|
147
|
+
OSS_REGION=your_region
|
|
148
|
+
|
|
149
|
+
# Email Configuration (Optional)
|
|
150
|
+
EMAIL_HOST=smtp.gmail.com
|
|
151
|
+
EMAIL_PORT=587
|
|
152
|
+
EMAIL_USER=your_email@gmail.com
|
|
153
|
+
EMAIL_PASS=your_app_password
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Programmatic Usage
|
|
157
|
+
|
|
158
|
+
You can also use the server programmatically in your Node.js applications:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { bootstrap } from '@fecommunity/reactpress-server';
|
|
162
|
+
|
|
163
|
+
async function startServer() {
|
|
164
|
+
const app = await bootstrap({
|
|
165
|
+
port: 3002,
|
|
166
|
+
apiPrefix: '/api',
|
|
167
|
+
cors: true
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
console.log('ReactPress server started successfully!');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
startServer();
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## API Endpoints
|
|
177
|
+
|
|
178
|
+
The server provides comprehensive REST APIs:
|
|
179
|
+
|
|
180
|
+
### Authentication
|
|
181
|
+
- `POST /api/auth/login` - User login
|
|
182
|
+
- `POST /api/auth/register` - User registration
|
|
183
|
+
- `GET /api/auth/profile` - Get user profile
|
|
184
|
+
|
|
185
|
+
### Articles
|
|
186
|
+
- `GET /api/articles` - Get articles (with pagination)
|
|
187
|
+
- `POST /api/articles` - Create article
|
|
188
|
+
- `GET /api/articles/:id` - Get article by ID
|
|
189
|
+
- `PUT /api/articles/:id` - Update article
|
|
190
|
+
- `DELETE /api/articles/:id` - Delete article
|
|
191
|
+
|
|
192
|
+
### Categories
|
|
193
|
+
- `GET /api/categories` - Get all categories
|
|
194
|
+
- `POST /api/categories` - Create category
|
|
195
|
+
- `PUT /api/categories/:id` - Update category
|
|
196
|
+
- `DELETE /api/categories/:id` - Delete category
|
|
197
|
+
|
|
198
|
+
### Tags
|
|
199
|
+
- `GET /api/tags` - Get all tags
|
|
200
|
+
- `POST /api/tags` - Create tag
|
|
201
|
+
- `PUT /api/tags/:id` - Update tag
|
|
202
|
+
- `DELETE /api/tags/:id` - Delete tag
|
|
203
|
+
|
|
204
|
+
### Comments
|
|
205
|
+
- `GET /api/comments` - Get comments
|
|
206
|
+
- `POST /api/comments` - Create comment
|
|
207
|
+
- `PUT /api/comments/:id` - Update comment
|
|
208
|
+
- `DELETE /api/comments/:id` - Delete comment
|
|
209
|
+
|
|
210
|
+
### File Upload
|
|
211
|
+
- `POST /api/upload/image` - Upload image
|
|
212
|
+
- `POST /api/upload/file` - Upload file
|
|
213
|
+
|
|
214
|
+
## Database Setup
|
|
215
|
+
|
|
216
|
+
### MySQL Installation
|
|
217
|
+
|
|
218
|
+
**Ubuntu/Debian:**
|
|
219
|
+
```bash
|
|
220
|
+
sudo apt update
|
|
221
|
+
sudo apt install mysql-server
|
|
222
|
+
sudo mysql_secure_installation
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**macOS:**
|
|
226
|
+
```bash
|
|
227
|
+
brew install mysql
|
|
228
|
+
brew services start mysql
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Windows:**
|
|
232
|
+
Download and install from [MySQL Official Website](https://dev.mysql.com/downloads/mysql/)
|
|
233
|
+
|
|
234
|
+
### Database Creation
|
|
235
|
+
|
|
236
|
+
```sql
|
|
237
|
+
CREATE DATABASE reactpress;
|
|
238
|
+
CREATE USER 'reactpress'@'localhost' IDENTIFIED BY 'your_password';
|
|
239
|
+
GRANT ALL PRIVILEGES ON reactpress.* TO 'reactpress'@'localhost';
|
|
240
|
+
FLUSH PRIVILEGES;
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Advanced Usage
|
|
244
|
+
|
|
245
|
+
### Custom Configuration
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import { NestFactory } from '@nestjs/core';
|
|
249
|
+
import { AppModule } from '@fecommunity/reactpress-server';
|
|
250
|
+
|
|
251
|
+
async function bootstrap() {
|
|
252
|
+
const app = await NestFactory.create(AppModule);
|
|
253
|
+
|
|
254
|
+
// Custom middleware
|
|
255
|
+
app.use('/custom', customMiddleware);
|
|
256
|
+
|
|
257
|
+
// Custom global filters
|
|
258
|
+
app.useGlobalFilters(new CustomExceptionFilter());
|
|
259
|
+
|
|
260
|
+
await app.listen(3002);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
bootstrap();
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Plugin Development
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { Module } from '@nestjs/common';
|
|
270
|
+
import { PluginInterface } from '@fecommunity/reactpress-server';
|
|
271
|
+
|
|
272
|
+
@Module({
|
|
273
|
+
// Your plugin implementation
|
|
274
|
+
})
|
|
275
|
+
export class CustomPlugin implements PluginInterface {
|
|
276
|
+
install() {
|
|
277
|
+
// Plugin installation logic
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Deployment
|
|
283
|
+
|
|
284
|
+
### PM2 (Recommended)
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# Install PM2
|
|
288
|
+
npm install -g pm2
|
|
289
|
+
|
|
290
|
+
# Start with PM2
|
|
291
|
+
npm run pm2
|
|
292
|
+
|
|
293
|
+
# Monitor
|
|
294
|
+
pm2 monitor
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Docker
|
|
298
|
+
|
|
299
|
+
```dockerfile
|
|
300
|
+
FROM node:18-alpine
|
|
301
|
+
WORKDIR /app
|
|
302
|
+
COPY package*.json ./
|
|
303
|
+
RUN npm install
|
|
304
|
+
COPY . .
|
|
305
|
+
RUN npm run build
|
|
306
|
+
EXPOSE 3002
|
|
307
|
+
CMD ["npm", "start"]
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Docker Compose
|
|
311
|
+
|
|
312
|
+
```yaml
|
|
313
|
+
version: '3.8'
|
|
314
|
+
services:
|
|
315
|
+
reactpress-server:
|
|
316
|
+
build: .
|
|
317
|
+
ports:
|
|
318
|
+
- "3002:3002"
|
|
319
|
+
environment:
|
|
320
|
+
- DB_HOST=mysql
|
|
321
|
+
- DB_USERNAME=root
|
|
322
|
+
- DB_PASSWORD=password
|
|
323
|
+
- DB_DATABASE=reactpress
|
|
324
|
+
depends_on:
|
|
325
|
+
- mysql
|
|
326
|
+
|
|
327
|
+
mysql:
|
|
328
|
+
image: mysql:5.7
|
|
329
|
+
environment:
|
|
330
|
+
- MYSQL_ROOT_PASSWORD=password
|
|
331
|
+
- MYSQL_DATABASE=reactpress
|
|
332
|
+
ports:
|
|
333
|
+
- "3306:3306"
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Integration with Frontend
|
|
337
|
+
|
|
338
|
+
Use with ReactPress client:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
# Install both server and client
|
|
342
|
+
npm install @fecommunity/reactpress-server @fecommunity/reactpress-client @fecommunity/reactpress-config
|
|
343
|
+
|
|
344
|
+
# Start server
|
|
345
|
+
npx reactpress-server dev
|
|
346
|
+
|
|
347
|
+
# In another terminal, start client
|
|
348
|
+
npx reactpress-client dev
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## Troubleshooting
|
|
352
|
+
|
|
353
|
+
### Common Issues
|
|
354
|
+
|
|
355
|
+
1. **Database Connection Error**
|
|
356
|
+
```
|
|
357
|
+
Error: connect ECONNREFUSED 127.0.0.1:3306
|
|
358
|
+
```
|
|
359
|
+
- Ensure MySQL is running
|
|
360
|
+
- Check database credentials in `.env`
|
|
361
|
+
|
|
362
|
+
2. **Port Already in Use**
|
|
363
|
+
```
|
|
364
|
+
Error: listen EADDRINUSE :::3002
|
|
365
|
+
```
|
|
366
|
+
- Change port in `.env` file or use `-p` option
|
|
367
|
+
|
|
368
|
+
3. **JWT Secret Missing**
|
|
369
|
+
```
|
|
370
|
+
Error: JWT_SECRET is not defined
|
|
371
|
+
```
|
|
372
|
+
- Add `JWT_SECRET=your_secret_key` to `.env`
|
|
373
|
+
|
|
374
|
+
### Debug Mode
|
|
375
|
+
|
|
376
|
+
Start server with debug information:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
DEBUG=* npx reactpress-server dev
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## Contributing
|
|
383
|
+
|
|
384
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
385
|
+
|
|
386
|
+
## License
|
|
387
|
+
|
|
388
|
+
MIT
|
|
389
|
+
|
|
390
|
+
## Links
|
|
391
|
+
|
|
392
|
+
- [GitHub Repository](https://github.com/fecommunity/reactpress)
|
|
393
|
+
- [Documentation](https://reactpress.surge.sh)
|
|
394
|
+
- [npm Package](https://www.npmjs.com/package/@fecommunity/reactpress-server)
|
|
395
|
+
- [API Documentation](http://localhost:3002/api) (when server is running)
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const { execSync } = require('child_process');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
const inquirer = require('inquirer');
|
|
9
|
+
|
|
10
|
+
program
|
|
11
|
+
.name('@reactpress/server')
|
|
12
|
+
.description('ReactPress Server CLI')
|
|
13
|
+
.version('1.0.0');
|
|
14
|
+
|
|
15
|
+
// Init command - 初始化服务器配置
|
|
16
|
+
program
|
|
17
|
+
.command('init')
|
|
18
|
+
.description('Initialize ReactPress server configuration')
|
|
19
|
+
.option('-d, --database <type>', 'Database type (mysql|postgres)', 'mysql')
|
|
20
|
+
.option('-p, --port <port>', 'Server port', '3002')
|
|
21
|
+
.option('--skip-db-setup', 'Skip database setup')
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
console.log(chalk.blue('🚀 Initializing ReactPress Server...\n'));
|
|
24
|
+
|
|
25
|
+
const cwd = process.cwd();
|
|
26
|
+
const envPath = path.join(cwd, '.env');
|
|
27
|
+
|
|
28
|
+
// 检查.env文件是否已存在
|
|
29
|
+
if (fs.existsSync(envPath)) {
|
|
30
|
+
const { overwrite } = await inquirer.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: 'confirm',
|
|
33
|
+
name: 'overwrite',
|
|
34
|
+
message: 'Configuration file (.env) already exists. Overwrite?',
|
|
35
|
+
default: false
|
|
36
|
+
}
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
if (!overwrite) {
|
|
40
|
+
console.log(chalk.yellow('⚠️ Initialization cancelled.'));
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 收集配置信息
|
|
46
|
+
console.log(chalk.cyan('📋 Please provide the following configuration:\n'));
|
|
47
|
+
|
|
48
|
+
const config = await inquirer.prompt([
|
|
49
|
+
{
|
|
50
|
+
type: 'input',
|
|
51
|
+
name: 'DB_HOST',
|
|
52
|
+
message: 'Database host:',
|
|
53
|
+
default: 'localhost'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: 'input',
|
|
57
|
+
name: 'DB_PORT',
|
|
58
|
+
message: 'Database port:',
|
|
59
|
+
default: options.database === 'postgres' ? '5432' : '3306'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: 'input',
|
|
63
|
+
name: 'DB_USERNAME',
|
|
64
|
+
message: 'Database username:',
|
|
65
|
+
default: 'root'
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: 'password',
|
|
69
|
+
name: 'DB_PASSWORD',
|
|
70
|
+
message: 'Database password:',
|
|
71
|
+
mask: '*'
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: 'input',
|
|
75
|
+
name: 'DB_DATABASE',
|
|
76
|
+
message: 'Database name:',
|
|
77
|
+
default: 'reactpress'
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
type: 'input',
|
|
81
|
+
name: 'SERVER_PORT',
|
|
82
|
+
message: 'Server port:',
|
|
83
|
+
default: options.port
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: 'input',
|
|
87
|
+
name: 'JWT_SECRET',
|
|
88
|
+
message: 'JWT secret (leave empty to generate):',
|
|
89
|
+
default: ''
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
type: 'input',
|
|
93
|
+
name: 'ADMIN_USER',
|
|
94
|
+
message: 'Admin username:',
|
|
95
|
+
default: 'admin'
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: 'password',
|
|
99
|
+
name: 'ADMIN_PASSWD',
|
|
100
|
+
message: 'Admin password:',
|
|
101
|
+
default: 'admin',
|
|
102
|
+
mask: '*'
|
|
103
|
+
}
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
// 如果没有提供JWT密钥则生成一个
|
|
107
|
+
if (!config.JWT_SECRET) {
|
|
108
|
+
config.JWT_SECRET = require('crypto').randomBytes(32).toString('hex');
|
|
109
|
+
console.log(chalk.green('🔐 Generated JWT secret'));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 创建.env文件
|
|
113
|
+
const envContent = `# ReactPress Server Configuration
|
|
114
|
+
# Generated on ${new Date().toISOString()}
|
|
115
|
+
|
|
116
|
+
# Database Configuration
|
|
117
|
+
DB_TYPE=${options.database}
|
|
118
|
+
DB_HOST=${config.DB_HOST}
|
|
119
|
+
DB_PORT=${config.DB_PORT}
|
|
120
|
+
DB_USERNAME=${config.DB_USERNAME}
|
|
121
|
+
DB_PASSWORD=${config.DB_PASSWORD}
|
|
122
|
+
DB_DATABASE=${config.DB_DATABASE}
|
|
123
|
+
|
|
124
|
+
# Server Configuration
|
|
125
|
+
SERVER_PORT=${config.SERVER_PORT}
|
|
126
|
+
SERVER_API_PREFIX=/api
|
|
127
|
+
|
|
128
|
+
# Security
|
|
129
|
+
JWT_SECRET=${config.JWT_SECRET}
|
|
130
|
+
ADMIN_USER=${config.ADMIN_USER}
|
|
131
|
+
ADMIN_PASSWD=${config.ADMIN_PASSWD}
|
|
132
|
+
|
|
133
|
+
# Environment
|
|
134
|
+
NODE_ENV=development
|
|
135
|
+
`;
|
|
136
|
+
|
|
137
|
+
fs.writeFileSync(envPath, envContent);
|
|
138
|
+
console.log(chalk.green('✅ Configuration saved to .env file'));
|
|
139
|
+
|
|
140
|
+
if (!options.skipDbSetup) {
|
|
141
|
+
console.log(chalk.yellow('\n🗄️ Setting up database...'));
|
|
142
|
+
console.log(chalk.gray(`Please ensure your ${options.database} server is running and create the database:`));
|
|
143
|
+
console.log(chalk.cyan(`CREATE DATABASE ${config.DB_DATABASE};`));
|
|
144
|
+
console.log(chalk.gray('Then run: npx @reactpress/server start'));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log(chalk.green('\n🎉 ReactPress Server initialized successfully!'));
|
|
148
|
+
console.log(chalk.cyan('\nNext steps:'));
|
|
149
|
+
console.log(chalk.gray('1. Start the server: npx @reactpress/server start'));
|
|
150
|
+
console.log(chalk.gray('2. Visit API: http://localhost:' + config.SERVER_PORT + '/api'));
|
|
151
|
+
console.log(chalk.gray('3. API docs: http://localhost:' + config.SERVER_PORT + '/api (Swagger UI)'));
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Start command - 启动服务器
|
|
155
|
+
program
|
|
156
|
+
.command('start')
|
|
157
|
+
.description('Start ReactPress server')
|
|
158
|
+
.option('-p, --port <port>', 'Server port')
|
|
159
|
+
.option('-d, --dev', 'Start in development mode')
|
|
160
|
+
.option('--watch', 'Watch for file changes (dev mode)')
|
|
161
|
+
.action(async (options) => {
|
|
162
|
+
console.log(chalk.blue('🚀 Starting ReactPress Server...\n'));
|
|
163
|
+
|
|
164
|
+
const cwd = process.cwd();
|
|
165
|
+
const envPath = path.join(cwd, '.env');
|
|
166
|
+
|
|
167
|
+
// 检查.env文件是否存在
|
|
168
|
+
if (!fs.existsSync(envPath)) {
|
|
169
|
+
console.log(chalk.red('❌ Configuration file (.env) not found!'));
|
|
170
|
+
console.log(chalk.yellow('Please run: npx @reactpress/server init'));
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 检查是否在项目根目录(有server目录)
|
|
175
|
+
const serverPath = path.join(cwd, 'server');
|
|
176
|
+
const hasServerDir = fs.existsSync(serverPath);
|
|
177
|
+
|
|
178
|
+
let serverMainPath;
|
|
179
|
+
if (hasServerDir) {
|
|
180
|
+
// 在项目根目录,使用相对路径
|
|
181
|
+
serverMainPath = path.join(serverPath, 'dist', 'main.js');
|
|
182
|
+
const packageDir = serverPath;
|
|
183
|
+
|
|
184
|
+
// 检查构建文件是否存在
|
|
185
|
+
if (!fs.existsSync(serverMainPath)) {
|
|
186
|
+
console.log(chalk.yellow('⚠️ Built server not found, building...'));
|
|
187
|
+
try {
|
|
188
|
+
execSync('pnpm run build:server', { cwd: cwd, stdio: 'inherit' });
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.log(chalk.red('❌ Build failed'));
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
// 可能在独立安装的@reactpress/server包中
|
|
196
|
+
try {
|
|
197
|
+
const serverPackagePath = require.resolve('@reactpress/server/package.json');
|
|
198
|
+
const serverPackageDir = path.dirname(serverPackagePath);
|
|
199
|
+
serverMainPath = path.join(serverPackageDir, 'dist', 'main.js');
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.log(chalk.red('❌ ReactPress server package not found!'));
|
|
202
|
+
console.log(chalk.yellow('Please install: npm install @reactpress/server'));
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 设置环境变量
|
|
208
|
+
const env = {
|
|
209
|
+
...process.env,
|
|
210
|
+
NODE_ENV: options.dev ? 'development' : 'production'
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
if (options.port) {
|
|
214
|
+
env.SERVER_PORT = options.port;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
if (options.dev || options.watch) {
|
|
219
|
+
console.log(chalk.yellow('🔄 Starting in development mode...'));
|
|
220
|
+
if (hasServerDir) {
|
|
221
|
+
execSync('pnpm run dev:server', {
|
|
222
|
+
cwd: cwd,
|
|
223
|
+
stdio: 'inherit',
|
|
224
|
+
env
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
console.log(chalk.yellow('⚠️ Development mode requires server source code'));
|
|
228
|
+
console.log(chalk.cyan('Starting in production mode instead...'));
|
|
229
|
+
execSync(`node ${serverMainPath}`, {
|
|
230
|
+
cwd: process.cwd(),
|
|
231
|
+
stdio: 'inherit',
|
|
232
|
+
env
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
console.log(chalk.green('🌟 Starting in production mode...'));
|
|
237
|
+
execSync(`node ${serverMainPath}`, {
|
|
238
|
+
cwd: process.cwd(),
|
|
239
|
+
stdio: 'inherit',
|
|
240
|
+
env
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
} catch (error) {
|
|
244
|
+
console.log(chalk.red('❌ Failed to start server'));
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Build command - 构建服务器
|
|
250
|
+
program
|
|
251
|
+
.command('build')
|
|
252
|
+
.description('Build ReactPress server')
|
|
253
|
+
.action(() => {
|
|
254
|
+
console.log(chalk.blue('🔨 Building ReactPress Server...\n'));
|
|
255
|
+
|
|
256
|
+
const cwd = process.cwd();
|
|
257
|
+
const serverPath = path.join(cwd, 'server');
|
|
258
|
+
|
|
259
|
+
if (!fs.existsSync(serverPath)) {
|
|
260
|
+
console.log(chalk.red('❌ Server directory not found!'));
|
|
261
|
+
console.log(chalk.yellow('This command should be run from the project root directory.'));
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
execSync('pnpm run build:server', {
|
|
267
|
+
cwd: cwd,
|
|
268
|
+
stdio: 'inherit'
|
|
269
|
+
});
|
|
270
|
+
console.log(chalk.green('✅ Build completed successfully!'));
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.log(chalk.red('❌ Build failed'));
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Dev command - 开发模式启动
|
|
278
|
+
program
|
|
279
|
+
.command('dev')
|
|
280
|
+
.description('Start server in development mode')
|
|
281
|
+
.option('-p, --port <port>', 'Server port')
|
|
282
|
+
.action((options) => {
|
|
283
|
+
console.log(chalk.blue('🔄 Starting ReactPress Server in development mode...\n'));
|
|
284
|
+
|
|
285
|
+
// 调用start命令的dev模式
|
|
286
|
+
const args = ['start', '--dev'];
|
|
287
|
+
if (options.port) {
|
|
288
|
+
args.push('--port', options.port);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 重新调用当前脚本
|
|
292
|
+
const child = require('child_process').spawn('node', [__filename, ...args], {
|
|
293
|
+
stdio: 'inherit',
|
|
294
|
+
env: process.env
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
child.on('exit', (code) => {
|
|
298
|
+
process.exit(code);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
program.parse();
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fecommunity/reactpress-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5-beta.0",
|
|
4
4
|
"description": "ReactPress Server - NestJS-based backend API for ReactPress CMS",
|
|
5
5
|
"author": "fecommunity",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/main.js",
|
|
8
8
|
"types": "dist/index.d.ts",
|
|
9
9
|
"bin": {
|
|
10
|
-
"@fecommunity/reactpress-server": "
|
|
10
|
+
"@fecommunity/reactpress-server": "./bin/reactpress-server.js"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"dist/**/*",
|
|
14
14
|
"public/**/*",
|
|
15
|
+
"bin/**/*",
|
|
15
16
|
"README.md",
|
|
16
17
|
"LICENSE"
|
|
17
18
|
],
|
|
@@ -53,7 +54,7 @@
|
|
|
53
54
|
"prepublishOnly": "npm run build"
|
|
54
55
|
},
|
|
55
56
|
"dependencies": {
|
|
56
|
-
"@fecommunity/reactpress-config": "
|
|
57
|
+
"@fecommunity/reactpress-config": "^1.0.7-beta.0",
|
|
57
58
|
"@nestjs/common": "^6.7.2",
|
|
58
59
|
"@nestjs/config": "^0.6.3",
|
|
59
60
|
"@nestjs/core": "^6.7.2",
|