nsbp-cli 0.2.1 → 0.2.3

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/bin/nsbp.js CHANGED
@@ -63,6 +63,12 @@ program
63
63
  '.prettierrc',
64
64
  '.prettierignore',
65
65
  '.gitignore',
66
+ '.dockerignore',
67
+ 'docker-compose.yml',
68
+ 'docker-compose.dev.yml',
69
+ 'Dockerfile',
70
+ 'Dockerfile.dev',
71
+ 'Makefile',
66
72
  'README.md'
67
73
  ];
68
74
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nsbp-cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "CLI tool for creating NSBP (Node React SSR by Webpack) projects",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -0,0 +1,56 @@
1
+ # Dependencies
2
+ node_modules
3
+ npm-debug.log
4
+ yarn-error.log
5
+ yarn-debug.log
6
+ pnpm-debug.log
7
+ pnpm-lock.yaml
8
+
9
+ # Build outputs
10
+ build
11
+ public/js
12
+ public/css
13
+ public/client.*
14
+ public/*.js
15
+ public/*.js.map
16
+ public/*.txt
17
+ public/*.json
18
+ .temp_cache
19
+
20
+ # IDE
21
+ .vscode
22
+ .idea
23
+ *.swp
24
+ *.swo
25
+ *~
26
+
27
+ # OS
28
+ .DS_Store
29
+ Thumbs.db
30
+
31
+ # Git
32
+ .git
33
+ .gitignore
34
+
35
+ # Docker
36
+ Dockerfile*
37
+ docker-compose*.yml
38
+ .dockerignore
39
+
40
+ # CI/CD
41
+ .github
42
+ .gitlab-ci.yml
43
+
44
+ # Environment
45
+ .env.local
46
+ .env.*.local
47
+
48
+ # Logs
49
+ logs
50
+ *.log
51
+
52
+ # CLI (for main project only)
53
+ cli
54
+
55
+ # Serena
56
+ .serena
@@ -0,0 +1,65 @@
1
+ # Multi-stage build for production
2
+
3
+ # Stage 1: Build
4
+ FROM node:20-alpine AS builder
5
+
6
+ # Set working directory
7
+ WORKDIR /app
8
+
9
+ # Copy package files
10
+ COPY package*.json ./
11
+
12
+ # Install pnpm and dependencies (including devDependencies for building)
13
+ RUN npm install -g pnpm && pnpm install
14
+
15
+ # Copy source code
16
+ COPY . .
17
+
18
+ # Build application
19
+ RUN npm run build
20
+
21
+ # Stage 2: Production
22
+ FROM node:20-alpine AS production
23
+
24
+ # Install dumb-init for proper signal handling
25
+ RUN apk add --no-cache dumb-init
26
+
27
+ # Create non-root user
28
+ RUN addgroup -g 1001 -S nodejs && \
29
+ adduser -S nodejs -u 1001
30
+
31
+ # Set working directory
32
+ WORKDIR /app
33
+
34
+ # Copy package files
35
+ COPY package*.json ./
36
+
37
+ # Install pnpm and only production dependencies
38
+ RUN npm install -g pnpm && pnpm install --prod && pnpm store prune
39
+
40
+ # Copy build artifacts from builder stage
41
+ COPY --from=builder /app/build ./build
42
+ COPY --from=builder /app/public ./public
43
+
44
+ # Copy scripts and config
45
+ COPY --from=builder /app/scripts ./scripts
46
+ COPY --from=builder /app/tsconfig.json ./
47
+
48
+ # Change ownership
49
+ RUN chown -R nodejs:nodejs /app
50
+
51
+ # Switch to non-root user
52
+ USER nodejs
53
+
54
+ # Expose port
55
+ EXPOSE 3001
56
+
57
+ # Health check
58
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
59
+ CMD node -e "require('http').get('http://localhost:3001', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
60
+
61
+ # Use dumb-init to handle signals properly
62
+ ENTRYPOINT ["dumb-init", "--"]
63
+
64
+ # Start application
65
+ CMD ["node", "./scripts/start.js"]
@@ -0,0 +1,52 @@
1
+ # Development Dockerfile
2
+
3
+ FROM node:20-alpine
4
+
5
+ # Install dumb-init for proper signal handling
6
+ RUN apk add --no-cache dumb-init
7
+
8
+ # Create non-root user
9
+ RUN addgroup -g 1001 -S nodejs && \
10
+ adduser -S nodejs -u 1001
11
+
12
+ # Set working directory
13
+ WORKDIR /app
14
+
15
+ # Copy package files first to leverage Docker cache
16
+ COPY package*.json ./
17
+
18
+ # Install pnpm and all dependencies (including devDependencies)
19
+ RUN npm install -g pnpm && pnpm install && pnpm store prune
20
+
21
+ # Copy application code
22
+ COPY . .
23
+
24
+ # Create build directory with proper permissions
25
+ RUN mkdir -p /app/build && \
26
+ chown -R nodejs:nodejs /app
27
+
28
+ # Create entrypoint script to fix volume permissions
29
+ RUN printf '#!/bin/sh\n\
30
+ # Fix permissions for volume mounts before switching user\n\
31
+ if [ -d "/app/build" ]; then\n\
32
+ chown -R nodejs:nodejs /app/build 2>/dev/null || true\n\
33
+ chmod -R 755 /app/build 2>/dev/null || true\n\
34
+ fi\n\
35
+ if [ -d "/app/node_modules" ]; then\n\
36
+ chown -R nodejs:nodejs /app/node_modules 2>/dev/null || true\n\
37
+ fi\n\
38
+ # Switch to nodejs user and execute command\n\
39
+ exec su-exec nodejs:nodejs "$@"\n' > /entrypoint.sh && \
40
+ chmod +x /entrypoint.sh
41
+
42
+ # Install su-exec for user switching
43
+ RUN apk add --no-cache su-exec
44
+
45
+ # Expose port
46
+ EXPOSE 3001
47
+
48
+ # Use entrypoint (runs as root, fixes perms, then switches to nodejs)
49
+ ENTRYPOINT ["/entrypoint.sh"]
50
+
51
+ # Start development server
52
+ CMD ["dumb-init", "--", "npm", "run", "dev"]
@@ -0,0 +1,66 @@
1
+ .PHONY: help build dev prod down clean logs restart publish-cli
2
+
3
+ help: ## Show this help message
4
+ @echo 'Usage: make [target]'
5
+ @echo ''
6
+ @echo 'Available targets:'
7
+ @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " \033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
8
+
9
+ build: ## Build Docker images for production
10
+ docker-compose build
11
+
12
+ build-dev: ## Build Docker images for development
13
+ docker-compose -f docker-compose.dev.yml build
14
+
15
+ dev: ## Start development environment (removes orphan containers)
16
+ docker-compose -f docker-compose.dev.yml up --build --remove-orphans
17
+
18
+ prod: ## Start production environment (removes orphan containers)
19
+ docker-compose up -d --remove-orphans
20
+
21
+ down: ## Stop and remove containers (including orphan containers)
22
+ docker-compose down --remove-orphans
23
+ docker-compose -f docker-compose.dev.yml down --remove-orphans
24
+
25
+ clean: ## Stop containers, remove images and volumes (including orphan containers)
26
+ docker-compose down -v --rmi all --remove-orphans
27
+ docker-compose -f docker-compose.dev.yml down -v --rmi all --remove-orphans
28
+
29
+ logs: ## View logs
30
+ docker-compose logs -f
31
+
32
+ logs-dev: ## View development logs
33
+ docker-compose -f docker-compose.dev.yml logs -f
34
+
35
+ restart: ## Restart production containers
36
+ docker-compose restart
37
+
38
+ restart-dev: ## Restart development containers
39
+ docker-compose -f docker-compose.dev.yml restart
40
+
41
+ rebuild: ## Rebuild and restart production containers (removes orphan containers)
42
+ docker-compose up -d --build --remove-orphans
43
+
44
+ rebuild-dev: ## Rebuild and restart development containers (removes orphan containers)
45
+ docker-compose -f docker-compose.dev.yml up -d --build --remove-orphans
46
+
47
+ shell: ## Open shell in production container
48
+ docker-compose exec app sh
49
+
50
+ shell-dev: ## Open shell in development container
51
+ docker-compose -f docker-compose.dev.yml exec app sh
52
+
53
+ test: ## Run tests (if configured)
54
+ docker-compose exec app npm test
55
+
56
+ publish-cli: ## Publish CLI to npm registry
57
+ @echo "🚀 Starting CLI publish process..."
58
+ cd cli && npm run update
59
+ @echo "📦 Template updated, committing changes..."
60
+ git add .
61
+ git diff --quiet && git diff --cached --quiet || git commit -m "chore: update cli template"
62
+ cd cli && npm version patch
63
+ cd cli && npm publish
64
+ @echo "📤 Pushing to git repository..."
65
+ git push --follow-tags
66
+ @echo "✅ CLI published successfully!"
@@ -1,6 +1,6 @@
1
1
  # 开发
2
2
  - npm run dev (开发运行)
3
- - npm run build (生产编译)
3
+ - npm run build (生产编译)
4
4
  - npm start (生产运行)
5
5
 
6
6
  客户端渲染
@@ -10,4 +10,128 @@ http://localhost:3001/
10
10
  http://localhost:3001/?seo=1
11
11
 
12
12
  服务端渲染不成功,改为客户端渲染
13
- http://localhost:3001/?seo=1&from=link
13
+ http://localhost:3001/?seo=1&from=link
14
+
15
+ ## Docker 部署
16
+
17
+ **权限问题已修复!** 详细说明见下面的开发环境说明。
18
+
19
+ ### 生产环境
20
+
21
+ 使用 Makefile (推荐):
22
+
23
+ ```bash
24
+ # 构建并启动
25
+ make prod
26
+
27
+ # 或分步执行
28
+ make build
29
+ make prod
30
+
31
+ # 查看日志
32
+ make logs
33
+
34
+ # 重启
35
+ make restart
36
+
37
+ # 进入容器
38
+ make shell
39
+
40
+ # 停止
41
+ make down
42
+
43
+ # 完全清理(删除镜像和卷)
44
+ make clean
45
+ ```
46
+
47
+ 或直接使用 Docker Compose:
48
+
49
+ ```bash
50
+ # 构建镜像
51
+ docker-compose build
52
+
53
+ # 启动服务(后台运行)
54
+ docker-compose up -d
55
+
56
+ # 查看日志
57
+ docker-compose logs -f
58
+
59
+ # 停止服务
60
+ docker-compose down
61
+ ```
62
+
63
+ 访问: http://localhost:3001
64
+
65
+ ### 开发环境
66
+
67
+ ⚠️ **重要提示**:
68
+ 1. 首次启动开发环境需要等待构建完成,期间可能看到 `Cannot find module` 错误,这是正常的
69
+ 2. 开发环境使用 volume 挂载,遇到权限问题时会自动修复
70
+ 3. 如果遇到权限错误(EACCES),容器会自动修复权限(通过 entrypoint.sh)
71
+
72
+ ```bash
73
+ # 启动开发环境(带热重载)
74
+ make dev
75
+
76
+ # 查看日志
77
+ make logs-dev
78
+
79
+ # 进入容器
80
+ make shell-dev
81
+
82
+ # 重启开发环境
83
+ make restart-dev
84
+
85
+ # 重新构建并启动
86
+ make rebuild-dev
87
+ ```
88
+
89
+ 或直接使用 Docker Compose:
90
+
91
+ ```bash
92
+ # 构建并启动开发环境
93
+ docker-compose -f docker-compose.dev.yml up --build
94
+
95
+ # 后台运行
96
+ docker-compose -f docker-compose.dev.yml up -d --build
97
+
98
+ # 查看日志
99
+ docker-compose -f docker-compose.dev.yml logs -f
100
+
101
+ # 停止
102
+ docker-compose -f docker-compose.dev.yml down
103
+ ```
104
+
105
+ ### Docker 命令速查
106
+
107
+ ```bash
108
+ # 查看所有可用命令
109
+ make help
110
+
111
+ # 生产环境
112
+ make build # 构建镜像
113
+ make prod # 启动生产环境
114
+ make logs # 查看日志
115
+ make restart # 重启容器
116
+ make shell # 进入容器
117
+ make down # 停止容器
118
+
119
+ # 开发环境
120
+ make build-dev # 构建开发镜像
121
+ make dev # 启动开发环境
122
+ make logs-dev # 查看开发日志
123
+ make restart-dev # 重启开发容器
124
+ make shell-dev # 进入开发容器
125
+
126
+ # 通用命令
127
+ make clean # 清理所有资源(镜像、卷等)
128
+ make rebuild # 重新构建并启动生产环境
129
+ make rebuild-dev # 重新构建并启动开发环境
130
+ ```
131
+
132
+ ### 环境变量
133
+
134
+ 可在 `docker-compose.yml` 或 `docker-compose.dev.yml` 中配置环境变量:
135
+
136
+ - `NODE_ENV`: 运行环境 (production/development)
137
+ - `PORT`: 服务端口 (默认 3001)
@@ -0,0 +1,37 @@
1
+ services:
2
+ app:
3
+ build:
4
+ context: .
5
+ dockerfile: Dockerfile.dev
6
+ container_name: nsbp-app-dev
7
+ ports:
8
+ - "3001:3001"
9
+ - "9229:9229" # Node.js debug port
10
+ environment:
11
+ - NODE_ENV=development
12
+ - PORT=3001
13
+ volumes:
14
+ # Mount source code for hot reload
15
+ - ./src:/app/src
16
+ - ./public:/app/public
17
+ - ./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
21
+ - ./tsconfig.json:/app/tsconfig.json
22
+ # Persist node_modules
23
+ - node_modules:/app/node_modules
24
+ # Build output - named volume for persistence
25
+ - build_output:/app/build
26
+ command: ["dumb-init", "--", "npm", "run", "dev"]
27
+ restart: unless-stopped
28
+ networks:
29
+ - nsbp-network
30
+
31
+ volumes:
32
+ node_modules:
33
+ build_output:
34
+
35
+ networks:
36
+ nsbp-network:
37
+ driver: bridge
@@ -0,0 +1,24 @@
1
+ services:
2
+ app:
3
+ build:
4
+ context: .
5
+ dockerfile: Dockerfile
6
+ container_name: nsbp-app
7
+ ports:
8
+ - "3001:3001"
9
+ environment:
10
+ - NODE_ENV=production
11
+ - PORT=3001
12
+ restart: unless-stopped
13
+ healthcheck:
14
+ test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
15
+ interval: 30s
16
+ timeout: 3s
17
+ retries: 3
18
+ start_period: 5s
19
+ networks:
20
+ - nsbp-network
21
+
22
+ networks:
23
+ nsbp-network:
24
+ driver: bridge
@@ -0,0 +1,77 @@
1
+ #!/bin/bash
2
+
3
+ # 开发环境验证脚本
4
+
5
+ echo "========================================="
6
+ echo "Docker 开发环境验证"
7
+ echo "========================================="
8
+ echo ""
9
+
10
+ GREEN='\033[0;32m'
11
+ RED='\033[0;31m'
12
+ NC='\033[0m'
13
+
14
+ # 检查容器状态
15
+ echo "1. 检查容器状态..."
16
+ if docker ps | grep -q "nsbp-app-dev"; then
17
+ echo -e "${GREEN}✅ 容器正在运行${NC}"
18
+ else
19
+ echo -e "${RED}❌ 容器未运行${NC}"
20
+ echo ""
21
+ echo "启动命令:"
22
+ echo " make dev"
23
+ echo " docker-compose -f docker-compose.dev.yml up -d --build"
24
+ exit 1
25
+ fi
26
+
27
+ echo ""
28
+ echo "2. 检查服务是否可访问..."
29
+ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3001)
30
+ if [ "$HTTP_CODE" = "200" ]; then
31
+ echo -e "${GREEN}✅ 服务可访问 (HTTP $HTTP_CODE)${NC}"
32
+ else
33
+ echo -e "${RED}❌ 服务不可访问 (HTTP $HTTP_CODE)${NC}"
34
+ fi
35
+
36
+ echo ""
37
+ echo "3. 检查权限错误..."
38
+ if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "EACCES"; then
39
+ echo -e "${RED}❌ 发现权限错误${NC}"
40
+ echo ""
41
+ echo "最近的权限错误:"
42
+ docker-compose -f docker-compose.dev.yml logs | grep "EACCES" | tail -3
43
+ else
44
+ echo -e "${GREEN}✅ 未发现权限错误${NC}"
45
+ fi
46
+
47
+ echo ""
48
+ echo "4. 检查构建状态..."
49
+ if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "compiled successfully"; then
50
+ echo -e "${GREEN}✅ 构建完成${NC}"
51
+ else
52
+ echo -e "${YELLOW}⚠️ 构建中或未开始${NC}"
53
+ fi
54
+
55
+ echo ""
56
+ echo "5. 检查服务器监听..."
57
+ if docker-compose -f docker-compose.dev.yml logs 2>&1 | grep -q "listening"; then
58
+ echo -e "${GREEN}✅ 服务器正在监听${NC}"
59
+ else
60
+ echo -e "${YELLOW}⚠️ 服务器尚未启动监听${NC}"
61
+ fi
62
+
63
+ echo ""
64
+ echo "========================================="
65
+ echo -e "${GREEN}验证完成!${NC}"
66
+ echo "========================================="
67
+ echo ""
68
+ echo "访问应用:"
69
+ echo " http://localhost:3001"
70
+ echo ""
71
+ echo "查看日志:"
72
+ echo " docker-compose -f docker-compose.dev.yml logs -f"
73
+ echo ""
74
+ echo "停止服务:"
75
+ echo " make down"
76
+ echo " docker-compose -f docker-compose.dev.yml down"
77
+ echo ""
@@ -347,7 +347,7 @@ export const getPhotoMenu = (req: any, res: any) => {
347
347
  <QuickStartGrid>
348
348
  <QuickStartCard>
349
349
  <QuickStartTitle>1️⃣ 创建项目</QuickStartTitle>
350
- <QuickStartCode>$ npx nsbp create my-app</QuickStartCode>
350
+ <QuickStartCode>$ npx nsbp-cli create my-app</QuickStartCode>
351
351
  <QuickStartDescription>
352
352
  使用 CLI 工具创建新项目
353
353
  </QuickStartDescription>
@@ -394,7 +394,7 @@ export const getPhotoMenu = (req: any, res: any) => {
394
394
  <PhotoCard>
395
395
  <PhotoImageWrapper>
396
396
  <PhotoImage
397
- src={item.cover}
397
+ src={item.cover || 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='}
398
398
  alt={item.name}
399
399
  loading="lazy"
400
400
  />
@@ -123,7 +123,7 @@ const Photo = ({ query, data, menu, getPhotoMenu }: any) => {
123
123
  <motion.img
124
124
  key={i}
125
125
  className="demo4-photo"
126
- src={useCurrentFlag ? `/images/${photos[i][2]}` : photos[i][2]}
126
+ src={photos[i][2] ? (useCurrentFlag ? `/images/${photos[i][2]}` : photos[i][2]) : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='}
127
127
  initial={false}
128
128
  animate={{
129
129
  left: pos.left,
@@ -5,8 +5,8 @@ import { useCurrentFlag, outPhotoDicPath } from '../utils/config'
5
5
 
6
6
  const app = express()
7
7
 
8
- app.use(express.static('public'))
9
- !useCurrentFlag && app.use(express.static(outPhotoDicPath))
8
+ app.use(express.static('public', { dotfiles: 'allow' }))
9
+ !useCurrentFlag && app.use(express.static(outPhotoDicPath, { dotfiles: 'allow' }))
10
10
 
11
11
  //使用express提供的static中间件,中间件会将所有静态文件的路由指向public文件夹
12
12
 
@@ -47,7 +47,7 @@ const getFileMenu = (dir: string): { name: string; cover?: string; count?: numbe
47
47
  const count = files.length
48
48
 
49
49
  // 在该目录下找 cover.jpg
50
- let cover = undefined
50
+ let cover = ''
51
51
  const coverPath = path.join(fullPath, 'cover.jpg')
52
52
  if (fs.existsSync(coverPath)) {
53
53
  // 转成相对 public 的 URL 路径
@@ -227,11 +227,12 @@ module.exports = ({ mode, entry, server, init }) => {
227
227
  },
228
228
  name(module) {
229
229
  //名字就是包当中的名字
230
- return (
231
- /[\\/]node_modules[\\/](.*)/.exec(module.identifier()) &&
232
- /[\\/]node_modules[\\/](.*)/.exec(module.identifier()).length &&
233
- /[\\/]node_modules[\\/](.*)/.exec(module.identifier())[1].replace(/\/|\\/g, '_')
234
- )
230
+ const match = /[\\/]node_modules[\\/](.*)/.exec(module.identifier())
231
+ if (match && match.length) {
232
+ // 移除开头的点号,避免生成隐藏文件
233
+ return match[1].replace(/\/|\\/g, '_').replace(/^\./, '')
234
+ }
235
+ return false
235
236
  },
236
237
  minChunks: 1, //最小共用次数为1时就使用
237
238
  priority: 30, //权重为30