nsbp-cli 0.2.23 → 0.2.25
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 +1 -1
- package/bin/nsbp.js +6 -9
- package/package.json +1 -1
- package/templates/basic/.env.development +13 -0
- package/templates/basic/.env.example +33 -0
- package/templates/basic/.env.production +17 -0
- package/templates/basic/Makefile +60 -18
- package/templates/basic/README.md +152 -0
- package/templates/basic/{webpack.base.js → config/webpack.base.js} +2 -2
- package/templates/basic/{webpack.client.js → config/webpack.client.js} +2 -2
- package/templates/basic/{webpack.server.js → config/webpack.server.js} +3 -3
- package/templates/basic/{Dockerfile → docker/Dockerfile} +1 -1
- package/templates/basic/{docker-compose.dev.yml → docker/docker-compose.dev.yml} +12 -7
- package/templates/basic/{docker-compose.yml → docker/docker-compose.yml} +8 -4
- package/templates/basic/docs/ENV_CONFIG_GUIDE.md +346 -0
- package/templates/basic/docs/QUICKSTART.md +99 -0
- package/templates/basic/gitignore +2 -0
- package/templates/basic/package.json +8 -6
- package/templates/basic/public/apple-touch-icon.png +0 -0
- package/templates/basic/public/favicon-16x16.png +0 -0
- package/templates/basic/public/favicon-192x192.png +0 -0
- package/templates/basic/public/favicon-32x32.png +0 -0
- package/templates/basic/public/favicon-512x512.png +0 -0
- package/templates/basic/public/favicon.svg +10 -0
- package/templates/basic/public/site.webmanifest +20 -0
- package/templates/basic/scripts/verify-dev.sh +6 -6
- package/templates/basic/scripts/verify-security.sh +124 -0
- package/templates/basic/src/server/index.ts +56 -2
- package/templates/basic/src/server/utils.tsx +7 -0
- /package/templates/basic/{postcss.config.js → config/postcss.config.js} +0 -0
- /package/templates/basic/{.dockerignore → docker/.dockerignore} +0 -0
- /package/templates/basic/{Dockerfile.dev → docker/Dockerfile.dev} +0 -0
package/README.md
CHANGED
|
@@ -147,7 +147,7 @@ node ./bin/nsbp.js --help # Test CLI locally
|
|
|
147
147
|
|
|
148
148
|
- **Package Name**: `nsbp-cli`
|
|
149
149
|
- **Bin Command**: `nsbp` (install globally and run `nsbp --help`)
|
|
150
|
-
- **Version**: `0.2.
|
|
150
|
+
- **Version**: `0.2.25`
|
|
151
151
|
- **Dependencies**: chalk, commander, fs-extra, inquirer
|
|
152
152
|
- **Package Manager**: Uses pnpm (also compatible with npm)
|
|
153
153
|
- **Node Version**: >=16.0.0
|
package/bin/nsbp.js
CHANGED
|
@@ -55,19 +55,16 @@ program
|
|
|
55
55
|
'src',
|
|
56
56
|
'public',
|
|
57
57
|
'scripts',
|
|
58
|
-
'
|
|
59
|
-
'
|
|
60
|
-
'
|
|
58
|
+
'config',
|
|
59
|
+
'docker',
|
|
60
|
+
'docs',
|
|
61
|
+
'.env.example',
|
|
62
|
+
'.env.development',
|
|
63
|
+
'.env.production',
|
|
61
64
|
'tsconfig.json',
|
|
62
|
-
'postcss.config.js',
|
|
63
65
|
'.prettierrc',
|
|
64
66
|
'.prettierignore',
|
|
65
67
|
'gitignore',
|
|
66
|
-
'.dockerignore',
|
|
67
|
-
'docker-compose.yml',
|
|
68
|
-
'docker-compose.dev.yml',
|
|
69
|
-
'Dockerfile',
|
|
70
|
-
'Dockerfile.dev',
|
|
71
68
|
'Makefile',
|
|
72
69
|
'README.md'
|
|
73
70
|
];
|
package/package.json
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# NSBP 开发环境配置
|
|
2
|
+
|
|
3
|
+
# ==================== 运行环境配置 ====================
|
|
4
|
+
NODE_ENV=development
|
|
5
|
+
PORT=3001
|
|
6
|
+
|
|
7
|
+
# ==================== 安全配置 ====================
|
|
8
|
+
# 开发环境禁用速率限制(影响开发效率)
|
|
9
|
+
ENABLE_RATE_LIMIT=0
|
|
10
|
+
|
|
11
|
+
# ==================== 调试配置 ====================
|
|
12
|
+
# 启用详细日志便于调试
|
|
13
|
+
# DEBUG=nsbp:*
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# NSBP 环境变量配置
|
|
2
|
+
# 复制此文件为 .env 并根据需要修改配置
|
|
3
|
+
|
|
4
|
+
# ==================== 运行环境配置 ====================
|
|
5
|
+
NODE_ENV=development
|
|
6
|
+
PORT=3001
|
|
7
|
+
|
|
8
|
+
# ==================== 安全配置 ====================
|
|
9
|
+
# 启用速率限制(1=启用,0=禁用)
|
|
10
|
+
# 开发环境建议禁用,生产环境建议启用
|
|
11
|
+
ENABLE_RATE_LIMIT=0
|
|
12
|
+
|
|
13
|
+
# ==================== Docker 配置(Docker 部署时使用)====================
|
|
14
|
+
# Docker 镜像标签(可选)
|
|
15
|
+
# DOCKER_IMAGE_TAG=latest
|
|
16
|
+
|
|
17
|
+
# ==================== 调试配置 ====================
|
|
18
|
+
# 启用详细日志(开发时有用)
|
|
19
|
+
# DEBUG=nsbp:*
|
|
20
|
+
|
|
21
|
+
# ==================== 性能配置 ====================
|
|
22
|
+
# 启用性能监控(生产环境可选)
|
|
23
|
+
# ENABLE_PERFORMANCE_MONITORING=0
|
|
24
|
+
|
|
25
|
+
# ==================== 其他配置 ====================
|
|
26
|
+
# 时区(可选)
|
|
27
|
+
# TZ=Asia/Shanghai
|
|
28
|
+
|
|
29
|
+
# ==================== 注意事项 ====================
|
|
30
|
+
# 1. 不要将 .env 文件提交到 Git(已在 .gitignore 中忽略)
|
|
31
|
+
# 2. 敏感信息(密钥、密码)请放在 .env.local 中
|
|
32
|
+
# 3. .env.local 不会被提交到 Git,适合存放敏感信息
|
|
33
|
+
# 4. 优先级:.env.local > .env > 默认值
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# NSBP 生产环境配置
|
|
2
|
+
|
|
3
|
+
# ==================== 运行环境配置 ====================
|
|
4
|
+
NODE_ENV=production
|
|
5
|
+
PORT=3001
|
|
6
|
+
|
|
7
|
+
# ==================== 安全配置 ====================
|
|
8
|
+
# 生产环境启用速率限制(防止 DDoS 和暴力攻击)
|
|
9
|
+
ENABLE_RATE_LIMIT=1
|
|
10
|
+
|
|
11
|
+
# ==================== 性能配置 ====================
|
|
12
|
+
# 生产环境关闭调试日志
|
|
13
|
+
# DEBUG=
|
|
14
|
+
|
|
15
|
+
# ==================== 其他配置 ====================
|
|
16
|
+
# 时区
|
|
17
|
+
TZ=Asia/Shanghai
|
package/templates/basic/Makefile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
.PHONY: help build dev prod down clean logs restart
|
|
1
|
+
.PHONY: help build dev prod down clean logs restart env-dev env-prod env-local
|
|
2
2
|
|
|
3
3
|
# Package manager detection
|
|
4
4
|
PNPM := $(shell which pnpm)
|
|
@@ -19,48 +19,90 @@ help: ## Show this help message
|
|
|
19
19
|
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
|
20
20
|
|
|
21
21
|
build: ## Build Docker images for production
|
|
22
|
-
$(COMPOSE) build
|
|
22
|
+
$(COMPOSE) -f docker/docker-compose.yml build
|
|
23
23
|
|
|
24
24
|
build-dev: ## Build Docker images for development
|
|
25
|
-
$(COMPOSE) -f docker-compose.dev.yml build
|
|
25
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml build
|
|
26
26
|
|
|
27
27
|
dev: ## Start development environment (removes orphan containers)
|
|
28
|
-
$(COMPOSE) -f docker-compose.dev.yml up --build --remove-orphans
|
|
28
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml up --build --remove-orphans
|
|
29
29
|
|
|
30
30
|
prod: ## Start production environment (removes orphan containers)
|
|
31
|
-
$(COMPOSE) up -d --remove-orphans
|
|
31
|
+
$(COMPOSE) -f docker/docker-compose.yml up -d --remove-orphans
|
|
32
32
|
|
|
33
33
|
down: ## Stop and remove containers (including orphan containers)
|
|
34
|
-
$(COMPOSE) down --remove-orphans
|
|
35
|
-
$(COMPOSE) -f docker-compose.dev.yml down --remove-orphans
|
|
34
|
+
$(COMPOSE) -f docker/docker-compose.yml down --remove-orphans
|
|
35
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml down --remove-orphans
|
|
36
36
|
|
|
37
37
|
clean: ## Stop containers, remove images and volumes (including orphan containers)
|
|
38
|
-
$(COMPOSE) down -v --rmi all --remove-orphans
|
|
39
|
-
$(COMPOSE) -f docker-compose.dev.yml down -v --rmi all --remove-orphans
|
|
38
|
+
$(COMPOSE) -f docker/docker-compose.yml down -v --rmi all --remove-orphans
|
|
39
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml down -v --rmi all --remove-orphans
|
|
40
40
|
|
|
41
41
|
logs: ## View logs
|
|
42
|
-
$(COMPOSE) logs -f
|
|
42
|
+
$(COMPOSE) -f docker/docker-compose.yml logs -f
|
|
43
43
|
|
|
44
44
|
logs-dev: ## View development logs
|
|
45
|
-
$(COMPOSE) -f docker-compose.dev.yml logs -f
|
|
45
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml logs -f
|
|
46
46
|
|
|
47
47
|
restart: ## Restart production containers
|
|
48
|
-
$(COMPOSE) restart
|
|
48
|
+
$(COMPOSE) -f docker/docker-compose.yml restart
|
|
49
49
|
|
|
50
50
|
restart-dev: ## Restart development containers
|
|
51
|
-
$(COMPOSE) -f docker-compose.dev.yml restart
|
|
51
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml restart
|
|
52
52
|
|
|
53
53
|
rebuild: ## Rebuild and restart production containers (removes orphan containers)
|
|
54
|
-
$(COMPOSE) up -d --build --remove-orphans
|
|
54
|
+
$(COMPOSE) -f docker/docker-compose.yml up -d --build --remove-orphans
|
|
55
55
|
|
|
56
56
|
rebuild-dev: ## Rebuild and restart development containers (removes orphan containers)
|
|
57
|
-
$(COMPOSE) -f docker-compose.dev.yml up -d --build --remove-orphans
|
|
57
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml up -d --build --remove-orphans
|
|
58
58
|
|
|
59
59
|
shell: ## Open shell in production container
|
|
60
|
-
$(COMPOSE) exec app sh
|
|
60
|
+
$(COMPOSE) -f docker/docker-compose.yml exec app sh
|
|
61
61
|
|
|
62
62
|
shell-dev: ## Open shell in development container
|
|
63
|
-
$(COMPOSE) -f docker-compose.dev.yml exec app sh
|
|
63
|
+
$(COMPOSE) -f docker/docker-compose.dev.yml exec app sh
|
|
64
64
|
|
|
65
65
|
test: ## Run tests (if configured)
|
|
66
|
-
$(COMPOSE) exec app $(PM) test
|
|
66
|
+
$(COMPOSE) -f docker/docker-compose.yml exec app $(PM) test
|
|
67
|
+
|
|
68
|
+
env-dev: ## Set up development environment
|
|
69
|
+
@if [ -f .env.development ]; then \
|
|
70
|
+
cp .env.development .env && \
|
|
71
|
+
echo -e "\033[0;32m✅ 开发环境已配置 (.env)\033[0m"; \
|
|
72
|
+
else \
|
|
73
|
+
echo -e "\033[0;33m⚠️ .env.development 不存在\033[0m"; \
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
env-prod: ## Set up production environment
|
|
77
|
+
@if [ -f .env.production ]; then \
|
|
78
|
+
cp .env.production .env && \
|
|
79
|
+
echo -e "\033[0;32m✅ 生产环境已配置 (.env)\033[0m"; \
|
|
80
|
+
else \
|
|
81
|
+
echo -e "\033[0;33m⚠️ .env.production 不存在\033[0m"; \
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
env-local: ## Set up local environment with sensitive data
|
|
85
|
+
@if [ ! -f .env.local ]; then \
|
|
86
|
+
echo "# Local environment (contains sensitive data)" > .env.local && \
|
|
87
|
+
echo "# DO NOT commit this file to Git" >> .env.local && \
|
|
88
|
+
echo -e "\033[0;32m✅ .env.local 已创建\033[0m"; \
|
|
89
|
+
echo "请编辑 .env.local 添加敏感信息"; \
|
|
90
|
+
else \
|
|
91
|
+
echo -e "\033[0;33m⚠️ .env.local 已存在\033[0m"; \
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
show-env: ## Show current environment variables
|
|
95
|
+
@echo "========================================="
|
|
96
|
+
@echo "当前环境变量配置"
|
|
97
|
+
@echo "========================================="
|
|
98
|
+
@echo ""
|
|
99
|
+
@if [ -f .env ]; then \
|
|
100
|
+
echo "📄 .env 文件内容:"; \
|
|
101
|
+
cat .env | grep -v "^#" | grep -v "^$$"; \
|
|
102
|
+
else \
|
|
103
|
+
echo "⚠️ .env 文件不存在"; \
|
|
104
|
+
fi
|
|
105
|
+
@echo ""
|
|
106
|
+
@if [ -f .env.local ]; then \
|
|
107
|
+
echo "📄 .env.local 文件存在(包含敏感信息)"; \
|
|
108
|
+
fi
|
|
@@ -2,6 +2,84 @@
|
|
|
2
2
|
|
|
3
3
|
🌐 **Online Demo**: [https://nsbp.erishen.cn/](https://nsbp.erishen.cn/)
|
|
4
4
|
|
|
5
|
+
## 环境变量配置
|
|
6
|
+
|
|
7
|
+
### 快速开始
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 1. 复制环境变量模板
|
|
11
|
+
cp .env.example .env
|
|
12
|
+
|
|
13
|
+
# 2. 根据需要编辑 .env 文件
|
|
14
|
+
# 编辑 NODE_ENV、PORT、ENABLE_RATE_LIMIT 等
|
|
15
|
+
|
|
16
|
+
# 3. 开始开发或部署
|
|
17
|
+
pnpm run dev # 本地开发
|
|
18
|
+
docker-compose up -d # Docker 部署
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 环境变量说明
|
|
22
|
+
|
|
23
|
+
| 变量名 | 默认值 | 说明 | 推荐环境 |
|
|
24
|
+
|-------|--------|------|---------|
|
|
25
|
+
| `NODE_ENV` | development | 运行环境 (development/production) | 全部 |
|
|
26
|
+
| `PORT` | 3001 | 服务端口 | 全部 |
|
|
27
|
+
| `ENABLE_RATE_LIMIT` | 0 | 启用速率限制 (1=启用, 0=禁用) | 生产环境 |
|
|
28
|
+
| `DEBUG` | - | 启用调试日志 | 开发环境 |
|
|
29
|
+
| `TZ` | Asia/Shanghai | 时区配置 | 生产环境 |
|
|
30
|
+
|
|
31
|
+
### 配置文件说明
|
|
32
|
+
|
|
33
|
+
- **`.env.example`** - 环境变量模板(提交到 Git)
|
|
34
|
+
- **`.env`** - 本地开发配置(不提交到 Git)
|
|
35
|
+
- **`.env.production`** - 生产环境配置(不提交到 Git)
|
|
36
|
+
- **`.env.development`** - 开发环境配置(不提交到 Git)
|
|
37
|
+
- **`.env.local`** - 本地敏感信息(最高优先级,不提交到 Git)
|
|
38
|
+
|
|
39
|
+
### 配置优先级
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
.env.local > .env > docker-compose.yml 默认值
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 本地开发配置
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 复制开发环境配置
|
|
49
|
+
cp .env.development .env
|
|
50
|
+
|
|
51
|
+
# 或手动创建 .env 文件
|
|
52
|
+
cat > .env << EOF
|
|
53
|
+
NODE_ENV=development
|
|
54
|
+
PORT=3001
|
|
55
|
+
ENABLE_RATE_LIMIT=0
|
|
56
|
+
EOF
|
|
57
|
+
|
|
58
|
+
# 启动开发环境
|
|
59
|
+
pnpm run dev
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Docker 部署配置
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# 生产环境配置
|
|
66
|
+
cp .env.production .env
|
|
67
|
+
|
|
68
|
+
# Docker Compose 会自动读取 .env 文件
|
|
69
|
+
docker-compose up -d
|
|
70
|
+
|
|
71
|
+
# 查看环境变量是否生效
|
|
72
|
+
docker-compose exec app env | grep NODE_ENV
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 敏感信息管理
|
|
76
|
+
|
|
77
|
+
**重要:**
|
|
78
|
+
- ✅ `.env.example` 可以提交到 Git(模板文件)
|
|
79
|
+
- ❌ `.env`、`.env.local` 不要提交到 Git(已在 .gitignore 中)
|
|
80
|
+
- ✅ 敏感信息(密钥、数据库密码)放在 `.env.local` 中
|
|
81
|
+
- ✅ `.env.local` 会覆盖其他配置,优先级最高
|
|
82
|
+
|
|
5
83
|
## 开发
|
|
6
84
|
- pnpm run dev (开发运行)
|
|
7
85
|
- pnpm run build (生产编译)
|
|
@@ -141,6 +219,80 @@ make rebuild-dev # 重新构建并启动开发环境
|
|
|
141
219
|
|
|
142
220
|
- `NODE_ENV`: 运行环境 (production/development)
|
|
143
221
|
- `PORT`: 服务端口 (默认 3001)
|
|
222
|
+
- `ENABLE_RATE_LIMIT`: 启用速率限制 (1=启用,0=禁用,默认禁用)
|
|
223
|
+
|
|
224
|
+
## 安全特性
|
|
225
|
+
|
|
226
|
+
NSBP 内置了多层安全防护,默认启用生产级安全配置:
|
|
227
|
+
|
|
228
|
+
### 已启用的安全措施
|
|
229
|
+
|
|
230
|
+
#### 1. **HTTP 头部安全 (Helmet)**
|
|
231
|
+
- Content Security Policy (CSP): 防止 XSS 攻击
|
|
232
|
+
- X-Frame-Options: 防止点击劫持
|
|
233
|
+
- X-Content-Type-Options: 防止 MIME 类型嗅探
|
|
234
|
+
- Strict-Transport-Security: 强制 HTTPS
|
|
235
|
+
- X-XSS-Protection: XSS 保护
|
|
236
|
+
- Referrer-Policy: 控制引用信息
|
|
237
|
+
|
|
238
|
+
#### 2. **静态文件安全**
|
|
239
|
+
- ✅ 禁止访问 `.env`、`.git` 等敏感文件
|
|
240
|
+
- ✅ 静态资源缓存优化(1 年缓存)
|
|
241
|
+
- ✅ 请求体大小限制(10MB)
|
|
242
|
+
|
|
243
|
+
#### 3. **技术栈隐藏**
|
|
244
|
+
- ✅ 移除 `X-Powered-By` 头部
|
|
245
|
+
- ✅ 不暴露 Express 版本信息
|
|
246
|
+
|
|
247
|
+
#### 4. **速率限制 (可选)**
|
|
248
|
+
- ✅ 15 分钟内最多 100 次请求
|
|
249
|
+
- ✅ 自动限流恶意 IP
|
|
250
|
+
- ✅ 可通过环境变量启用/禁用
|
|
251
|
+
|
|
252
|
+
### 启用速率限制
|
|
253
|
+
|
|
254
|
+
在生产环境中,建议启用速率限制以防止 DDoS 攻击:
|
|
255
|
+
|
|
256
|
+
**Docker 方式:**
|
|
257
|
+
```bash
|
|
258
|
+
# docker-compose.yml 中添加
|
|
259
|
+
environment:
|
|
260
|
+
- ENABLE_RATE_LIMIT=1
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**本地开发方式:**
|
|
264
|
+
```bash
|
|
265
|
+
# .env 文件
|
|
266
|
+
ENABLE_RATE_LIMIT=1
|
|
267
|
+
|
|
268
|
+
# 或命令行
|
|
269
|
+
ENABLE_RATE_LIMIT=1 pnpm start
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### 安全最佳实践
|
|
273
|
+
|
|
274
|
+
#### 生产环境建议
|
|
275
|
+
1. ✅ **启用 HTTPS**: 使用反向代理(Nginx/Apache)配置 SSL
|
|
276
|
+
2. ✅ **启用速率限制**: 防止暴力攻击和 DDoS
|
|
277
|
+
3. ✅ **设置强密码**: 数据库、API 密钥等
|
|
278
|
+
4. ✅ **定期更新依赖**: `pnpm update`
|
|
279
|
+
5. ✅ **配置防火墙**: 限制入站流量
|
|
280
|
+
|
|
281
|
+
#### 开发环境
|
|
282
|
+
- ✅ 默认配置已足够
|
|
283
|
+
- ❌ 不建议启用速率限制(影响开发效率)
|
|
284
|
+
- ✅ 保留详细错误日志便于调试
|
|
285
|
+
|
|
286
|
+
### 安全检查清单
|
|
287
|
+
|
|
288
|
+
部署前请确认:
|
|
289
|
+
- [ ] 已安装最新依赖 (`pnpm install`)
|
|
290
|
+
- [ ] 环境变量已配置(NODE_ENV=production)
|
|
291
|
+
- [ ] HTTPS 已配置
|
|
292
|
+
- [ ] 敏感信息(密钥、数据库密码)已移出代码库
|
|
293
|
+
- [ ] 速率限制已启用(生产环境)
|
|
294
|
+
- [ ] 静态文件访问已测试
|
|
295
|
+
- [ ] CSP 策略已测试(检查控制台错误)
|
|
144
296
|
|
|
145
297
|
### CLI 发布
|
|
146
298
|
|
|
@@ -2,7 +2,7 @@ const path = require('path')
|
|
|
2
2
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
|
3
3
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
|
|
4
4
|
const TerserPlugin = require('terser-webpack-plugin')
|
|
5
|
-
const { version } = require('
|
|
5
|
+
const { version } = require('../package.json')
|
|
6
6
|
const LoadablePlugin = require('@loadable/webpack-plugin')
|
|
7
7
|
const { createLoadableComponentsTransformer } = require('typescript-loadable-components-plugin')
|
|
8
8
|
const BrowserSyncPlugin = require('browser-sync-webpack-plugin')
|
|
@@ -54,7 +54,7 @@ module.exports = ({ mode, entry, server, init }) => {
|
|
|
54
54
|
logInfoToStdOut: true,
|
|
55
55
|
logLevel: 'info',
|
|
56
56
|
transpileOnly: true,
|
|
57
|
-
configFile: path.resolve(__dirname, '
|
|
57
|
+
configFile: path.resolve(__dirname, '../tsconfig.json'),
|
|
58
58
|
getCustomTransformers: (program) => {
|
|
59
59
|
// console.log('getCustomTransformers', program)
|
|
60
60
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const path = require('path') //node的path模块
|
|
2
2
|
const { merge } = require('webpack-merge')
|
|
3
3
|
const config = require('./webpack.base.js')
|
|
4
|
-
const { version } = require('
|
|
4
|
+
const { version } = require('../package.json')
|
|
5
5
|
|
|
6
6
|
const server = false
|
|
7
7
|
|
|
@@ -12,7 +12,7 @@ const entry = {
|
|
|
12
12
|
const clientConfig = {
|
|
13
13
|
output: {
|
|
14
14
|
//打包出口
|
|
15
|
-
path: path.resolve(__dirname, 'public'),
|
|
15
|
+
path: path.resolve(__dirname, '../public'),
|
|
16
16
|
filename: ({ chunk }) => {
|
|
17
17
|
const { name } = chunk
|
|
18
18
|
// console.log('name', name)
|
|
@@ -2,7 +2,7 @@ const path = require('path') //node的path模块
|
|
|
2
2
|
const nodeExternals = require('webpack-node-externals')
|
|
3
3
|
const { merge } = require('webpack-merge')
|
|
4
4
|
const config = require('./webpack.base.js')
|
|
5
|
-
const { version } = require('
|
|
5
|
+
const { version } = require('../package.json')
|
|
6
6
|
|
|
7
7
|
const init = process.env.INIT || 0
|
|
8
8
|
const server = true
|
|
@@ -18,12 +18,12 @@ const serverConfig = {
|
|
|
18
18
|
output: {
|
|
19
19
|
//打包出口
|
|
20
20
|
filename: `bundle.${version}.js`, //打包后的文件名
|
|
21
|
-
path: path.resolve(__dirname, 'build'), //存放到根目录的build文件夹
|
|
21
|
+
path: path.resolve(__dirname, '../build'), //存放到根目录的build文件夹
|
|
22
22
|
clean: true,
|
|
23
23
|
libraryTarget: 'commonjs2'
|
|
24
24
|
},
|
|
25
25
|
externals: [
|
|
26
|
-
'@loadable/component',
|
|
26
|
+
'@loadable/component',
|
|
27
27
|
nodeExternals()
|
|
28
28
|
] //保持node中require的引用方式
|
|
29
29
|
}
|
|
@@ -43,7 +43,7 @@ COPY --from=builder /app/public ./public
|
|
|
43
43
|
|
|
44
44
|
# Copy scripts and config
|
|
45
45
|
COPY --from=builder /app/scripts ./scripts
|
|
46
|
-
COPY --from=builder /app/tsconfig.json ./
|
|
46
|
+
COPY --from=builder /app/tsconfig.json ./tsconfig.json
|
|
47
47
|
|
|
48
48
|
# Change ownership
|
|
49
49
|
RUN chown -R nodejs:nodejs /app
|
|
@@ -1,23 +1,28 @@
|
|
|
1
|
+
# 从 .env 文件读取环境变量(如果存在)
|
|
2
|
+
# 开发环境配置优先级:.env > docker-compose.dev.yml 默认值
|
|
3
|
+
|
|
1
4
|
services:
|
|
2
5
|
app:
|
|
3
6
|
build:
|
|
4
|
-
context:
|
|
5
|
-
dockerfile: Dockerfile.dev
|
|
7
|
+
context: ..
|
|
8
|
+
dockerfile: docker/Dockerfile.dev
|
|
6
9
|
container_name: nsbp-app-dev
|
|
7
10
|
ports:
|
|
8
11
|
- "3001:3001"
|
|
9
12
|
- "9229:9229" # Node.js debug port
|
|
10
13
|
environment:
|
|
11
|
-
- NODE_ENV
|
|
12
|
-
- PORT
|
|
14
|
+
- NODE_ENV=${NODE_ENV:-development}
|
|
15
|
+
- PORT=${PORT:-3001}
|
|
16
|
+
# 开发环境默认禁用速率限制,如需启用可在 .env 中设置
|
|
17
|
+
- ENABLE_RATE_LIMIT=${ENABLE_RATE_LIMIT:-0}
|
|
13
18
|
volumes:
|
|
14
19
|
# Mount source code for hot reload
|
|
15
20
|
- ./src:/app/src
|
|
16
21
|
- ./public:/app/public
|
|
17
22
|
- ./scripts:/app/scripts
|
|
18
|
-
- ./webpack.base.js:/app/webpack.base.js
|
|
19
|
-
- ./webpack.client.js:/app/webpack.client.js
|
|
20
|
-
- ./webpack.server.js:/app/webpack.server.js
|
|
23
|
+
- ./config/webpack.base.js:/app/config/webpack.base.js
|
|
24
|
+
- ./config/webpack.client.js:/app/config/webpack.client.js
|
|
25
|
+
- ./config/webpack.server.js:/app/config/webpack.server.js
|
|
21
26
|
- ./tsconfig.json:/app/tsconfig.json
|
|
22
27
|
# Persist node_modules
|
|
23
28
|
- node_modules:/app/node_modules
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
# 从 .env 文件读取环境变量(如果存在)
|
|
2
|
+
# 生产环境配置优先级:.env > docker-compose.yml 默认值
|
|
3
|
+
|
|
1
4
|
services:
|
|
2
5
|
app:
|
|
3
6
|
build:
|
|
4
|
-
context:
|
|
5
|
-
dockerfile: Dockerfile
|
|
7
|
+
context: ..
|
|
8
|
+
dockerfile: docker/Dockerfile
|
|
6
9
|
container_name: nsbp-app
|
|
7
10
|
ports:
|
|
8
11
|
- "8091:3001"
|
|
9
12
|
environment:
|
|
10
|
-
- NODE_ENV
|
|
11
|
-
- PORT
|
|
13
|
+
- NODE_ENV=${NODE_ENV:-production}
|
|
14
|
+
- PORT=${PORT:-3001}
|
|
15
|
+
- ENABLE_RATE_LIMIT=${ENABLE_RATE_LIMIT:-1}
|
|
12
16
|
restart: unless-stopped
|
|
13
17
|
healthcheck:
|
|
14
18
|
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# NSBP 环境变量配置指南
|
|
2
|
+
|
|
3
|
+
## 快速开始
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# 1. 复制环境变量模板
|
|
7
|
+
cp .env.example .env
|
|
8
|
+
|
|
9
|
+
# 2. 根据需要编辑 .env
|
|
10
|
+
nano .env
|
|
11
|
+
|
|
12
|
+
# 3. 开始开发或部署
|
|
13
|
+
pnpm run dev # 本地开发
|
|
14
|
+
docker-compose up -d # Docker 部署
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 配置文件说明
|
|
20
|
+
|
|
21
|
+
### 文件优先级
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
.env.local (最高优先级) → .env → docker-compose.yml 默认值
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 文件列表
|
|
28
|
+
|
|
29
|
+
| 文件名 | 说明 | 提交到 Git | 使用场景 |
|
|
30
|
+
|-------|------|-----------|---------|
|
|
31
|
+
| `.env.example` | 环境变量模板 | ✅ 提交 | 新项目初始化 |
|
|
32
|
+
| `.env` | 默认环境配置 | ❌ 不提交 | 日常开发/部署 |
|
|
33
|
+
| `.env.development` | 开发环境配置 | ❌ 不提交 | 切换到开发环境 |
|
|
34
|
+
| `.env.production` | 生产环境配置 | ❌ 不提交 | 切换到生产环境 |
|
|
35
|
+
| `.env.local` | 本地敏感信息 | ❌ 不提交 | 存储密钥、密码等 |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 快速切换环境
|
|
40
|
+
|
|
41
|
+
### 使用 Makefile(推荐)
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# 切换到开发环境
|
|
45
|
+
make env-dev
|
|
46
|
+
|
|
47
|
+
# 切换到生产环境
|
|
48
|
+
make env-prod
|
|
49
|
+
|
|
50
|
+
# 创建本地配置文件
|
|
51
|
+
make env-local
|
|
52
|
+
|
|
53
|
+
# 查看当前配置
|
|
54
|
+
make show-env
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 手动方式
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 切换到开发环境
|
|
61
|
+
cp .env.development .env
|
|
62
|
+
|
|
63
|
+
# 切换到生产环境
|
|
64
|
+
cp .env.production .env
|
|
65
|
+
|
|
66
|
+
# 创建本地配置
|
|
67
|
+
cp .env.example .env.local
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 环境变量说明
|
|
73
|
+
|
|
74
|
+
### 基础配置
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# 运行环境
|
|
78
|
+
NODE_ENV=development # 或 production
|
|
79
|
+
|
|
80
|
+
# 服务端口
|
|
81
|
+
PORT=3001
|
|
82
|
+
|
|
83
|
+
# 时区
|
|
84
|
+
TZ=Asia/Shanghai
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 安全配置
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# 启用速率限制
|
|
91
|
+
ENABLE_RATE_LIMIT=1 # 1=启用,0=禁用
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**建议:**
|
|
95
|
+
- ✅ 开发环境:`ENABLE_RATE_LIMIT=0`(不影响开发效率)
|
|
96
|
+
- ✅ 生产环境:`ENABLE_RATE_LIMIT=1`(防止 DDoS 攻击)
|
|
97
|
+
|
|
98
|
+
### 调试配置
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# 启用详细日志
|
|
102
|
+
DEBUG=nsbp:*
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 使用场景
|
|
108
|
+
|
|
109
|
+
### 场景 1:新项目初始化
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# 1. 克隆项目
|
|
113
|
+
git clone <repository-url>
|
|
114
|
+
cd nsbp
|
|
115
|
+
|
|
116
|
+
# 2. 复制环境变量模板
|
|
117
|
+
cp .env.example .env
|
|
118
|
+
|
|
119
|
+
# 3. 安装依赖
|
|
120
|
+
pnpm install
|
|
121
|
+
|
|
122
|
+
# 4. 启动开发环境
|
|
123
|
+
pnpm run dev
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 场景 2:日常开发
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# 使用开发环境配置
|
|
130
|
+
make env-dev
|
|
131
|
+
|
|
132
|
+
# 启动开发环境
|
|
133
|
+
pnpm run dev
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 场景 3:Docker 部署
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# 切换到生产环境
|
|
140
|
+
make env-prod
|
|
141
|
+
|
|
142
|
+
# 启动 Docker 容器
|
|
143
|
+
docker-compose up -d
|
|
144
|
+
|
|
145
|
+
# 查看日志
|
|
146
|
+
docker-compose logs -f
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 场景 4:敏感信息管理
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# 1. 创建本地配置文件
|
|
153
|
+
make env-local
|
|
154
|
+
|
|
155
|
+
# 2. 编辑 .env.local 添加敏感信息
|
|
156
|
+
nano .env.local
|
|
157
|
+
|
|
158
|
+
# 添加内容:
|
|
159
|
+
# DATABASE_URL=postgresql://user:pass@localhost:5432/db
|
|
160
|
+
# API_SECRET=your-secret-key
|
|
161
|
+
# JWT_SECRET=jwt-secret-key
|
|
162
|
+
|
|
163
|
+
# .env.local 会自动覆盖 .env 中的同名变量
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 最佳实践
|
|
169
|
+
|
|
170
|
+
### ✅ 推荐做法
|
|
171
|
+
|
|
172
|
+
1. **始终使用 .env 文件**
|
|
173
|
+
```bash
|
|
174
|
+
# 不要在代码中硬编码
|
|
175
|
+
const PORT = process.env.PORT || 3001 # ✅
|
|
176
|
+
const PORT = 3001 # ❌
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
2. **分离敏感信息**
|
|
180
|
+
```bash
|
|
181
|
+
# .env - 非敏感配置(可以分享给团队)
|
|
182
|
+
NODE_ENV=development
|
|
183
|
+
PORT=3001
|
|
184
|
+
ENABLE_RATE_LIMIT=0
|
|
185
|
+
|
|
186
|
+
# .env.local - 敏感配置(个人使用)
|
|
187
|
+
DATABASE_URL=postgresql://localhost/db
|
|
188
|
+
API_KEY=secret-key-123
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
3. **提供 .env.example**
|
|
192
|
+
```bash
|
|
193
|
+
# .env.example - 示例配置(提交到 Git)
|
|
194
|
+
NODE_ENV=development
|
|
195
|
+
PORT=3001
|
|
196
|
+
ENABLE_RATE_LIMIT=0
|
|
197
|
+
# API_KEY=your-api-key # 提供示例,不包含真实值
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
4. **使用环境前缀**
|
|
201
|
+
```bash
|
|
202
|
+
# 命名规范
|
|
203
|
+
NSBP_NODE_ENV=development
|
|
204
|
+
NSBP_PORT=3001
|
|
205
|
+
NSBP_ENABLE_RATE_LIMIT=0
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### ❌ 避免做法
|
|
209
|
+
|
|
210
|
+
1. **不要提交 .env 到 Git**
|
|
211
|
+
```bash
|
|
212
|
+
# .gitignore 已包含
|
|
213
|
+
.env
|
|
214
|
+
.env.local
|
|
215
|
+
.env.*.local
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
2. **不要在代码中硬编码敏感信息**
|
|
219
|
+
```javascript
|
|
220
|
+
// ❌ 错误做法
|
|
221
|
+
const dbPassword = "my-password-123"
|
|
222
|
+
|
|
223
|
+
// ✅ 正确做法
|
|
224
|
+
const dbPassword = process.env.DB_PASSWORD
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
3. **不要在 .env.example 中包含真实值**
|
|
228
|
+
```bash
|
|
229
|
+
# .env.example - 只提供示例
|
|
230
|
+
API_KEY=your-api-key-here # ✅
|
|
231
|
+
API_KEY=sk-1234567890abcdef # ❌
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Docker Compose 集成
|
|
237
|
+
|
|
238
|
+
### 自动读取 .env
|
|
239
|
+
|
|
240
|
+
Docker Compose 会自动读取项目根目录下的 `.env` 文件:
|
|
241
|
+
|
|
242
|
+
```yaml
|
|
243
|
+
# docker-compose.yml
|
|
244
|
+
services:
|
|
245
|
+
app:
|
|
246
|
+
environment:
|
|
247
|
+
- NODE_ENV=${NODE_ENV:-production}
|
|
248
|
+
- PORT=${PORT:-3001}
|
|
249
|
+
- ENABLE_RATE_LIMIT=${ENABLE_RATE_LIMIT:-1}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### 使用方式
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
# 1. 创建 .env 文件
|
|
256
|
+
cp .env.production .env
|
|
257
|
+
|
|
258
|
+
# 2. Docker Compose 自动读取
|
|
259
|
+
docker-compose up -d
|
|
260
|
+
|
|
261
|
+
# 3. 验证环境变量
|
|
262
|
+
docker-compose exec app env | grep NODE_ENV
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 故障排除
|
|
268
|
+
|
|
269
|
+
### 问题 1:环境变量未生效
|
|
270
|
+
|
|
271
|
+
**检查步骤:**
|
|
272
|
+
```bash
|
|
273
|
+
# 1. 检查 .env 文件是否存在
|
|
274
|
+
ls -la .env
|
|
275
|
+
|
|
276
|
+
# 2. 查看文件内容
|
|
277
|
+
cat .env
|
|
278
|
+
|
|
279
|
+
# 3. 验证格式(等号两边不要有空格)
|
|
280
|
+
NODE_ENV=development # ✅
|
|
281
|
+
NODE_ENV = development # ❌
|
|
282
|
+
|
|
283
|
+
# 4. 重启服务
|
|
284
|
+
docker-compose restart
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### 问题 2:敏感信息泄露
|
|
288
|
+
|
|
289
|
+
**预防措施:**
|
|
290
|
+
```bash
|
|
291
|
+
# 1. 检查 .gitignore
|
|
292
|
+
cat .gitignore | grep .env
|
|
293
|
+
|
|
294
|
+
# 2. 验证文件未被提交
|
|
295
|
+
git ls-files | grep .env
|
|
296
|
+
|
|
297
|
+
# 3. 如果已提交,从历史记录中移除
|
|
298
|
+
git filter-branch --force --index-filter \
|
|
299
|
+
'git rm --cached --ignore-unmatch .env'
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 问题 3:环境变量优先级混乱
|
|
303
|
+
|
|
304
|
+
**验证方法:**
|
|
305
|
+
```bash
|
|
306
|
+
# 1. 显示容器中的环境变量
|
|
307
|
+
docker-compose exec app env | sort
|
|
308
|
+
|
|
309
|
+
# 2. 查看实际生效的值
|
|
310
|
+
docker-compose exec app sh -c 'echo $NODE_ENV'
|
|
311
|
+
|
|
312
|
+
# 3. 检查 .env.local 是否覆盖了预期值
|
|
313
|
+
cat .env.local | grep NODE_ENV
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## 常用命令速查
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
# 查看当前配置
|
|
322
|
+
make show-env
|
|
323
|
+
|
|
324
|
+
# 切换开发环境
|
|
325
|
+
make env-dev
|
|
326
|
+
|
|
327
|
+
# 切换生产环境
|
|
328
|
+
make env-prod
|
|
329
|
+
|
|
330
|
+
# 创建本地配置
|
|
331
|
+
make env-local
|
|
332
|
+
|
|
333
|
+
# 查看容器环境变量
|
|
334
|
+
docker-compose exec app env
|
|
335
|
+
|
|
336
|
+
# 验证特定变量
|
|
337
|
+
docker-compose exec app sh -c 'echo $ENABLE_RATE_LIMIT'
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## 参考资源
|
|
343
|
+
|
|
344
|
+
- [Docker Compose 环境变量](https://docs.docker.com/compose/environment-variables/)
|
|
345
|
+
- [Node.js process.env](https://nodejs.org/api/process.html#process_process_env)
|
|
346
|
+
- [十二因子应用](https://12factor.net/)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Docker 快速启动指南
|
|
2
|
+
|
|
3
|
+
🌐 **Online Demo**: [https://nsbp.erishen.cn/](https://nsbp.erishen.cn/)
|
|
4
|
+
|
|
5
|
+
## 5 分钟快速开始
|
|
6
|
+
|
|
7
|
+
### 生产环境(推荐用于生产部署)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 1. 构建并启动
|
|
11
|
+
docker-compose up -d
|
|
12
|
+
|
|
13
|
+
# 2. 查看状态
|
|
14
|
+
docker-compose ps
|
|
15
|
+
|
|
16
|
+
# 3. 查看日志(可选)
|
|
17
|
+
docker-compose logs -f
|
|
18
|
+
|
|
19
|
+
# 4. 访问应用
|
|
20
|
+
open http://localhost:3001
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
完成!🎉
|
|
24
|
+
|
|
25
|
+
### 开发环境(推荐用于开发)
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# 1. 构建并启动(前台运行,可查看构建日志)
|
|
29
|
+
docker-compose -f docker-compose.dev.yml up --build
|
|
30
|
+
|
|
31
|
+
# 2. 等待看到 "Server listening on port 3001"
|
|
32
|
+
# (首次启动需要 1-3 分钟进行构建)
|
|
33
|
+
|
|
34
|
+
# 3. 访问应用
|
|
35
|
+
open http://localhost:3001
|
|
36
|
+
|
|
37
|
+
# 4. 修改代码,自动热重载
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**提示:** 如果想在后台运行:
|
|
41
|
+
```bash
|
|
42
|
+
docker-compose -f docker-compose.dev.yml up -d --build
|
|
43
|
+
docker-compose -f docker-compose.dev.yml logs -f
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 常用命令
|
|
47
|
+
|
|
48
|
+
### 生产环境
|
|
49
|
+
```bash
|
|
50
|
+
make prod # 启动
|
|
51
|
+
make logs # 查看日志
|
|
52
|
+
make restart # 重启
|
|
53
|
+
make down # 停止
|
|
54
|
+
make clean # 完全清理
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 开发环境
|
|
58
|
+
```bash
|
|
59
|
+
make dev # 启动(带热重载)
|
|
60
|
+
make logs-dev # 查看日志
|
|
61
|
+
make restart-dev # 重启
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 通用
|
|
65
|
+
```bash
|
|
66
|
+
make help # 查看所有命令
|
|
67
|
+
make shell # 进入生产容器
|
|
68
|
+
make shell-dev # 进入开发容器
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## 验证安装
|
|
72
|
+
|
|
73
|
+
检查 Docker 是否正确安装:
|
|
74
|
+
```bash
|
|
75
|
+
docker --version
|
|
76
|
+
docker-compose --version
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
测试配置:
|
|
80
|
+
```bash
|
|
81
|
+
./scripts/verify-dev.sh
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 遇到问题?
|
|
85
|
+
|
|
86
|
+
- 查看 README.md 中的 Docker 部署章节
|
|
87
|
+
- 运行 `./scripts/verify-dev.sh` 验证开发环境状态
|
|
88
|
+
- 确保 Docker 守护进程正在运行
|
|
89
|
+
|
|
90
|
+
## 目录说明
|
|
91
|
+
|
|
92
|
+
- `Dockerfile` - 生产环境镜像
|
|
93
|
+
- `Dockerfile.dev` - 开发环境镜像
|
|
94
|
+
- `docker-compose.yml` - 生产环境配置
|
|
95
|
+
- `docker-compose.dev.yml` - 开发环境配置
|
|
96
|
+
- `Makefile` - 快捷命令
|
|
97
|
+
- `scripts/verify-dev.sh` - 开发环境验证脚本
|
|
98
|
+
- `README.md` - 完整文档
|
|
99
|
+
- `QUICKSTART.md` - 本文档
|
|
@@ -3,16 +3,16 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"description": "node react ssr by webpack",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"homepage": "https://nsbp.erishen.cn
|
|
6
|
+
"homepage": "https://nsbp.erishen.cn",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"dev": "npm-run-all -l -s dev:init -p dev:build:*",
|
|
9
|
-
"dev:init": "cross-env INIT=1 webpack --config webpack.server.js --mode development",
|
|
10
|
-
"dev:build:server": "webpack --config webpack.server.js --mode development --watch",
|
|
11
|
-
"dev:build:client": "webpack --config webpack.client.js --mode development --watch",
|
|
9
|
+
"dev:init": "cross-env INIT=1 webpack --config config/webpack.server.js --mode development",
|
|
10
|
+
"dev:build:server": "webpack --config config/webpack.server.js --mode development --watch",
|
|
11
|
+
"dev:build:client": "webpack --config config/webpack.client.js --mode development --watch",
|
|
12
12
|
"dev:build:start": "node ./scripts/start.js",
|
|
13
13
|
"build": "pnpm run clean && npm-run-all -l -p build:**",
|
|
14
|
-
"build:server": "webpack --config webpack.server.js --mode production",
|
|
15
|
-
"build:client": "webpack --config webpack.client.js --mode production",
|
|
14
|
+
"build:server": "webpack --config config/webpack.server.js --mode production",
|
|
15
|
+
"build:client": "webpack --config config/webpack.client.js --mode production",
|
|
16
16
|
"start": "node ./scripts/start.js",
|
|
17
17
|
"clean": "rimraf build && rimraf public/js && rimraf public/css && rimraf public/client.* && rimraf public/*.js && rimraf public/*.js.map && rimraf public/*.txt && rimraf public/*.json && rimraf .temp_cache",
|
|
18
18
|
"format": "prettier --write **/*.{js,css,less,scss,ts,tsx}",
|
|
@@ -37,7 +37,9 @@
|
|
|
37
37
|
"@reduxjs/toolkit": "^2.11.2",
|
|
38
38
|
"axios": "^1.7.0",
|
|
39
39
|
"express": "^5.2.1",
|
|
40
|
+
"express-rate-limit": "^8.2.0",
|
|
40
41
|
"framer-motion": "^12.25.0",
|
|
42
|
+
"helmet": "^8.1.0",
|
|
41
43
|
"lodash": "^4.17.21",
|
|
42
44
|
"probe-image-size": "^7.1.0",
|
|
43
45
|
"react": "^19.2.3",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#2563eb" />
|
|
5
|
+
<stop offset="100%" stop-color="#1d4ed8" />
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<rect width="100" height="100" rx="20" fill="url(#gradient)" />
|
|
9
|
+
<text x="50" y="68" font-family="Arial, sans-serif" font-size="60" font-weight="bold" text-anchor="middle" fill="white">N</text>
|
|
10
|
+
</svg>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Nsbp.js - 轻量级 React SSR 框架",
|
|
3
|
+
"short_name": "Nsbp.js",
|
|
4
|
+
"description": "轻量级 React SSR 框架,专为低资源部署与高度可定制场景而生",
|
|
5
|
+
"icons": [
|
|
6
|
+
{
|
|
7
|
+
"src": "/favicon-192x192.png",
|
|
8
|
+
"sizes": "192x192",
|
|
9
|
+
"type": "image/png"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"src": "/favicon-512x512.png",
|
|
13
|
+
"sizes": "512x512",
|
|
14
|
+
"type": "image/png"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"theme_color": "#2563eb",
|
|
18
|
+
"background_color": "#ffffff",
|
|
19
|
+
"display": "standalone"
|
|
20
|
+
}
|
|
@@ -20,7 +20,7 @@ else
|
|
|
20
20
|
echo ""
|
|
21
21
|
echo "启动命令:"
|
|
22
22
|
echo " make dev"
|
|
23
|
-
echo " docker-compose -f docker-compose.dev.yml up -d --build"
|
|
23
|
+
echo " docker-compose -f docker/docker-compose.dev.yml up -d --build"
|
|
24
24
|
exit 1
|
|
25
25
|
fi
|
|
26
26
|
|
|
@@ -35,7 +35,7 @@ fi
|
|
|
35
35
|
|
|
36
36
|
echo ""
|
|
37
37
|
echo "3. 检查权限错误..."
|
|
38
|
-
if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "EACCES"; then
|
|
38
|
+
if docker-compose -f docker/docker-compose.dev.yml logs 2>&1 | grep -q "EACCES"; then
|
|
39
39
|
echo -e "${RED}❌ 发现权限错误${NC}"
|
|
40
40
|
echo ""
|
|
41
41
|
echo "最近的权限错误:"
|
|
@@ -46,7 +46,7 @@ fi
|
|
|
46
46
|
|
|
47
47
|
echo ""
|
|
48
48
|
echo "4. 检查构建状态..."
|
|
49
|
-
if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "compiled successfully"; then
|
|
49
|
+
if docker-compose -f docker/docker-compose.dev.yml logs 2>&1 | grep -q "compiled successfully"; then
|
|
50
50
|
echo -e "${GREEN}✅ 构建完成${NC}"
|
|
51
51
|
else
|
|
52
52
|
echo -e "${YELLOW}⚠️ 构建中或未开始${NC}"
|
|
@@ -54,7 +54,7 @@ fi
|
|
|
54
54
|
|
|
55
55
|
echo ""
|
|
56
56
|
echo "5. 检查服务器监听..."
|
|
57
|
-
if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "listening"; then
|
|
57
|
+
if docker-compose -f docker/docker-compose.dev.yml logs 2>&1 | grep -q "listening"; then
|
|
58
58
|
echo -e "${GREEN}✅ 服务器正在监听${NC}"
|
|
59
59
|
else
|
|
60
60
|
echo -e "${YELLOW}⚠️ 服务器尚未启动监听${NC}"
|
|
@@ -69,9 +69,9 @@ echo "访问应用:"
|
|
|
69
69
|
echo " http://localhost:3001"
|
|
70
70
|
echo ""
|
|
71
71
|
echo "查看日志:"
|
|
72
|
-
echo " docker-compose -f docker-compose.dev.yml logs -f"
|
|
72
|
+
echo " docker-compose -f docker/docker-compose.dev.yml logs -f"
|
|
73
73
|
echo ""
|
|
74
74
|
echo "停止服务:"
|
|
75
75
|
echo " make down"
|
|
76
|
-
echo " docker-compose -f docker-compose.dev.yml down"
|
|
76
|
+
echo " docker-compose -f docker/docker-compose.dev.yml down"
|
|
77
77
|
echo ""
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "========================================="
|
|
4
|
+
echo "NSBP 安全功能验证"
|
|
5
|
+
echo "========================================="
|
|
6
|
+
echo ""
|
|
7
|
+
|
|
8
|
+
GREEN='\033[0;32m'
|
|
9
|
+
RED='\033[0;31m'
|
|
10
|
+
YELLOW='\033[1;33m'
|
|
11
|
+
NC='\033[0m'
|
|
12
|
+
|
|
13
|
+
# 检查依赖
|
|
14
|
+
echo "1. 检查安全依赖安装..."
|
|
15
|
+
if grep -q '"helmet"' package.json && grep -q '"express-rate-limit"' package.json; then
|
|
16
|
+
echo -e "${GREEN}✅ helmet 和 express-rate-limit 已安装${NC}"
|
|
17
|
+
else
|
|
18
|
+
echo -e "${RED}❌ 缺少安全依赖${NC}"
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
echo ""
|
|
23
|
+
|
|
24
|
+
# 检查服务器代码
|
|
25
|
+
echo "2. 检查服务器代码安全配置..."
|
|
26
|
+
if grep -q "helmet(" src/server/index.ts; then
|
|
27
|
+
echo -e "${GREEN}✅ Helmet 已启用${NC}"
|
|
28
|
+
else
|
|
29
|
+
echo -e "${RED}❌ Helmet 未配置${NC}"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
if grep -q "rateLimit" src/server/index.ts; then
|
|
33
|
+
echo -e "${GREEN}✅ 速率限制已配置(可选)${NC}"
|
|
34
|
+
else
|
|
35
|
+
echo -e "${RED}❌ 速率限制未配置${NC}"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if grep -q "dotfiles: 'ignore'" src/server/index.ts; then
|
|
39
|
+
echo -e "${GREEN}✅ dotfiles 访问已禁用${NC}"
|
|
40
|
+
else
|
|
41
|
+
echo -e "${RED}⚠️ dotfiles 配置需要检查${NC}"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
if grep -q "disable('x-powered-by')" src/server/index.ts; then
|
|
45
|
+
echo -e "${GREEN}✅ X-Powered-By 已隐藏${NC}"
|
|
46
|
+
else
|
|
47
|
+
echo -e "${RED}❌ X-Powered-By 未隐藏${NC}"
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
if grep -q "express.json.*limit" src/server/index.ts && grep -q "express.urlencoded.*limit" src/server/index.ts; then
|
|
51
|
+
echo -e "${GREEN}✅ 请求体大小限制已配置${NC}"
|
|
52
|
+
else
|
|
53
|
+
echo -e "${RED}❌ 请求体大小限制未配置${NC}"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
echo ""
|
|
57
|
+
|
|
58
|
+
# 检查 CSP 配置
|
|
59
|
+
echo "3. 检查 Content Security Policy..."
|
|
60
|
+
if grep -q "contentSecurityPolicy" src/server/index.ts; then
|
|
61
|
+
echo -e "${GREEN}✅ CSP 已配置${NC}"
|
|
62
|
+
if grep -q "defaultSrc.*'self'" src/server/index.ts; then
|
|
63
|
+
echo -e "${GREEN} - default-src: 'self'${NC}"
|
|
64
|
+
fi
|
|
65
|
+
if grep -q "scriptSrc" src/server/index.ts; then
|
|
66
|
+
echo -e "${GREEN} - script-src 已配置${NC}"
|
|
67
|
+
fi
|
|
68
|
+
if grep -q "styleSrc" src/server/index.ts; then
|
|
69
|
+
echo -e "${GREEN} - style-src 已配置${NC}"
|
|
70
|
+
fi
|
|
71
|
+
if grep -q "imgSrc.*https:" src/server/index.ts; then
|
|
72
|
+
echo -e "${GREEN} - img-src 允许 HTTPS${NC}"
|
|
73
|
+
fi
|
|
74
|
+
else
|
|
75
|
+
echo -e "${RED}❌ CSP 未配置${NC}"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo ""
|
|
79
|
+
|
|
80
|
+
# 检查文档
|
|
81
|
+
echo "4. 检查安全文档..."
|
|
82
|
+
if grep -q "## 安全特性" README.md; then
|
|
83
|
+
echo -e "${GREEN}✅ 安全章节已添加到 README${NC}"
|
|
84
|
+
else
|
|
85
|
+
echo -e "${YELLOW}⚠️ 建议添加安全章节到 README${NC}"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
echo ""
|
|
89
|
+
|
|
90
|
+
# 统计
|
|
91
|
+
echo "========================================="
|
|
92
|
+
echo "安全配置统计"
|
|
93
|
+
echo "========================================="
|
|
94
|
+
|
|
95
|
+
TOTAL_CHECKS=7
|
|
96
|
+
PASSED_CHECKS=0
|
|
97
|
+
|
|
98
|
+
# 统计通过项
|
|
99
|
+
grep -q '"helmet"' package.json && grep -q '"express-rate-limit"' package.json && ((PASSED_CHECKS++))
|
|
100
|
+
grep -q "helmet(" src/server/index.ts && ((PASSED_CHECKS++))
|
|
101
|
+
grep -q "dotfiles: 'ignore'" src/server/index.ts && ((PASSED_CHECKS++))
|
|
102
|
+
grep -q "disable('x-powered-by')" src/server/index.ts && ((PASSED_CHECKS++))
|
|
103
|
+
grep -q "express.json.*limit" src/server/index.ts && ((PASSED_CHECKS++))
|
|
104
|
+
grep -q "contentSecurityPolicy" src/server/index.ts && ((PASSED_CHECKS++))
|
|
105
|
+
grep -q "## 安全特性" README.md && ((PASSED_CHECKS++))
|
|
106
|
+
|
|
107
|
+
SCORE=$(( PASSED_CHECKS * 100 / TOTAL_CHECKS ))
|
|
108
|
+
|
|
109
|
+
echo -e "通过率: ${PASSED_CHECKS}/${TOTAL_CHECKS} (${YELLOW}${SCORE}%${NC})"
|
|
110
|
+
echo ""
|
|
111
|
+
|
|
112
|
+
if [ $SCORE -eq 100 ]; then
|
|
113
|
+
echo -e "${GREEN}🎉 所有安全检查通过!${NC}"
|
|
114
|
+
echo "项目已达到生产级安全标准。"
|
|
115
|
+
elif [ $SCORE -ge 70 ]; then
|
|
116
|
+
echo -e "${YELLOW}✅ 安全配置良好${NC}"
|
|
117
|
+
echo "建议检查未通过的项目。"
|
|
118
|
+
else
|
|
119
|
+
echo -e "${RED}⚠️ 安全配置需要改进${NC}"
|
|
120
|
+
echo "请检查上述未通过的项目。"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
echo ""
|
|
124
|
+
echo "========================================="
|
|
@@ -1,12 +1,62 @@
|
|
|
1
1
|
import express from 'express'
|
|
2
|
+
import helmet from 'helmet'
|
|
3
|
+
import rateLimit from 'express-rate-limit'
|
|
2
4
|
import { render } from './utils'
|
|
3
5
|
import { getPhotoWH, getPhotoMenu } from './photo'
|
|
4
6
|
import { useCurrentFlag, outPhotoDicPath } from '../utils/config'
|
|
5
7
|
|
|
6
8
|
const app = express()
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
// 1. Security headers (helmet)
|
|
11
|
+
app.use(helmet({
|
|
12
|
+
contentSecurityPolicy: {
|
|
13
|
+
directives: {
|
|
14
|
+
defaultSrc: ["'self'"],
|
|
15
|
+
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
|
|
16
|
+
styleSrc: ["'self'", "'unsafe-inline'"],
|
|
17
|
+
imgSrc: ["'self'", "data:", "https:"],
|
|
18
|
+
connectSrc: ["'self'", "https:"],
|
|
19
|
+
fontSrc: ["'self'", "data:"],
|
|
20
|
+
objectSrc: ["'none'"],
|
|
21
|
+
mediaSrc: ["'self'"],
|
|
22
|
+
frameSrc: ["'none'"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
crossOriginEmbedderPolicy: false, // Allow inline scripts for SSR
|
|
26
|
+
crossOriginOpenerPolicy: false, // Allow window.open for development
|
|
27
|
+
}))
|
|
28
|
+
|
|
29
|
+
// 2. Hide X-Powered-By header
|
|
30
|
+
app.disable('x-powered-by')
|
|
31
|
+
|
|
32
|
+
// 3. Rate limiting (optional, controlled by environment variable)
|
|
33
|
+
if (process.env.ENABLE_RATE_LIMIT === '1') {
|
|
34
|
+
const limiter = rateLimit({
|
|
35
|
+
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
36
|
+
max: 100, // Limit each IP to 100 requests per windowMs
|
|
37
|
+
message: 'Too many requests from this IP, please try again later.',
|
|
38
|
+
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
|
|
39
|
+
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
|
|
40
|
+
})
|
|
41
|
+
app.use('/api', limiter)
|
|
42
|
+
console.log('🛡️ Rate limiting enabled for /api routes')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 4. Static file serving (disable dotfiles access)
|
|
46
|
+
app.use(express.static('public', {
|
|
47
|
+
dotfiles: 'ignore',
|
|
48
|
+
setHeaders: (res, filePath) => {
|
|
49
|
+
// Cache static assets for 1 year
|
|
50
|
+
if (filePath.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$/)) {
|
|
51
|
+
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}))
|
|
55
|
+
!useCurrentFlag && app.use(express.static(outPhotoDicPath, { dotfiles: 'ignore' }))
|
|
56
|
+
|
|
57
|
+
// 5. Body parsing with size limits
|
|
58
|
+
app.use(express.json({ limit: '10mb' }))
|
|
59
|
+
app.use(express.urlencoded({ limit: '10mb', extended: true }))
|
|
10
60
|
|
|
11
61
|
//使用express提供的static中间件,中间件会将所有静态文件的路由指向public文件夹
|
|
12
62
|
|
|
@@ -27,4 +77,8 @@ app.use((req, res) => {
|
|
|
27
77
|
const PORT = process.env.PORT || 3001
|
|
28
78
|
app.listen(PORT, () => {
|
|
29
79
|
console.log(`Server listening on port ${PORT}`)
|
|
80
|
+
console.log(`🔒 Security headers enabled`)
|
|
81
|
+
if (process.env.ENABLE_RATE_LIMIT === '1') {
|
|
82
|
+
console.log(`🚦 Rate limiting active`)
|
|
83
|
+
}
|
|
30
84
|
})
|
|
@@ -116,6 +116,13 @@ export const render = (req: any, res: any) => {
|
|
|
116
116
|
<html>
|
|
117
117
|
<head>
|
|
118
118
|
<meta charset="utf-8">
|
|
119
|
+
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
|
120
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
121
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
|
122
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
|
123
|
+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
|
124
|
+
<link rel="manifest" href="/site.webmanifest">
|
|
125
|
+
<meta name="theme-color" content="#2563eb">
|
|
119
126
|
${helmet?.title?.toString()}
|
|
120
127
|
${helmet?.meta?.toString()}
|
|
121
128
|
${styleTags}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|