@qlover/create-app 0.7.5 → 0.7.7

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.
Files changed (166) hide show
  1. package/CHANGELOG.md +257 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/next-app/.env.template +22 -0
  5. package/dist/templates/next-app/.prettierignore +58 -0
  6. package/dist/templates/next-app/README.md +36 -0
  7. package/dist/templates/next-app/build/generateLocales.ts +25 -0
  8. package/dist/templates/next-app/config/IOCIdentifier.ts +45 -0
  9. package/dist/templates/next-app/config/Identifier/common.error.ts +34 -0
  10. package/dist/templates/next-app/config/Identifier/common.ts +62 -0
  11. package/dist/templates/next-app/config/Identifier/index.ts +10 -0
  12. package/dist/templates/next-app/config/Identifier/page.about.ts +181 -0
  13. package/dist/templates/next-app/config/Identifier/page.executor.ts +272 -0
  14. package/dist/templates/next-app/config/Identifier/page.home.ts +63 -0
  15. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +39 -0
  16. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +72 -0
  17. package/dist/templates/next-app/config/Identifier/page.login.ts +165 -0
  18. package/dist/templates/next-app/config/Identifier/page.register.ts +147 -0
  19. package/dist/templates/next-app/config/Identifier/page.request.ts +182 -0
  20. package/dist/templates/next-app/config/common.ts +34 -0
  21. package/dist/templates/next-app/config/i18n/PageI18nInterface.ts +51 -0
  22. package/dist/templates/next-app/config/i18n/i18nConfig.ts +12 -0
  23. package/dist/templates/next-app/config/i18n/index.ts +3 -0
  24. package/dist/templates/next-app/config/i18n/loginI18n.ts +42 -0
  25. package/dist/templates/next-app/config/theme.ts +23 -0
  26. package/dist/templates/next-app/docs/env.md +94 -0
  27. package/dist/templates/next-app/eslint.config.mjs +181 -0
  28. package/dist/templates/next-app/next.config.ts +21 -0
  29. package/dist/templates/next-app/package.json +58 -0
  30. package/dist/templates/next-app/plugins/eslint-plugin-testid.mjs +94 -0
  31. package/dist/templates/next-app/plugins/generateLocalesPlugin.ts +33 -0
  32. package/dist/templates/next-app/postcss.config.mjs +5 -0
  33. package/dist/templates/next-app/public/file.svg +1 -0
  34. package/dist/templates/next-app/public/globe.svg +1 -0
  35. package/dist/templates/next-app/public/locales/en/common.json +183 -0
  36. package/dist/templates/next-app/public/locales/zh/common.json +183 -0
  37. package/dist/templates/next-app/public/next.svg +1 -0
  38. package/dist/templates/next-app/public/vercel.svg +1 -0
  39. package/dist/templates/next-app/public/window.svg +1 -0
  40. package/dist/templates/next-app/src/app/[locale]/favicon.ico +0 -0
  41. package/dist/templates/next-app/src/app/[locale]/layout.tsx +44 -0
  42. package/dist/templates/next-app/src/app/[locale]/login/FeatureItem.tsx +13 -0
  43. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +115 -0
  44. package/dist/templates/next-app/src/app/[locale]/login/page.tsx +73 -0
  45. package/dist/templates/next-app/src/app/[locale]/not-found.tsx +24 -0
  46. package/dist/templates/next-app/src/app/[locale]/page.tsx +106 -0
  47. package/dist/templates/next-app/src/base/cases/AppConfig.ts +15 -0
  48. package/dist/templates/next-app/src/base/cases/InversifyContainer.ts +33 -0
  49. package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +25 -0
  50. package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +11 -0
  51. package/dist/templates/next-app/src/base/services/I18nService.ts +115 -0
  52. package/dist/templates/next-app/src/base/services/UserService.ts +23 -0
  53. package/dist/templates/next-app/src/core/IOC.ts +58 -0
  54. package/dist/templates/next-app/src/core/IocRegisterImpl.ts +100 -0
  55. package/dist/templates/next-app/src/core/bootstraps/BootstrapClient.ts +98 -0
  56. package/dist/templates/next-app/src/core/bootstraps/BootstrapsRegistry.ts +47 -0
  57. package/dist/templates/next-app/src/core/bootstraps/IocIdentifierTest.ts +26 -0
  58. package/dist/templates/next-app/src/core/bootstraps/PrintBootstrap.ts +18 -0
  59. package/dist/templates/next-app/src/core/globals.ts +21 -0
  60. package/dist/templates/next-app/src/i18n/request.ts +22 -0
  61. package/dist/templates/next-app/src/i18n/routing.ts +30 -0
  62. package/dist/templates/next-app/src/middleware.ts +22 -0
  63. package/dist/templates/next-app/src/server/getServerI18n.ts +26 -0
  64. package/dist/templates/next-app/src/styles/css/antd-themes/_default.css +239 -0
  65. package/dist/templates/next-app/src/styles/css/antd-themes/dark.css +178 -0
  66. package/dist/templates/next-app/src/styles/css/antd-themes/index.css +3 -0
  67. package/dist/templates/next-app/src/styles/css/antd-themes/no-context.css +34 -0
  68. package/dist/templates/next-app/src/styles/css/antd-themes/pink.css +204 -0
  69. package/dist/templates/next-app/src/styles/css/index.css +6 -0
  70. package/dist/templates/next-app/src/styles/css/page.css +19 -0
  71. package/dist/templates/next-app/src/styles/css/tailwind.css +5 -0
  72. package/dist/templates/next-app/src/styles/css/themes/_default.css +29 -0
  73. package/dist/templates/next-app/src/styles/css/themes/dark.css +29 -0
  74. package/dist/templates/next-app/src/styles/css/themes/index.css +3 -0
  75. package/dist/templates/next-app/src/styles/css/themes/pink.css +29 -0
  76. package/dist/templates/next-app/src/styles/css/zIndex.css +9 -0
  77. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +42 -0
  78. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +25 -0
  79. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +45 -0
  80. package/dist/templates/next-app/src/uikit/components/LanguageSwitcher.tsx +52 -0
  81. package/dist/templates/next-app/src/uikit/components/LocaleLink.tsx +51 -0
  82. package/dist/templates/next-app/src/uikit/components/NextIntlProvider.tsx +21 -0
  83. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +86 -0
  84. package/dist/templates/next-app/src/uikit/context/IOCContext.ts +6 -0
  85. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +28 -0
  86. package/dist/templates/next-app/src/uikit/hook/useIOC.ts +37 -0
  87. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +11 -0
  88. package/dist/templates/next-app/src/uikit/hook/useStore.ts +15 -0
  89. package/dist/templates/next-app/tailwind.config.ts +8 -0
  90. package/dist/templates/next-app/tsconfig.json +36 -0
  91. package/dist/templates/react-app/.env.template +0 -2
  92. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +1 -1
  93. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +6 -31
  94. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +1 -1
  95. package/dist/templates/react-app/config/IOCIdentifier.ts +77 -5
  96. package/dist/templates/react-app/config/app.router.ts +2 -2
  97. package/dist/templates/react-app/package.json +4 -7
  98. package/dist/templates/react-app/public/locales/en/common.json +1 -1
  99. package/dist/templates/react-app/public/locales/zh/common.json +1 -1
  100. package/dist/templates/react-app/src/App.tsx +9 -4
  101. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +1 -1
  102. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +4 -0
  103. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +16 -13
  104. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +4 -3
  105. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +2 -2
  106. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +39 -0
  107. package/dist/templates/react-app/src/base/cases/RequestState.ts +20 -0
  108. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +2 -2
  109. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +8 -2
  110. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +7 -0
  111. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +24 -0
  112. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +10 -0
  113. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +20 -0
  114. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +20 -0
  115. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +23 -0
  116. package/dist/templates/react-app/src/base/port/RequestStatusInterface.ts +5 -0
  117. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +27 -0
  118. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +12 -0
  119. package/dist/templates/react-app/src/base/services/I18nService.ts +10 -6
  120. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +23 -5
  121. package/dist/templates/react-app/src/base/services/RouteService.ts +25 -54
  122. package/dist/templates/react-app/src/base/services/UserService.ts +10 -20
  123. package/dist/templates/react-app/src/core/IOC.ts +1 -26
  124. package/dist/templates/react-app/src/core/IocRegisterImpl.ts +125 -0
  125. package/dist/templates/react-app/src/core/bootstraps/BootstrapApp.ts +4 -6
  126. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +8 -6
  127. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +26 -0
  128. package/dist/templates/react-app/src/pages/auth/Layout.tsx +2 -2
  129. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +5 -6
  130. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +8 -7
  131. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +8 -19
  132. package/dist/templates/react-app/src/pages/base/{ErrorIdentifierPage.tsx → IdentifierPage.tsx} +1 -1
  133. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +11 -15
  134. package/dist/templates/react-app/src/pages/base/Layout.tsx +1 -1
  135. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +2 -2
  136. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +34 -46
  137. package/dist/templates/react-app/src/styles/css/antd-themes/_default.css +2 -2
  138. package/dist/templates/react-app/src/styles/css/antd-themes/dark.css +2 -2
  139. package/dist/templates/react-app/src/styles/css/antd-themes/pink.css +2 -2
  140. package/dist/templates/react-app/src/styles/css/index.css +1 -0
  141. package/dist/templates/react-app/src/styles/css/page.css +8 -0
  142. package/dist/templates/react-app/src/styles/css/zIndex.css +9 -0
  143. package/dist/templates/react-app/src/uikit/{controllers/ExecutorController.ts → bridges/ExecutorPageBridge.ts} +13 -36
  144. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +41 -0
  145. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +16 -0
  146. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +136 -0
  147. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +3 -2
  148. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +2 -2
  149. package/dist/templates/react-app/src/uikit/{providers → components}/ProcessExecutorProvider.tsx +4 -4
  150. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +1 -1
  151. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +3 -5
  152. package/dist/templates/react-app/src/uikit/{providers → components}/UserAuthProvider.tsx +3 -3
  153. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +5 -2
  154. package/dist/templates/react-app/src/uikit/hooks/{userRouterService.ts → useNavigateBridge.ts} +3 -3
  155. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +5 -2
  156. package/dist/templates/react-app/tsconfig.json +1 -4
  157. package/package.json +1 -1
  158. package/dist/templates/react-app/src/base/port/InteractionHubInterface.ts +0 -94
  159. package/dist/templates/react-app/src/base/port/UIDependenciesInterface.ts +0 -37
  160. package/dist/templates/react-app/src/core/registers/IocRegisterImpl.ts +0 -25
  161. package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +0 -74
  162. package/dist/templates/react-app/src/core/registers/RegisterControllers.ts +0 -26
  163. package/dist/templates/react-app/src/core/registers/RegisterGlobals.ts +0 -30
  164. package/dist/templates/react-app/src/uikit/controllers/JSONStorageController.ts +0 -49
  165. package/dist/templates/react-app/src/uikit/controllers/RequestController.ts +0 -158
  166. /package/dist/templates/react-app/src/uikit/{providers → components}/BaseRouteProvider.tsx +0 -0
@@ -0,0 +1,94 @@
1
+ # 环境配置指南
2
+
3
+ 本项目使用 Next.js 内置的环境变量系统来管理不同环境的配置。
4
+
5
+ ## 环境文件
6
+
7
+ 项目支持以下环境配置文件:
8
+
9
+ - `.env` - 默认环境配置,适用于所有环境
10
+ - `.env.local` - 本地环境配置,会覆盖 `.env`(不应提交到版本控制)
11
+ - `.env.development` - 开发环境配置
12
+ - `.env.production` - 生产环境配置
13
+ - `.env.test` - 测试环境配置
14
+
15
+ 加载优先级(从高到低):
16
+
17
+ 1. `.env.local`
18
+ 2. `.env.[environment]`
19
+ 3. `.env`
20
+
21
+ ## 使用方法
22
+
23
+ 1. 复制 `.env.template` 创建对应环境的配置文件:
24
+
25
+ ```bash
26
+ # 开发环境
27
+ cp .env.template .env.development
28
+
29
+ # 生产环境
30
+ cp .env.template .env.production
31
+
32
+ # 测试环境
33
+ cp .env.template .env.test
34
+ ```
35
+
36
+ 2. 修改对应环境的配置文件内容
37
+
38
+ 3. 启动应用时指定环境:
39
+
40
+ ```bash
41
+ # 开发环境
42
+ APP_ENV=development npm run dev
43
+
44
+ # 生产环境
45
+ APP_ENV=production npm run build
46
+ APP_ENV=production npm run start
47
+
48
+ # 测试环境
49
+ APP_ENV=test npm run test
50
+ ```
51
+
52
+ ## 在代码中使用环境变量
53
+
54
+ 1. 服务端和客户端都可访问的变量:
55
+
56
+ ```typescript
57
+ // 在 .env 文件中定义
58
+ PUBLIC_API_URL=http://api.example.com
59
+
60
+ // 在代码中使用
61
+ console.log(process.env.PUBLIC_API_URL)
62
+ ```
63
+
64
+ 2. 仅服务端可访问的变量:
65
+
66
+ ```typescript
67
+ // 在 .env 文件中定义(以 PRIVATE_ 开头)
68
+ PRIVATE_API_KEY = secret_key;
69
+
70
+ // 在服务端代码中使用
71
+ console.log(process.env.PRIVATE_API_KEY);
72
+ ```
73
+
74
+ 3. 使用运行时配置:
75
+
76
+ ```typescript
77
+ import getConfig from 'next/config';
78
+
79
+ const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
80
+
81
+ // 服务端配置
82
+ console.log(serverRuntimeConfig.mySecret);
83
+
84
+ // 公共配置
85
+ console.log(publicRuntimeConfig.appEnv);
86
+ ```
87
+
88
+ ## 注意事项
89
+
90
+ 1. 不要将包含敏感信息的 `.env` 文件提交到版本控制
91
+ 2. 确保 `.env.local` 和 `*.env` 文件在 `.gitignore` 中
92
+ 3. 使用 `.env.template` 作为配置模板
93
+ 4. 环境变量命名推荐使用大写字母和下划线
94
+ 5. 在 CI/CD 中使用环境变量时,直接在平台中配置,不要使用 .env 文件
@@ -0,0 +1,181 @@
1
+ import { dirname } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { FlatCompat } from '@eslint/eslintrc';
4
+ import importPlugin from 'eslint-plugin-import';
5
+ import prettierPlugin from 'eslint-plugin-prettier';
6
+ import unusedImports from 'eslint-plugin-unused-imports';
7
+ import qloverEslint from '@qlover/eslint-plugin';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+
12
+ const compat = new FlatCompat({ baseDirectory: __dirname });
13
+
14
+ const eslintConfig = [
15
+ ...compat.extends(
16
+ 'next/core-web-vitals',
17
+ 'next/typescript',
18
+ 'plugin:import/recommended',
19
+ 'plugin:import/typescript',
20
+ 'plugin:prettier/recommended' // 添加 prettier 推荐配置
21
+ ),
22
+ {
23
+ ignores: [
24
+ // dependencies
25
+ 'node_modules/**',
26
+ '.pnp/**',
27
+ '.pnp.js',
28
+
29
+ // testing
30
+ 'coverage/**',
31
+ 'test-results/**',
32
+
33
+ // next.js
34
+ '.next/**',
35
+ 'out/**',
36
+ 'build/**',
37
+ 'dist/**',
38
+
39
+ // misc
40
+ '*.pem',
41
+
42
+ // debug
43
+ 'npm-debug.log*',
44
+ 'yarn-debug.log*',
45
+ 'yarn-error.log*',
46
+
47
+ // env files
48
+ '.env*',
49
+
50
+ // vercel
51
+ '.vercel/**',
52
+
53
+ // typescript
54
+ '*.tsbuildinfo',
55
+ 'next-env.d.ts',
56
+
57
+ // cache
58
+ '.cache/**',
59
+ '.eslintcache',
60
+
61
+ // IDE
62
+ '.idea/**',
63
+ '.vscode/**',
64
+
65
+ // package manager
66
+ 'package-lock.json',
67
+ 'yarn.lock',
68
+ 'pnpm-lock.yaml',
69
+
70
+ // config files
71
+ '*.config.js',
72
+ '*.config.mjs',
73
+ '*.config.cjs',
74
+ 'postcss.config.*',
75
+ 'tailwind.config.*',
76
+ 'next.config.*',
77
+ 'jest.config.*',
78
+ 'babel.config.*',
79
+
80
+ // static assets
81
+ 'public/**',
82
+ '**/*.min.js',
83
+ '**/*.bundle.js',
84
+ '**/vendor/**',
85
+
86
+ // generated files
87
+ 'coverage/**',
88
+ '.nyc_output/**',
89
+ 'storybook-static/**'
90
+ ]
91
+ },
92
+ {
93
+ plugins: {
94
+ 'unused-imports': unusedImports,
95
+ import: importPlugin,
96
+ prettier: prettierPlugin,
97
+ '@qlover-eslint': qloverEslint
98
+ },
99
+ rules: {
100
+ '@qlover-eslint/ts-class-method-return': 'error',
101
+ '@qlover-eslint/require-root-testid': 'error',
102
+ // 禁用原始的 no-unused-vars,使用 unused-imports 的规则替代
103
+ '@typescript-eslint/no-unused-vars': 'off',
104
+ // 强制使用 import type 导入类型
105
+ '@typescript-eslint/consistent-type-imports': [
106
+ 'error',
107
+ {
108
+ prefer: 'type-imports',
109
+ disallowTypeAnnotations: true,
110
+ fixStyle: 'separate-type-imports'
111
+ }
112
+ ],
113
+ // 检查未使用的导入
114
+ 'unused-imports/no-unused-imports': 'error',
115
+ // 检查未使用的变量,但允许以下划线开头的变量
116
+ 'unused-imports/no-unused-vars': [
117
+ 'error',
118
+ {
119
+ vars: 'all',
120
+ varsIgnorePattern: '^_',
121
+ args: 'after-used',
122
+ argsIgnorePattern: '^_'
123
+ }
124
+ ],
125
+ // import 语句排序规则
126
+ 'import/order': [
127
+ 'error',
128
+ {
129
+ groups: [
130
+ 'builtin', // Node.js 内置模块
131
+ 'external', // 第三方模块
132
+ 'internal', // 内部模块(使用 alias 的导入)
133
+ ['parent', 'sibling'], // 父级和同级模块
134
+ 'index', // 当前目录下的模块
135
+ 'object', // 对象导入
136
+ 'type' // 类型导入
137
+ ],
138
+ pathGroups: [
139
+ {
140
+ pattern: '@/**',
141
+ group: 'internal',
142
+ position: 'after'
143
+ }
144
+ ],
145
+ // "newlines-between": "always", // 不同组之间空一行
146
+ alphabetize: {
147
+ order: 'asc', // 按字母顺序排序
148
+ caseInsensitive: true // 排序时忽略大小写
149
+ }
150
+ }
151
+ ],
152
+ // Prettier 配置
153
+ 'prettier/prettier': [
154
+ 'error',
155
+ {
156
+ singleQuote: true,
157
+ trailingComma: 'none',
158
+ endOfLine: 'lf'
159
+ }
160
+ ],
161
+ // 默认禁用 export default
162
+ 'import/no-default-export': 'error',
163
+ }
164
+ },
165
+ // 为特定文件允许 default export
166
+ {
167
+ files: [
168
+ 'src/app/**/page.tsx',
169
+ 'src/app/**/layout.tsx',
170
+ 'src/app/**/not-found.tsx',
171
+ 'src/i18n/request.ts',
172
+ 'src/middleware.ts',
173
+ '**/*.config.*'
174
+ ],
175
+ rules: {
176
+ 'import/no-default-export': 'off'
177
+ }
178
+ }
179
+ ];
180
+
181
+ export default eslintConfig;
@@ -0,0 +1,21 @@
1
+ import createNextIntlPlugin from 'next-intl/plugin';
2
+ import { generateLocales } from './build/generateLocales';
3
+ import type { NextConfig } from 'next';
4
+
5
+ const withNextIntl = createNextIntlPlugin();
6
+
7
+ // 在构建开始时生成本地化文件
8
+ generateLocales().catch((error) => {
9
+ console.error('Failed to generate locales:', error);
10
+ });
11
+
12
+ const nextConfig: NextConfig = {
13
+ turbopack: {
14
+ root: __dirname // 明确指定根目录
15
+ },
16
+ env: {
17
+ APP_ENV: process.env.APP_ENV
18
+ }
19
+ };
20
+
21
+ export default withNextIntl(nextConfig);
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "next-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "cross-env APP_ENV=localhost next dev --turbopack",
7
+ "dev:staging": "cross-env APP_ENV=staging next dev --turbopack",
8
+ "dev:prod": "cross-env APP_ENV=production next dev --turbopack",
9
+ "build": "cross-env APP_ENV=localhost next build --turbopack",
10
+ "build:staging": "cross-env APP_ENV=staging next build --turbopack",
11
+ "build:prod": "cross-env APP_ENV=production next build --turbopack",
12
+ "start": "next start",
13
+ "lint": "eslint .",
14
+ "lint:fix": "eslint . --ext .ts,.tsx --fix",
15
+ "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
16
+ "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
17
+ "fix": "npm run lint:fix && npm run format"
18
+ },
19
+ "dependencies": {
20
+ "@ant-design/icons": "^6.0.0",
21
+ "@ant-design/nextjs-registry": "^1.1.0",
22
+ "@ant-design/v5-patch-for-react-19": "^1.0.3",
23
+ "@brain-toolkit/antd-theme-override": "^0.0.3",
24
+ "@brain-toolkit/bridge": "^0.0.1",
25
+ "@qlover/corekit-bridge": "^1.6.4",
26
+ "@qlover/fe-corekit": "^2.1.0",
27
+ "@qlover/slice-store-react": "^1.4.1",
28
+ "antd": "^5.27.1",
29
+ "clsx": "^2.1.1",
30
+ "inversify": "^7.8.1",
31
+ "lodash": "^4.17.21",
32
+ "next": "15.5.0",
33
+ "next-intl": "^4.3.5",
34
+ "next-themes": "^0.4.6",
35
+ "react": "19.1.0",
36
+ "react-dom": "19.1.0"
37
+ },
38
+ "devDependencies": {
39
+ "@brain-toolkit/ts2locales": "^0.2.3",
40
+ "@eslint/eslintrc": "^3",
41
+ "@tailwindcss/postcss": "^4",
42
+ "@types/lodash": "^4.17.20",
43
+ "@types/node": "^20",
44
+ "@types/react": "^19",
45
+ "@types/react-dom": "^19",
46
+ "@qlover/eslint-plugin": "file:../../../packages/eslint-plugin",
47
+ "cross-env": "^7.0.3",
48
+ "eslint": "^9",
49
+ "eslint-config-next": "15.5.0",
50
+ "eslint-config-prettier": "^10.1.8",
51
+ "eslint-plugin-import": "^2.32.0",
52
+ "eslint-plugin-prettier": "^5.5.4",
53
+ "eslint-plugin-unused-imports": "^4.2.0",
54
+ "prettier": "^3.6.2",
55
+ "tailwindcss": "^4",
56
+ "typescript": "^5"
57
+ }
58
+ }
@@ -0,0 +1,94 @@
1
+ export const eslintPluginTestId = {
2
+ rules: {
3
+ 'require-root-testid': {
4
+ meta: {
5
+ type: 'problem',
6
+ docs: {
7
+ description:
8
+ 'Enforce data-testid attribute on root elements of TSX components',
9
+ category: 'Best Practices',
10
+ recommended: true
11
+ },
12
+ fixable: 'code',
13
+ schema: []
14
+ },
15
+ create(context) {
16
+ return {
17
+ JSXElement(node) {
18
+ // 检查是否是组件的根元素
19
+ const isRootElement = (node) => {
20
+ const parent = node.parent;
21
+ if (!parent) return false;
22
+
23
+ // 如果父节点是 return 语句或者是箭头函数的主体,说明这是根元素
24
+ if (
25
+ parent.type === 'ReturnStatement' ||
26
+ (parent.type === 'ArrowFunctionExpression' &&
27
+ parent.body === node)
28
+ ) {
29
+ return true;
30
+ }
31
+
32
+ return false;
33
+ };
34
+
35
+ if (isRootElement(node)) {
36
+ const hasTestId = node.openingElement.attributes.some(
37
+ (attr) =>
38
+ attr.type === 'JSXAttribute' &&
39
+ attr.name.name === 'data-testid'
40
+ );
41
+
42
+ if (!hasTestId) {
43
+ context.report({
44
+ node: node.openingElement,
45
+ message:
46
+ 'Root element of a component must have a data-testid attribute',
47
+ fix(fixer) {
48
+ // 获取组件名称作为 testid 的默认值
49
+ let componentName = '';
50
+ let current = node;
51
+ while (current) {
52
+ if (
53
+ current.type === 'FunctionDeclaration' ||
54
+ current.type === 'VariableDeclarator'
55
+ ) {
56
+ componentName = current.id?.name || '';
57
+ break;
58
+ }
59
+ current = current.parent;
60
+ }
61
+
62
+ const sourceCode = context.getSourceCode();
63
+ const openingElement = node.openingElement;
64
+ const tagToken = sourceCode.getFirstToken(openingElement);
65
+ const hasAttributes = openingElement.attributes.length > 0;
66
+
67
+ if (hasAttributes) {
68
+ // 如果有其他属性,在第一个属性前添加
69
+ const firstAttribute = openingElement.attributes[0];
70
+ const indent = sourceCode
71
+ .getText()
72
+ .slice(0, firstAttribute.range[0])
73
+ .match(/\s*$/)[0];
74
+ return fixer.insertTextBefore(
75
+ firstAttribute,
76
+ `data-testid='${componentName || 'component'}'${indent}`
77
+ );
78
+ } else {
79
+ // 如果没有其他属性,在标签名后面添加
80
+ return fixer.insertTextAfter(
81
+ tagToken,
82
+ ` data-testid='${componentName || 'component'}'`
83
+ );
84
+ }
85
+ }
86
+ });
87
+ }
88
+ }
89
+ }
90
+ };
91
+ }
92
+ }
93
+ }
94
+ };
@@ -0,0 +1,33 @@
1
+ import { generateLocales } from '../build/generateLocales';
2
+ import type { NextConfig } from 'next';
3
+
4
+ export function withGenerateLocales(nextConfig: NextConfig = {}) {
5
+ return {
6
+ ...nextConfig,
7
+ onDevelopmentStart: async () => {
8
+ try {
9
+ await generateLocales();
10
+ console.log('✅ Locales generated successfully');
11
+ } catch (error) {
12
+ console.error('❌ Failed to generate locales:', error);
13
+ }
14
+ },
15
+ webpack: (config, options) => {
16
+ const { dev, isServer } = options;
17
+
18
+ // 在生产构建开始时生成本地化文件
19
+ if (!dev && isServer) {
20
+ generateLocales().catch((error) => {
21
+ console.error('❌ Failed to generate locales:', error);
22
+ });
23
+ }
24
+
25
+ // 如果原配置有 webpack 配置,则调用它
26
+ if (typeof nextConfig.webpack === 'function') {
27
+ return nextConfig.webpack(config, options);
28
+ }
29
+
30
+ return config;
31
+ }
32
+ };
33
+ }
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ plugins: ["@tailwindcss/postcss"],
3
+ };
4
+
5
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>