create-aomex 0.0.11 → 0.0.13

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/dist/index.js CHANGED
@@ -121,7 +121,8 @@ spinner.add({
121
121
  "@aomex/async-trace",
122
122
  "@prisma/client",
123
123
  "@aomex/cache",
124
- "@aomex/cache-redis-adapter"
124
+ "@aomex/cache-redis-adapter",
125
+ "ioredis"
125
126
  ]
126
127
  },
127
128
  {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/replace-variables.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport path from 'node:path/posix';\nimport yargsParser from 'yargs-parser';\nimport { existsSync } from 'node:fs';\nimport { cp, mkdir, readdir, rm, stat } from 'node:fs/promises';\nimport { Listr } from 'listr2';\nimport { styleText } from 'node:util';\nimport { execSync, spawn } from 'node:child_process';\nimport { replaceVariables } from './replace-variables';\nimport kebabCase from 'lodash.kebabcase';\n\nconst argv = yargsParser(process.argv.slice(2));\nconst templateDir = path.join(import.meta.dirname, '..', 'templates');\n\nconst projectName = kebabCase(argv['project'] || 'my-aomex-project');\nconst targetDir = path.resolve(projectName);\nif (existsSync(targetDir)) {\n console.error(styleText('red', `目录 \"${targetDir}\" 已存在!`));\n process.exit(1);\n}\nconst nodeVersion = process.versions.node;\n\nlet packageManager = 'pnpm';\nfor (const item of <const>['pnpm', 'npm', 'yarn']) {\n if (argv[item]) {\n packageManager = item;\n break;\n }\n}\n\nconst runShell = async (command: string) => {\n await new Promise((resolve, reject) => {\n const stream = spawn(command, {\n cwd: process.cwd(),\n env: process.env,\n shell: true,\n });\n stream.on('close', resolve);\n stream.on('error', reject);\n });\n};\nconst sleep = () => new Promise((resolve) => setTimeout(resolve, 500));\n\nconst spinner = new Listr([]);\n\nspinner.add({\n title: '创建目录',\n task: async () => {\n if (existsSync(targetDir)) {\n await rm(targetDir, { recursive: true, force: true });\n }\n await mkdir(targetDir, { recursive: true });\n process.chdir(path.resolve(projectName));\n },\n});\n\nspinner.add({\n title: '复制模板文件',\n task: async () => {\n const variables = {\n projectName,\n packageManager,\n nodeVersion,\n };\n await cp(templateDir, targetDir, { recursive: true });\n const files = await readdir(targetDir, { recursive: true });\n for (const file of files) {\n const isFile = (await stat(path.join(targetDir, file))).isFile();\n if (!isFile) continue;\n await replaceVariables(file, variables);\n }\n await sleep();\n },\n});\n\nspinner.add({\n title: 'git初始化',\n task: async () => {\n await runShell('git init');\n await sleep();\n },\n});\n\nspinner.add({\n title: '增加volta配置',\n skip: async () => {\n return !/\\d\\.\\d/.test(execSync('volta -v', { encoding: 'utf8' }));\n },\n task: async () => {\n await runShell(`volta pin node@${nodeVersion}`);\n if (packageManager !== 'npm') {\n await runShell(`volta pin ${packageManager}`);\n }\n },\n});\n\nspinner.add({\n title: '安装插件',\n task: async (_, task) => {\n const packages: { label: string; pkgs: string[]; dev?: boolean }[] = [\n {\n label: 'dependencies',\n pkgs: [\n '@aomex/core',\n '@aomex/web',\n '@aomex/cors',\n '@aomex/etag',\n '@aomex/compress',\n '@aomex/http-logger',\n '@aomex/response-time',\n '@aomex/console',\n '@aomex/cron',\n '@aomex/helmet',\n '@aomex/openapi',\n '@aomex/swagger-ui',\n '@aomex/async-trace',\n '@prisma/client',\n '@aomex/cache',\n '@aomex/cache-redis-adapter',\n ],\n },\n {\n label: 'dev dependencies',\n pkgs: [\n 'prisma',\n 'typescript',\n 'tsx',\n 'tsc-alias',\n '@types/node',\n 'husky',\n 'prettier',\n '@commitlint/cli',\n '@commitlint/config-conventional',\n 'eslint',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'eslint-plugin-check-file',\n ],\n dev: true,\n },\n ];\n const action = packageManager === 'npm' ? 'install' : 'add';\n const devSuffix = packageManager === 'npm' ? '--save-dev' : '-D';\n\n for (let i = 0; i < packages.length; ++i) {\n const { pkgs, dev, label } = packages[i]!;\n task.title = '安装插件 ' + styleText('gray', label);\n await runShell(\n `${packageManager} ${action} ${pkgs.join(' ')} ${dev ? devSuffix : ''}`,\n );\n }\n task.title = '安装插件';\n },\n});\n\nspinner.add({\n title: '生成prisma客户端',\n task: async () => {\n await runShell('npx prisma generate');\n await sleep();\n },\n});\n\nawait spinner.run();\n\nconsole.log(\n '\\n项目创建成功:' +\n styleText(['blue', 'underline'], process.cwd()) +\n '\\n' +\n '启动项目可执行如下指令:' +\n '\\n\\n' +\n styleText('green', `cd ${projectName} && ${packageManager} start`) +\n '\\n',\n);\n","import { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\n\nexport const replaceVariables = async (\n filename: string,\n variables: Record<string, string>,\n) => {\n const packageJSONFile = path.resolve(filename);\n let packageContent = await readFile(packageJSONFile, 'utf8');\n Object.entries(variables).forEach(([key, value]) => {\n packageContent = packageContent.replaceAll(`{{${key}}}`, value);\n });\n await writeFile(packageJSONFile, packageContent);\n};\n"],"mappings":"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","names":["path","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/replace-variables.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport path from 'node:path/posix';\nimport yargsParser from 'yargs-parser';\nimport { existsSync } from 'node:fs';\nimport { cp, mkdir, readdir, rm, stat } from 'node:fs/promises';\nimport { Listr } from 'listr2';\nimport { styleText } from 'node:util';\nimport { execSync, spawn } from 'node:child_process';\nimport { replaceVariables } from './replace-variables';\nimport kebabCase from 'lodash.kebabcase';\n\nconst argv = yargsParser(process.argv.slice(2));\nconst templateDir = path.join(import.meta.dirname, '..', 'templates');\n\nconst projectName = kebabCase(argv['project'] || 'my-aomex-project');\nconst targetDir = path.resolve(projectName);\nif (existsSync(targetDir)) {\n console.error(styleText('red', `目录 \"${targetDir}\" 已存在!`));\n process.exit(1);\n}\nconst nodeVersion = process.versions.node;\n\nlet packageManager = 'pnpm';\nfor (const item of <const>['pnpm', 'npm', 'yarn']) {\n if (argv[item]) {\n packageManager = item;\n break;\n }\n}\n\nconst runShell = async (command: string) => {\n await new Promise((resolve, reject) => {\n const stream = spawn(command, {\n cwd: process.cwd(),\n env: process.env,\n shell: true,\n });\n stream.on('close', resolve);\n stream.on('error', reject);\n });\n};\nconst sleep = () => new Promise((resolve) => setTimeout(resolve, 500));\n\nconst spinner = new Listr([]);\n\nspinner.add({\n title: '创建目录',\n task: async () => {\n if (existsSync(targetDir)) {\n await rm(targetDir, { recursive: true, force: true });\n }\n await mkdir(targetDir, { recursive: true });\n process.chdir(path.resolve(projectName));\n },\n});\n\nspinner.add({\n title: '复制模板文件',\n task: async () => {\n const variables = {\n projectName,\n packageManager,\n nodeVersion,\n };\n await cp(templateDir, targetDir, { recursive: true });\n const files = await readdir(targetDir, { recursive: true });\n for (const file of files) {\n const isFile = (await stat(path.join(targetDir, file))).isFile();\n if (!isFile) continue;\n await replaceVariables(file, variables);\n }\n await sleep();\n },\n});\n\nspinner.add({\n title: 'git初始化',\n task: async () => {\n await runShell('git init');\n await sleep();\n },\n});\n\nspinner.add({\n title: '增加volta配置',\n skip: async () => {\n return !/\\d\\.\\d/.test(execSync('volta -v', { encoding: 'utf8' }));\n },\n task: async () => {\n await runShell(`volta pin node@${nodeVersion}`);\n if (packageManager !== 'npm') {\n await runShell(`volta pin ${packageManager}`);\n }\n },\n});\n\nspinner.add({\n title: '安装插件',\n task: async (_, task) => {\n const packages: { label: string; pkgs: string[]; dev?: boolean }[] = [\n {\n label: 'dependencies',\n pkgs: [\n '@aomex/core',\n '@aomex/web',\n '@aomex/cors',\n '@aomex/etag',\n '@aomex/compress',\n '@aomex/http-logger',\n '@aomex/response-time',\n '@aomex/console',\n '@aomex/cron',\n '@aomex/helmet',\n '@aomex/openapi',\n '@aomex/swagger-ui',\n '@aomex/async-trace',\n '@prisma/client',\n '@aomex/cache',\n '@aomex/cache-redis-adapter',\n 'ioredis',\n ],\n },\n {\n label: 'dev dependencies',\n pkgs: [\n 'prisma',\n 'typescript',\n 'tsx',\n 'tsc-alias',\n '@types/node',\n 'husky',\n 'prettier',\n '@commitlint/cli',\n '@commitlint/config-conventional',\n 'eslint',\n '@typescript-eslint/eslint-plugin',\n '@typescript-eslint/parser',\n 'eslint-plugin-check-file',\n ],\n dev: true,\n },\n ];\n const action = packageManager === 'npm' ? 'install' : 'add';\n const devSuffix = packageManager === 'npm' ? '--save-dev' : '-D';\n\n for (let i = 0; i < packages.length; ++i) {\n const { pkgs, dev, label } = packages[i]!;\n task.title = '安装插件 ' + styleText('gray', label);\n await runShell(\n `${packageManager} ${action} ${pkgs.join(' ')} ${dev ? devSuffix : ''}`,\n );\n }\n task.title = '安装插件';\n },\n});\n\nspinner.add({\n title: '生成prisma客户端',\n task: async () => {\n await runShell('npx prisma generate');\n await sleep();\n },\n});\n\nawait spinner.run();\n\nconsole.log(\n '\\n项目创建成功:' +\n styleText(['blue', 'underline'], process.cwd()) +\n '\\n' +\n '启动项目可执行如下指令:' +\n '\\n\\n' +\n styleText('green', `cd ${projectName} && ${packageManager} start`) +\n '\\n',\n);\n","import { readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\n\nexport const replaceVariables = async (\n filename: string,\n variables: Record<string, string>,\n) => {\n const packageJSONFile = path.resolve(filename);\n let packageContent = await readFile(packageJSONFile, 'utf8');\n Object.entries(variables).forEach(([key, value]) => {\n packageContent = packageContent.replaceAll(`{{${key}}}`, value);\n });\n await writeFile(packageJSONFile, packageContent);\n};\n"],"mappings":"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","names":["path","path"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-aomex",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "repository": "git@github.com:aomex/create-aomex.git",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,24 +35,26 @@
35
35
  "yargs-parser": "^21.1.1"
36
36
  },
37
37
  "devDependencies": {
38
- "@aomex/async-trace": "^3.0.0",
39
- "@aomex/cache": "^3.0.0",
40
- "@aomex/compress": "^3.0.0",
41
- "@aomex/console": "^3.0.0",
42
- "@aomex/core": "^3.0.0",
43
- "@aomex/cors": "^3.0.0",
44
- "@aomex/cron": "^3.0.0",
45
- "@aomex/etag": "^3.0.0",
46
- "@aomex/helmet": "^3.0.0",
47
- "@aomex/http-logger": "^3.0.0",
48
- "@aomex/openapi": "^3.0.0",
49
- "@aomex/response-time": "^3.0.0",
50
- "@aomex/swagger-ui": "^3.0.0",
51
- "@aomex/web": "^3.0.0",
38
+ "@aomex/async-trace": "^3.1.1",
39
+ "@aomex/cache": "^3.1.1",
40
+ "@aomex/cache-redis-adapter": "^3.1.0",
41
+ "@aomex/compress": "^3.1.1",
42
+ "@aomex/console": "^3.1.1",
43
+ "@aomex/core": "^3.1.1",
44
+ "@aomex/cors": "^3.1.1",
45
+ "@aomex/cron": "^3.1.1",
46
+ "@aomex/etag": "^3.1.1",
47
+ "@aomex/helmet": "^3.1.1",
48
+ "@aomex/http-logger": "^3.1.1",
49
+ "@aomex/openapi": "^3.1.1",
50
+ "@aomex/response-time": "^3.1.1",
51
+ "@aomex/swagger-ui": "^3.1.1",
52
+ "@aomex/web": "^3.1.1",
52
53
  "@prisma/client": "^5.17.0",
53
54
  "@types/lodash.kebabcase": "^4.1.9",
54
55
  "@types/node": "^20.14.12",
55
56
  "@types/yargs-parser": "^21.0.3",
57
+ "ioredis": "^5.4.1",
56
58
  "prisma": "^5.17.0",
57
59
  "release-it": "^17.6.0",
58
60
  "tsup": "^8.2.3",
@@ -1,6 +1,11 @@
1
1
  # {{projectName}}
2
2
 
3
- 使用 aomex 服务端框架,文档 [https://aomex.js.org](aomex.js.org)
3
+ 使用 aomex 服务端框架,开发前请认真阅读文档 [https://aomex.js.org](aomex.js.org)
4
+
5
+ ## 初始化
6
+
7
+ - 安装 docker 或者 orbstack
8
+ - 执行 {{packageManager}} install
4
9
 
5
10
  ## 启动服务
6
11
 
@@ -8,8 +13,14 @@
8
13
  {{packageManager}} start
9
14
  ```
10
15
 
11
- ## 编译成 js 文件
16
+ ## 在集成环境服务器下部署
17
+
18
+ ```bash
19
+ {{packageManager}} deploy:integration
20
+ ```
21
+
22
+ ## 在生产环境服务器下部署
12
23
 
13
24
  ```bash
14
- {{packageManager}} build
25
+ {{packageManager}} deploy:production
15
26
  ```
@@ -1,13 +1,13 @@
1
1
  services:
2
2
  migration:
3
- image: {{projectName}}:latest
3
+ image: {{projectName}}:integration
4
4
  command: npx prisma migrate deploy
5
5
  api:
6
- image: {{projectName}}:latest
6
+ image: {{projectName}}:integration
7
7
  restart: always
8
8
  ports:
9
9
  - 3000:3000
10
10
  cron:
11
- image: {{projectName}}:latest
12
- container_name: {{projectName}}-cron
11
+ image: {{projectName}}:integration
12
+ container_name: {{projectName}}-cron-integration
13
13
  command: npx aomex cron:start
@@ -0,0 +1,13 @@
1
+ services:
2
+ migration:
3
+ image: {{projectName}}:production
4
+ command: npx prisma migrate deploy
5
+ api:
6
+ image: {{projectName}}:production
7
+ restart: always
8
+ ports:
9
+ - 3000:3000
10
+ cron:
11
+ image: {{projectName}}:production
12
+ container_name: {{projectName}}-cron-production
13
+ command: npx aomex cron:start
@@ -1,13 +1,18 @@
1
1
  services:
2
- migration:
3
- image: {{projectName}}:latest
4
- command: npx prisma migrate deploy
5
- api:
6
- image: {{projectName}}:latest
7
- restart: always
2
+ db:
3
+ image: mysql:8.4
4
+ environment:
5
+ # 修改后需要同步修改.env里的参数
6
+ MYSQL_DATABASE: aomex_db
7
+ MYSQL_ROOT_PASSWORD: abcde
8
+ volumes:
9
+ - ./volumes/mysql:/var/lib/mysql
8
10
  ports:
9
- - 3000:3000
10
- cron:
11
- image: {{projectName}}:latest
12
- container_name: {{projectName}}-cron
13
- command: npx aomex cron:start
11
+ - 3306:3306
12
+ command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
13
+ redis:
14
+ image: redis:7.4
15
+ volumes:
16
+ - ./volumes/redis:/data
17
+ ports:
18
+ - 6379:6379
@@ -2,12 +2,13 @@
2
2
 
3
3
  set -ex
4
4
 
5
- sudo docker build --tag {{projectName}}:latest --file Dockerfile.integration .
5
+ sudo docker build --tag {{projectName}}:integration --file Dockerfile.integration .
6
6
 
7
- cron_container=$(sudo docker ps | { grep "{{projectName}}-cron" || :; })
8
- if [ -n "$cron_container" ];
7
+ cron_container_name={{projectName}}-cron-integration
8
+ container_exist=$(sudo docker ps | { grep $cron_container_name || :; })
9
+ if [ -n "$container_exist" ];
9
10
  then
10
- sudo docker exec it {{projectName}}-cron /bin/sh -c "npx aomex cron:stop"
11
+ sudo docker exec it $cron_container_name /bin/sh -c "npx aomex cron:stop"
11
12
  fi
12
13
 
13
- sudo docker compose --file Dockerfile.integration up -d --timeout=1
14
+ sudo docker compose --file docker-compose-integration.yml up -d --timeout=1
@@ -2,12 +2,13 @@
2
2
 
3
3
  set -ex
4
4
 
5
- sudo docker build --tag {{projectName}}:latest --file Dockerfile .
5
+ sudo docker build --tag {{projectName}}:production --file Dockerfile.production .
6
6
 
7
- cron_container=$(sudo docker ps | { grep "{{projectName}}-cron" || :; })
8
- if [ -n "$cron_container" ];
7
+ cron_container_name={{projectName}}-cron-production
8
+ container_exist=$(sudo docker ps | { grep $cron_container_name || :; })
9
+ if [ -n "$container_exist" ];
9
10
  then
10
- sudo docker exec it {{projectName}}-cron /bin/sh -c "npx aomex cron:stop"
11
+ sudo docker exec it $cron_container_name /bin/sh -c "npx aomex cron:stop"
11
12
  fi
12
13
 
13
- sudo docker compose --file Dockerfile up -d --timeout=1
14
+ sudo docker compose --file docker-compose-production.yml up -d --timeout=1
@@ -1,9 +1,9 @@
1
1
  import { execSync, spawn } from 'node:child_process';
2
2
  import process from 'node:process';
3
3
 
4
- execSync('docker compose -f docker-compose-development.yml down', { stdio: 'inherit' });
4
+ execSync('docker compose -f docker-compose.yml down', { stdio: 'inherit' });
5
5
 
6
- const docker = spawn('docker compose -f docker-compose-development.yml up', {
6
+ const docker = spawn('docker compose -f docker-compose.yml up', {
7
7
  stdio: ['inherit', 'inherit', 'pipe'],
8
8
  shell: 'zsh',
9
9
  });
@@ -1,7 +1,14 @@
1
1
  import type { Config } from './production';
2
2
  import { integration } from './integration';
3
+ import type { RedisOptions } from 'ioredis';
3
4
 
4
5
  // 本地开发环境,对应随意git分支
5
6
  export const development: Config = {
6
7
  ...integration,
8
+ redis: <RedisOptions>{
9
+ host: 'localhost',
10
+ port: 6379,
11
+ password: undefined,
12
+ db: 0,
13
+ },
7
14
  };
@@ -2,11 +2,11 @@ import { production, type Config } from './production';
2
2
  import { integration } from './integration';
3
3
  import { development } from './development';
4
4
 
5
- const configs = {
5
+ const configList = {
6
6
  production,
7
7
  integration,
8
8
  development,
9
9
  };
10
10
 
11
- export const config: Config =
12
- configs[(process.env['NODE_ENV'] || 'development') as keyof typeof configs];
11
+ export const configs: Config =
12
+ configList[(process.env['NODE_ENV'] || 'development') as keyof typeof configList];
@@ -1,6 +1,13 @@
1
+ import type { RedisOptions } from 'ioredis';
1
2
  import { production, type Config } from './production';
2
3
 
3
4
  // 线上集成环境,用于功能、交互测试。对应 develop 分支
4
5
  export const integration: Config = {
5
6
  ...production,
7
+ redis: <RedisOptions>{
8
+ host: '',
9
+ port: 6379,
10
+ password: '',
11
+ db: 0,
12
+ },
6
13
  };
@@ -1,4 +1,13 @@
1
+ import { type RedisOptions } from 'ioredis';
2
+
1
3
  // 正式环境。对应 main 分支
2
- export const production = {};
4
+ export const production = {
5
+ redis: <RedisOptions>{
6
+ host: '',
7
+ port: 6379,
8
+ password: '',
9
+ db: 0,
10
+ },
11
+ };
3
12
 
4
13
  export type Config = typeof production;
@@ -0,0 +1,8 @@
1
+ import { middleware } from '@aomex/core';
2
+
3
+ let counter = 0;
4
+
5
+ export const hello = middleware.web<{ visitCount: number }>(async (ctx, next) => {
6
+ ctx.visitCount = ++counter;
7
+ await next();
8
+ });
@@ -1,9 +1,11 @@
1
1
  import { Router } from '@aomex/web';
2
+ import { hello } from '@middleware/hello.middleware';
2
3
 
3
4
  export const router = new Router();
4
5
 
5
6
  router.get('/', {
7
+ mount: [hello],
6
8
  action: (ctx) => {
7
- ctx.send('hello world');
9
+ ctx.send(`hello world, ${ctx.visitCount}`);
8
10
  },
9
11
  });
@@ -1,4 +1,4 @@
1
- import { services } from '../services';
1
+ import { services } from '@services';
2
2
  import { body, params, Router } from '@aomex/web';
3
3
  import { rule } from '@aomex/core';
4
4
 
@@ -1,8 +1,9 @@
1
1
  import { Service } from '@aomex/core';
2
- import { Caching, CacheMemoryAdapter } from '@aomex/cache';
3
- // import { CacheRedisAdapter } from '@aomex/cache-redis-adapter';
2
+ import { Caching } from '@aomex/cache';
3
+ import { redisAdapter } from '@aomex/cache-redis-adapter';
4
+ import { configs } from '@configs';
4
5
 
5
- export const cache = new Caching(new CacheMemoryAdapter());
6
+ export const cache = new Caching(redisAdapter(configs.redis));
6
7
 
7
8
  export class CacheService extends Service {
8
9
  protected readonly hotRankingKey = 'hot-rankings';
@@ -32,6 +32,13 @@
32
32
  "noImplicitAny": true,
33
33
  "noImplicitThis": true,
34
34
  "allowSyntheticDefaultImports": true,
35
- "resolveJsonModule": true
35
+ "resolveJsonModule": true,
36
+ "paths": {
37
+ "@configs": ["./src/configs/index.ts"],
38
+ "@configs/*": ["./src/configs/*"],
39
+ "@middleware/*": ["./src/middleware/*"],
40
+ "@services": ["./src/services/index.ts"],
41
+ "@services/*": ["./src/services/*"]
42
+ }
36
43
  }
37
44
  }
@@ -1,18 +0,0 @@
1
- services:
2
- db:
3
- image: mysql:8.4
4
- environment:
5
- # 修改后需要同步修改.env里的参数
6
- MYSQL_DATABASE: aomex_db
7
- MYSQL_ROOT_PASSWORD: abcde
8
- volumes:
9
- - ./volumes/mysql:/var/lib/mysql
10
- ports:
11
- - 3306:3306
12
- command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
13
- redis:
14
- image: redis:7.4
15
- volumes:
16
- - ./volumes/redis:/data
17
- ports:
18
- - 6379:6379
File without changes