create-arui-scripts-app 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +15 -3
- package/assets/.yarn/releases/yarn-4.9.1.cjs +0 -0
- package/build/build-context.js +20 -0
- package/build/build-file-map.js +29 -2
- package/build/create-program.js +18 -0
- package/build/defaults.d.ts +4 -1
- package/build/defaults.js +8 -2
- package/build/install-dependencies.d.ts +2 -0
- package/build/install-dependencies.js +18 -5
- package/build/questions.js +31 -0
- package/build/run.js +40 -0
- package/build/templates/app-component.template.js +20 -7
- package/build/templates/app-styles.template.js +43 -12
- package/build/templates/arui-scripts-config.template.js +2 -2
- package/build/templates/client-entry.template.js +28 -18
- package/build/templates/e2e-cypress.template.d.ts +5 -0
- package/build/templates/e2e-cypress.template.js +52 -0
- package/build/templates/e2e-playwright.template.d.ts +4 -0
- package/build/templates/e2e-playwright.template.js +56 -0
- package/build/templates/lint.template.d.ts +4 -0
- package/build/templates/lint.template.js +52 -0
- package/build/templates/misc.template.d.ts +1 -1
- package/build/templates/misc.template.js +62 -5
- package/build/templates/package-json.template.js +26 -0
- package/build/templates/router.template.d.ts +5 -0
- package/build/templates/router.template.js +159 -0
- package/build/templates/server-entry.template.js +37 -41
- package/build/templates/store.template.js +1 -1
- package/build/templates/tsconfig.template.js +9 -9
- package/build/types.d.ts +7 -0
- package/build/versions.d.ts +1 -1
- package/build/versions.js +1 -1
- package/package.json +55 -55
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# create-arui-scripts-app
|
|
2
|
+
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#577](https://github.com/core-ds/arui-scripts/pull/577) [`231321b`](https://github.com/core-ds/arui-scripts/commit/231321bf2707abbbd909931cbd358880e488a2b5) Thanks [@dmitrbrvsk](https://github.com/dmitrbrvsk)! - В CLI генерации приложения добавлена возможность выбор e2e фреймворка (Cypress, Playwright) и подключение простого роутинга через React Router
|
|
8
|
+
|
|
9
|
+
## 1.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#566](https://github.com/core-ds/arui-scripts/pull/566) [`d5de571`](https://github.com/core-ds/arui-scripts/commit/d5de571bf16582ad78258d3b35acbc08d7da42a4) Thanks [@dmitrbrvsk](https://github.com/dmitrbrvsk)! - добавлена возможность подключать пакет arui-presets-lint (https://github.com/core-ds/arui-presets-lint/tree/master/packages/arui-presets-lint)
|
|
14
|
+
|
|
15
|
+
## 1.0.0
|
|
16
|
+
|
|
17
|
+
### Major Changes
|
|
18
|
+
|
|
19
|
+
- [#552](https://github.com/core-ds/arui-scripts/pull/552) [`3658e49`](https://github.com/core-ds/arui-scripts/commit/3658e49b0b752c592e738726aa8056569e28e19b) Thanks [@dmitrbrvsk](https://github.com/dmitrbrvsk)! - Добавлен пакет `create-arui-scripts-app` для генерации нового приложения через CLI. В `arui-scripts` CLI был переведен на commander.
|
package/README.md
CHANGED
|
@@ -32,10 +32,11 @@ npx create-arui-scripts-app my-app --yes
|
|
|
32
32
|
- `--ssr` / `--client-only` - SSR или только клиент
|
|
33
33
|
- `--code-loader <swc|babel|tsc>` - транспилятор
|
|
34
34
|
- `--test-runner <jest|vitest>` - тест-раннер
|
|
35
|
+
- `--e2e-framework <cypress|playwright|none>` - e2e фреймворк
|
|
35
36
|
- `--css-modules` / `--no-css-modules` - CSS-модули
|
|
36
37
|
- `--client-port` / `--server-port` - порты клиента и сервера
|
|
37
38
|
- `--docker-registry` / `--presets` - docker registry и preset
|
|
38
|
-
- `--polyfills` / `--react-compiler` / `--install` - и соответствующие `--no-*`
|
|
39
|
+
- `--polyfills` / `--react-compiler` / `--lint` / `--install` - и соответствующие `--no-*`
|
|
39
40
|
|
|
40
41
|
## Что настраивает мастер
|
|
41
42
|
|
|
@@ -43,16 +44,27 @@ npx create-arui-scripts-app my-app --yes
|
|
|
43
44
|
- режим **SSR** (клиент + сервер, клиент в `src/client/`) или **clientOnly** (статика)
|
|
44
45
|
- SSR-сервер на **Hapi** с рендерингом приложения (`renderToString`) и гидрацией на клиенте
|
|
45
46
|
- транспилятор (**swc** / babel / tsc) и тест-раннер (**Jest** / Vitest)
|
|
47
|
+
- опционально **e2e** (**Cypress** / Playwright) с конфигом и хелперами
|
|
48
|
+
- опционально **React Router**
|
|
46
49
|
- CSS-модули, полифилы (`core-js`), `experimentalReactCompiler`, docker registry, preset
|
|
50
|
+
- опционально **arui-presets-lint** (eslint, prettier, stylelint, knip, secretlint, lefthook)
|
|
47
51
|
- опциональная установка зависимостей сразу после генерации
|
|
48
52
|
|
|
53
|
+
Пример с линтерами:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npx create-arui-scripts-app my-app --yes --lint --install
|
|
57
|
+
```
|
|
58
|
+
|
|
49
59
|
## Результат
|
|
50
60
|
|
|
51
61
|
Генерируются `package.json`, `arui-scripts.config.ts`, `tsconfig.json`, клиентская точка входа,
|
|
52
62
|
пример компонента со стилями и тестом, `global-definitions.d.ts`, `.gitignore`, `README.md`,
|
|
53
63
|
`.yarnrc.yml` (с `nodeLinker: node-modules`),
|
|
54
|
-
а также в зависимости от ответов - серверная точка входа на Hapi, store на RTK,
|
|
55
|
-
`vitest.config.ts
|
|
64
|
+
а также в зависимости от ответов - серверная точка входа на Hapi, store на RTK, полифилы,
|
|
65
|
+
`vitest.config.ts`, e2e-каркас (Playwright или Cypress), роуты React Router и конфиги
|
|
66
|
+
`arui-presets-lint` (`eslint.config.mts`, `knip.ts`, `.secretlintrc.json`, `lefthook.yml`).
|
|
56
67
|
|
|
57
68
|
Дальнейшая сборка и запуск через команды `arui-scripts` в созданном проекте.
|
|
58
69
|
См. [документацию arui-scripts](../arui-scripts/README.md).
|
|
70
|
+
При подключении lint: `yarn lint` / `yarn lint:fix`.
|
|
File without changes
|
package/build/build-context.js
CHANGED
|
@@ -23,6 +23,10 @@ const VERSIONS = {
|
|
|
23
23
|
tsJest: '^29.1.0',
|
|
24
24
|
typesJest: '^29.5.0',
|
|
25
25
|
vitest: '^4.1.5',
|
|
26
|
+
playwrightTest: '^1.57.0',
|
|
27
|
+
cypress: '^15.19.0',
|
|
28
|
+
reactRouterDom: '^7.6.0',
|
|
29
|
+
aruiPresetsLint: '^11.0.0',
|
|
26
30
|
};
|
|
27
31
|
function buildContext(answers, aruiScriptsVersion) {
|
|
28
32
|
const dependencies = {
|
|
@@ -49,6 +53,10 @@ function buildContext(answers, aruiScriptsVersion) {
|
|
|
49
53
|
dependencies['@reduxjs/toolkit'] = VERSIONS.reduxToolkit;
|
|
50
54
|
dependencies['react-redux'] = VERSIONS.reactRedux;
|
|
51
55
|
}
|
|
56
|
+
if (answers.useRouter) {
|
|
57
|
+
dependencies['react-router'] = VERSIONS.reactRouterDom;
|
|
58
|
+
dependencies['react-router-dom'] = VERSIONS.reactRouterDom;
|
|
59
|
+
}
|
|
52
60
|
if (answers.polyfills) {
|
|
53
61
|
dependencies['core-js'] = VERSIONS.coreJs;
|
|
54
62
|
}
|
|
@@ -63,12 +71,23 @@ function buildContext(answers, aruiScriptsVersion) {
|
|
|
63
71
|
else {
|
|
64
72
|
devDependencies.vitest = VERSIONS.vitest;
|
|
65
73
|
}
|
|
74
|
+
if (answers.e2eFramework === 'playwright') {
|
|
75
|
+
devDependencies['@playwright/test'] = VERSIONS.playwrightTest;
|
|
76
|
+
}
|
|
77
|
+
else if (answers.e2eFramework === 'cypress') {
|
|
78
|
+
devDependencies.cypress = VERSIONS.cypress;
|
|
79
|
+
}
|
|
80
|
+
if (answers.useLint) {
|
|
81
|
+
devDependencies['arui-presets-lint'] = VERSIONS.aruiPresetsLint;
|
|
82
|
+
}
|
|
66
83
|
return {
|
|
67
84
|
name: answers.name,
|
|
68
85
|
useRtk: answers.useRtk,
|
|
69
86
|
clientOnly: answers.clientOnly,
|
|
70
87
|
codeLoader: answers.codeLoader,
|
|
71
88
|
testRunner: answers.testRunner,
|
|
89
|
+
e2eFramework: answers.e2eFramework,
|
|
90
|
+
useRouter: answers.useRouter,
|
|
72
91
|
cssModules: answers.cssModules,
|
|
73
92
|
clientServerPort: answers.clientServerPort,
|
|
74
93
|
serverPort: answers.serverPort,
|
|
@@ -76,6 +95,7 @@ function buildContext(answers, aruiScriptsVersion) {
|
|
|
76
95
|
presets: answers.presets.trim(),
|
|
77
96
|
polyfills: answers.polyfills,
|
|
78
97
|
reactCompiler: answers.reactCompiler,
|
|
98
|
+
useLint: answers.useLint,
|
|
79
99
|
aruiScriptsVersion,
|
|
80
100
|
dependencies,
|
|
81
101
|
devDependencies,
|
package/build/build-file-map.js
CHANGED
|
@@ -7,8 +7,12 @@ const app_styles_template_1 = require("./templates/app-styles.template");
|
|
|
7
7
|
const app_test_template_1 = require("./templates/app-test.template");
|
|
8
8
|
const arui_scripts_config_template_1 = require("./templates/arui-scripts-config.template");
|
|
9
9
|
const client_entry_template_1 = require("./templates/client-entry.template");
|
|
10
|
+
const e2e_cypress_template_1 = require("./templates/e2e-cypress.template");
|
|
11
|
+
const e2e_playwright_template_1 = require("./templates/e2e-playwright.template");
|
|
12
|
+
const lint_template_1 = require("./templates/lint.template");
|
|
10
13
|
const misc_template_1 = require("./templates/misc.template");
|
|
11
14
|
const package_json_template_1 = require("./templates/package-json.template");
|
|
15
|
+
const router_template_1 = require("./templates/router.template");
|
|
12
16
|
const server_entry_template_1 = require("./templates/server-entry.template");
|
|
13
17
|
const store_template_1 = require("./templates/store.template");
|
|
14
18
|
const tsconfig_template_1 = require("./templates/tsconfig.template");
|
|
@@ -22,14 +26,14 @@ function buildFileMap(ctx) {
|
|
|
22
26
|
'package.json': (0, package_json_template_1.packageJsonTemplate)(ctx),
|
|
23
27
|
'arui-scripts.config.ts': (0, arui_scripts_config_template_1.aruiScriptsConfigTemplate)(ctx),
|
|
24
28
|
'tsconfig.json': (0, tsconfig_template_1.tsconfigTemplate)(ctx),
|
|
25
|
-
'.gitignore': (0, misc_template_1.gitignoreTemplate)(),
|
|
29
|
+
'.gitignore': (0, misc_template_1.gitignoreTemplate)(ctx),
|
|
26
30
|
'.yarnrc.yml': (0, misc_template_1.yarnrcTemplate)(),
|
|
27
31
|
'global-definitions.d.ts': (0, misc_template_1.globalDefinitionsTemplate)(),
|
|
28
32
|
'README.md': (0, misc_template_1.readmeTemplate)(ctx),
|
|
29
33
|
[`${client}/index.tsx`]: (0, client_entry_template_1.clientEntryTemplate)(ctx),
|
|
30
34
|
[`${client}/components/app.tsx`]: (0, app_component_template_1.appComponentTemplate)(ctx),
|
|
31
35
|
[`${client}/components/${(0, app_styles_template_1.appStylesFileName)(ctx)}`]: (0, app_styles_template_1.appStylesTemplate)(ctx),
|
|
32
|
-
[`${client}/components/__tests__/app.test.
|
|
36
|
+
[`${client}/components/__tests__/app.test.ts`]: (0, app_test_template_1.appTestTemplate)(ctx),
|
|
33
37
|
};
|
|
34
38
|
if (!ctx.clientOnly) {
|
|
35
39
|
files['src/server/index.tsx'] = (0, server_entry_template_1.serverEntryTemplate)(ctx);
|
|
@@ -45,5 +49,28 @@ function buildFileMap(ctx) {
|
|
|
45
49
|
files[`${client}/store/hooks.ts`] = (0, store_template_1.storeHooksTemplate)();
|
|
46
50
|
files[`${client}/store/counter-slice.ts`] = (0, store_template_1.counterSliceTemplate)();
|
|
47
51
|
}
|
|
52
|
+
if (ctx.useRouter) {
|
|
53
|
+
files[`${client}/routes.tsx`] = (0, router_template_1.routesTemplate)();
|
|
54
|
+
files[`${client}/components/layout.tsx`] = (0, router_template_1.layoutTemplate)(ctx);
|
|
55
|
+
files[`${client}/pages/home.tsx`] = (0, router_template_1.homePageTemplate)(ctx);
|
|
56
|
+
files[`${client}/pages/about.tsx`] = (0, router_template_1.aboutPageTemplate)(ctx);
|
|
57
|
+
}
|
|
58
|
+
if (ctx.useLint) {
|
|
59
|
+
files['eslint.config.mts'] = (0, lint_template_1.eslintConfigTemplate)();
|
|
60
|
+
files['knip.ts'] = (0, lint_template_1.knipConfigTemplate)();
|
|
61
|
+
files['.secretlintrc.json'] = (0, lint_template_1.secretlintConfigTemplate)();
|
|
62
|
+
files['lefthook.yml'] = (0, lint_template_1.lefthookConfigTemplate)();
|
|
63
|
+
}
|
|
64
|
+
if (ctx.e2eFramework === 'playwright') {
|
|
65
|
+
files['playwright.config.ts'] = (0, e2e_playwright_template_1.playwrightConfigTemplate)(ctx);
|
|
66
|
+
files['e2e/helpers/index.ts'] = (0, e2e_playwright_template_1.playwrightHelpersTemplate)();
|
|
67
|
+
files['e2e/example.spec.ts'] = (0, e2e_playwright_template_1.playwrightExampleSpecTemplate)();
|
|
68
|
+
}
|
|
69
|
+
else if (ctx.e2eFramework === 'cypress') {
|
|
70
|
+
files['cypress.config.ts'] = (0, e2e_cypress_template_1.cypressConfigTemplate)(ctx);
|
|
71
|
+
files['cypress/support/e2e.ts'] = (0, e2e_cypress_template_1.cypressSupportE2eTemplate)();
|
|
72
|
+
files['cypress/support/commands.ts'] = (0, e2e_cypress_template_1.cypressSupportCommandsTemplate)();
|
|
73
|
+
files['cypress/e2e/example.cy.ts'] = (0, e2e_cypress_template_1.cypressExampleSpecTemplate)();
|
|
74
|
+
}
|
|
48
75
|
return files;
|
|
49
76
|
}
|
package/build/create-program.js
CHANGED
|
@@ -31,6 +31,13 @@ function createProgram(onInit = defaultInitHandler) {
|
|
|
31
31
|
.addOption(new commander_1.Option('--ssr', 'Клиент + сервер').conflicts('clientOnly'))
|
|
32
32
|
.addOption(new commander_1.Option('--code-loader <loader>', 'Транспилятор').choices(['swc', 'babel', 'tsc']))
|
|
33
33
|
.addOption(new commander_1.Option('--test-runner <runner>', 'Тест-раннер').choices(['jest', 'vitest']))
|
|
34
|
+
.addOption(new commander_1.Option('--e2e-framework <framework>', 'e2e фреймворк').choices([
|
|
35
|
+
'cypress',
|
|
36
|
+
'playwright',
|
|
37
|
+
'none',
|
|
38
|
+
]))
|
|
39
|
+
.option('--router', 'Подключить React Router')
|
|
40
|
+
.option('--no-router', 'Без React Router')
|
|
34
41
|
.option('--css-modules', 'CSS-модули')
|
|
35
42
|
.option('--no-css-modules', 'Обычный css')
|
|
36
43
|
.option('--client-port <port>', 'Порт dev-сервера', (value) => Number(value))
|
|
@@ -41,6 +48,8 @@ function createProgram(onInit = defaultInitHandler) {
|
|
|
41
48
|
.option('--no-polyfills', 'Без полифилов')
|
|
42
49
|
.option('--react-compiler', 'Включить experimentalReactCompiler')
|
|
43
50
|
.option('--no-react-compiler', 'Выключить experimentalReactCompiler')
|
|
51
|
+
.option('--lint', 'Подключить arui-presets-lint')
|
|
52
|
+
.option('--no-lint', 'Без arui-presets-lint')
|
|
44
53
|
.option('--install', 'Установить зависимости после генерации')
|
|
45
54
|
.option('--no-install', 'Не устанавливать зависимости')
|
|
46
55
|
.showHelpAfterError('(используйте --help для справки)')
|
|
@@ -75,6 +84,9 @@ function mapOptsToFlags(opts) {
|
|
|
75
84
|
if (typeof opts.testRunner === 'string') {
|
|
76
85
|
flags.testRunner = opts.testRunner;
|
|
77
86
|
}
|
|
87
|
+
if (typeof opts.e2eFramework === 'string') {
|
|
88
|
+
flags.e2eFramework = opts.e2eFramework;
|
|
89
|
+
}
|
|
78
90
|
if (typeof opts.cssModules === 'boolean') {
|
|
79
91
|
flags.cssModules = opts.cssModules;
|
|
80
92
|
}
|
|
@@ -96,6 +108,12 @@ function mapOptsToFlags(opts) {
|
|
|
96
108
|
if (typeof opts.reactCompiler === 'boolean') {
|
|
97
109
|
flags.reactCompiler = opts.reactCompiler;
|
|
98
110
|
}
|
|
111
|
+
if (typeof opts.router === 'boolean') {
|
|
112
|
+
flags.useRouter = opts.router;
|
|
113
|
+
}
|
|
114
|
+
if (typeof opts.lint === 'boolean') {
|
|
115
|
+
flags.useLint = opts.lint;
|
|
116
|
+
}
|
|
99
117
|
if (typeof opts.install === 'boolean') {
|
|
100
118
|
flags.install = opts.install;
|
|
101
119
|
}
|
package/build/defaults.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CodeLoader, type InitAnswers, type TestRunner } from './types';
|
|
1
|
+
import { type CodeLoader, type E2eFramework, type InitAnswers, type TestRunner } from './types';
|
|
2
2
|
export type CliFlags = {
|
|
3
3
|
yes?: boolean;
|
|
4
4
|
force?: boolean;
|
|
@@ -7,6 +7,8 @@ export type CliFlags = {
|
|
|
7
7
|
clientOnly?: boolean;
|
|
8
8
|
codeLoader?: CodeLoader;
|
|
9
9
|
testRunner?: TestRunner;
|
|
10
|
+
e2eFramework?: E2eFramework;
|
|
11
|
+
useRouter?: boolean;
|
|
10
12
|
cssModules?: boolean;
|
|
11
13
|
clientServerPort?: number;
|
|
12
14
|
serverPort?: number;
|
|
@@ -14,6 +16,7 @@ export type CliFlags = {
|
|
|
14
16
|
presets?: string;
|
|
15
17
|
polyfills?: boolean;
|
|
16
18
|
reactCompiler?: boolean;
|
|
19
|
+
useLint?: boolean;
|
|
17
20
|
install?: boolean;
|
|
18
21
|
};
|
|
19
22
|
export declare function defaultAnswers(name: string): InitAnswers;
|
package/build/defaults.js
CHANGED
|
@@ -10,6 +10,8 @@ function defaultAnswers(name) {
|
|
|
10
10
|
clientOnly: false,
|
|
11
11
|
codeLoader: 'swc',
|
|
12
12
|
testRunner: 'jest',
|
|
13
|
+
e2eFramework: 'none',
|
|
14
|
+
useRouter: false,
|
|
13
15
|
cssModules: true,
|
|
14
16
|
clientServerPort: 8080,
|
|
15
17
|
serverPort: 3000,
|
|
@@ -17,6 +19,7 @@ function defaultAnswers(name) {
|
|
|
17
19
|
presets: '',
|
|
18
20
|
polyfills: false,
|
|
19
21
|
reactCompiler: false,
|
|
22
|
+
useLint: false,
|
|
20
23
|
install: false,
|
|
21
24
|
};
|
|
22
25
|
}
|
|
@@ -26,6 +29,8 @@ const ANSWER_FLAG_KEYS = [
|
|
|
26
29
|
'clientOnly',
|
|
27
30
|
'codeLoader',
|
|
28
31
|
'testRunner',
|
|
32
|
+
'e2eFramework',
|
|
33
|
+
'useRouter',
|
|
29
34
|
'cssModules',
|
|
30
35
|
'clientServerPort',
|
|
31
36
|
'serverPort',
|
|
@@ -33,6 +38,7 @@ const ANSWER_FLAG_KEYS = [
|
|
|
33
38
|
'presets',
|
|
34
39
|
'polyfills',
|
|
35
40
|
'reactCompiler',
|
|
41
|
+
'useLint',
|
|
36
42
|
'install',
|
|
37
43
|
];
|
|
38
44
|
function hasAnswerFlags(flags) {
|
|
@@ -42,7 +48,7 @@ function hasAnswerFlags(flags) {
|
|
|
42
48
|
function answersFromFlags(defaultName, flags) {
|
|
43
49
|
var _a, _b;
|
|
44
50
|
const base = defaultAnswers(((_a = flags.name) === null || _a === void 0 ? void 0 : _a.trim()) || defaultName);
|
|
45
|
-
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, base), (flags.useRtk === undefined ? {} : { useRtk: flags.useRtk })), (flags.clientOnly === undefined ? {} : { clientOnly: flags.clientOnly })), (flags.codeLoader === undefined ? {} : { codeLoader: flags.codeLoader })), (flags.testRunner === undefined ? {} : { testRunner: flags.testRunner })), (flags.cssModules === undefined ? {} : { cssModules: flags.cssModules })), (flags.clientServerPort === undefined
|
|
51
|
+
return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, base), (flags.useRtk === undefined ? {} : { useRtk: flags.useRtk })), (flags.clientOnly === undefined ? {} : { clientOnly: flags.clientOnly })), (flags.codeLoader === undefined ? {} : { codeLoader: flags.codeLoader })), (flags.testRunner === undefined ? {} : { testRunner: flags.testRunner })), (flags.e2eFramework === undefined ? {} : { e2eFramework: flags.e2eFramework })), (flags.useRouter === undefined ? {} : { useRouter: flags.useRouter })), (flags.cssModules === undefined ? {} : { cssModules: flags.cssModules })), (flags.clientServerPort === undefined
|
|
46
52
|
? {}
|
|
47
|
-
: { clientServerPort: flags.clientServerPort })), (flags.serverPort === undefined ? {} : { serverPort: flags.serverPort })), (flags.dockerRegistry === undefined ? {} : { dockerRegistry: flags.dockerRegistry })), (flags.presets === undefined ? {} : { presets: flags.presets })), (flags.polyfills === undefined ? {} : { polyfills: flags.polyfills })), (flags.reactCompiler === undefined ? {} : { reactCompiler: flags.reactCompiler })), (flags.install === undefined ? {} : { install: flags.install })), { name: (((_b = flags.name) === null || _b === void 0 ? void 0 : _b.trim()) || defaultName).trim() });
|
|
53
|
+
: { clientServerPort: flags.clientServerPort })), (flags.serverPort === undefined ? {} : { serverPort: flags.serverPort })), (flags.dockerRegistry === undefined ? {} : { dockerRegistry: flags.dockerRegistry })), (flags.presets === undefined ? {} : { presets: flags.presets })), (flags.polyfills === undefined ? {} : { polyfills: flags.polyfills })), (flags.reactCompiler === undefined ? {} : { reactCompiler: flags.reactCompiler })), (flags.useLint === undefined ? {} : { useLint: flags.useLint })), (flags.install === undefined ? {} : { install: flags.install })), { name: (((_b = flags.name) === null || _b === void 0 ? void 0 : _b.trim()) || defaultName).trim() });
|
|
48
54
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export type PackageManager = 'yarn' | 'npm';
|
|
2
2
|
export declare function detectPackageManager(): PackageManager;
|
|
3
3
|
export declare function installDependencies(targetDir: string, packageManager?: PackageManager): Promise<void>;
|
|
4
|
+
export declare function hasGitRepository(targetDir: string): boolean;
|
|
5
|
+
export declare function installLefthook(targetDir: string): Promise<void>;
|
|
@@ -5,17 +5,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.detectPackageManager = detectPackageManager;
|
|
7
7
|
exports.installDependencies = installDependencies;
|
|
8
|
+
exports.hasGitRepository = hasGitRepository;
|
|
9
|
+
exports.installLefthook = installLefthook;
|
|
8
10
|
const child_process_1 = require("child_process");
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
9
13
|
const shelljs_1 = __importDefault(require("shelljs"));
|
|
10
14
|
function detectPackageManager() {
|
|
11
15
|
return shelljs_1.default.which('yarn') ? 'yarn' : 'npm';
|
|
12
16
|
}
|
|
13
|
-
function
|
|
14
|
-
const args = packageManager === 'yarn' ? [] : ['install'];
|
|
17
|
+
function runCommand(command, args, cwd) {
|
|
15
18
|
return new Promise((resolve, reject) => {
|
|
16
19
|
var _a, _b;
|
|
17
|
-
const child = (0, child_process_1.spawn)(
|
|
18
|
-
cwd
|
|
20
|
+
const child = (0, child_process_1.spawn)(command, args, {
|
|
21
|
+
cwd,
|
|
19
22
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
20
23
|
// для windows
|
|
21
24
|
shell: process.platform === 'win32',
|
|
@@ -32,8 +35,18 @@ function installDependencies(targetDir, packageManager = detectPackageManager())
|
|
|
32
35
|
resolve();
|
|
33
36
|
}
|
|
34
37
|
else {
|
|
35
|
-
reject(new Error(`${
|
|
38
|
+
reject(new Error(`${command} ${args.join(' ')} завершился с кодом ${code}\n${output.trim()}`));
|
|
36
39
|
}
|
|
37
40
|
});
|
|
38
41
|
});
|
|
39
42
|
}
|
|
43
|
+
function installDependencies(targetDir, packageManager = detectPackageManager()) {
|
|
44
|
+
const args = packageManager === 'yarn' ? [] : ['install'];
|
|
45
|
+
return runCommand(packageManager, args, targetDir);
|
|
46
|
+
}
|
|
47
|
+
function hasGitRepository(targetDir) {
|
|
48
|
+
return fs_1.default.existsSync(path_1.default.join(targetDir, '.git'));
|
|
49
|
+
}
|
|
50
|
+
function installLefthook(targetDir) {
|
|
51
|
+
return runCommand('npx', ['--no-install', 'lefthook', 'install'], targetDir);
|
|
52
|
+
}
|
package/build/questions.js
CHANGED
|
@@ -57,6 +57,29 @@ function getQuestions(defaultName, prefill = {}) {
|
|
|
57
57
|
{ title: 'Vitest', value: 'vitest', description: 'Быстрее, на базе Vite' },
|
|
58
58
|
],
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
type: unlessAnswered('e2eFramework', 'select'),
|
|
62
|
+
name: 'e2eFramework',
|
|
63
|
+
message: 'e2e фреймворк',
|
|
64
|
+
initial: 2,
|
|
65
|
+
choices: [
|
|
66
|
+
{ title: 'Cypress', value: 'cypress', description: 'классический e2e фреймворк' },
|
|
67
|
+
{
|
|
68
|
+
title: 'Playwright',
|
|
69
|
+
value: 'playwright',
|
|
70
|
+
description: 'Быстрый и современный e2e фреймворк',
|
|
71
|
+
},
|
|
72
|
+
{ title: 'Без e2e', value: 'none', description: 'Не подключать e2e' },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: unlessAnswered('useRouter', 'toggle'),
|
|
77
|
+
name: 'useRouter',
|
|
78
|
+
message: 'Подключить React Router',
|
|
79
|
+
initial: false,
|
|
80
|
+
active: 'да',
|
|
81
|
+
inactive: 'нет',
|
|
82
|
+
},
|
|
60
83
|
{
|
|
61
84
|
type: unlessAnswered('cssModules', 'toggle'),
|
|
62
85
|
name: 'cssModules',
|
|
@@ -114,6 +137,14 @@ function getQuestions(defaultName, prefill = {}) {
|
|
|
114
137
|
active: 'да',
|
|
115
138
|
inactive: 'нет',
|
|
116
139
|
},
|
|
140
|
+
{
|
|
141
|
+
type: unlessAnswered('useLint', 'toggle'),
|
|
142
|
+
name: 'useLint',
|
|
143
|
+
message: 'Подключить arui-presets-lint',
|
|
144
|
+
initial: false,
|
|
145
|
+
active: 'да',
|
|
146
|
+
inactive: 'нет',
|
|
147
|
+
},
|
|
117
148
|
{
|
|
118
149
|
type: unlessAnswered('install', 'toggle'),
|
|
119
150
|
name: 'install',
|
package/build/run.js
CHANGED
|
@@ -67,10 +67,32 @@ function runInit() {
|
|
|
67
67
|
spinner.fail(chalk_1.default.red('Не удалось установить зависимости'));
|
|
68
68
|
throw error;
|
|
69
69
|
}
|
|
70
|
+
if (initAnswers.useLint) {
|
|
71
|
+
yield tryInstallLefthook(targetDir);
|
|
72
|
+
}
|
|
70
73
|
}
|
|
71
74
|
printNextSteps(targetDir, baseCwd, initAnswers, packageManager);
|
|
72
75
|
});
|
|
73
76
|
}
|
|
77
|
+
function tryInstallLefthook(targetDir) {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
if (!(0, install_dependencies_1.hasGitRepository)(targetDir)) {
|
|
80
|
+
console.log(` ${chalk_1.default.dim('lefthook: пропущено (нет .git). После git init выполните: npx --no-install lefthook install')}`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const spinner = (0, ora_1.default)({ text: 'Устанавливаю git-хуки lefthook…', color: 'cyan' }).start();
|
|
84
|
+
try {
|
|
85
|
+
yield (0, install_dependencies_1.installLefthook)(targetDir);
|
|
86
|
+
spinner.succeed(chalk_1.default.green('Git-хуки lefthook установлены'));
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
spinner.fail(chalk_1.default.yellow('Не удалось установить lefthook'));
|
|
90
|
+
if (error instanceof Error && error.message) {
|
|
91
|
+
console.log(` ${chalk_1.default.dim(error.message)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
74
96
|
function resolveAnswers(defaultName, flags) {
|
|
75
97
|
return __awaiter(this, void 0, void 0, function* () {
|
|
76
98
|
const base = (0, defaults_1.answersFromFlags)(defaultName, flags);
|
|
@@ -115,6 +137,9 @@ function mergePromptAnswers(base, answers) {
|
|
|
115
137
|
if (answers.testRunner !== undefined) {
|
|
116
138
|
merged.testRunner = answers.testRunner;
|
|
117
139
|
}
|
|
140
|
+
if (answers.e2eFramework !== undefined) {
|
|
141
|
+
merged.e2eFramework = answers.e2eFramework;
|
|
142
|
+
}
|
|
118
143
|
if (answers.cssModules !== undefined) {
|
|
119
144
|
merged.cssModules = Boolean(answers.cssModules);
|
|
120
145
|
}
|
|
@@ -136,6 +161,12 @@ function mergePromptAnswers(base, answers) {
|
|
|
136
161
|
if (answers.reactCompiler !== undefined) {
|
|
137
162
|
merged.reactCompiler = Boolean(answers.reactCompiler);
|
|
138
163
|
}
|
|
164
|
+
if (answers.useRouter !== undefined) {
|
|
165
|
+
merged.useRouter = Boolean(answers.useRouter);
|
|
166
|
+
}
|
|
167
|
+
if (answers.useLint !== undefined) {
|
|
168
|
+
merged.useLint = Boolean(answers.useLint);
|
|
169
|
+
}
|
|
139
170
|
if (answers.install !== undefined) {
|
|
140
171
|
merged.install = Boolean(answers.install);
|
|
141
172
|
}
|
|
@@ -153,6 +184,9 @@ function printSuccess(context, targetDir, fileCount) {
|
|
|
153
184
|
chalk_1.default.dim(context.clientOnly ? 'clientOnly' : 'SSR'),
|
|
154
185
|
chalk_1.default.dim(context.codeLoader),
|
|
155
186
|
chalk_1.default.dim(context.testRunner),
|
|
187
|
+
...(context.e2eFramework !== 'none' ? [chalk_1.default.dim(context.e2eFramework)] : []),
|
|
188
|
+
...(context.useRouter ? [chalk_1.default.dim('router')] : []),
|
|
189
|
+
...(context.useLint ? [chalk_1.default.dim('lint')] : []),
|
|
156
190
|
].join(chalk_1.default.dim(' · '));
|
|
157
191
|
console.log();
|
|
158
192
|
console.log(` ${chalk_1.default.green('✔')} ${chalk_1.default.bold('Готово!')} ${chalk_1.default.dim(`проект «${context.name}» создан`)}`);
|
|
@@ -181,6 +215,12 @@ function printNextSteps(targetDir, baseCwd, answers, packageManager) {
|
|
|
181
215
|
if (!answers.install) {
|
|
182
216
|
steps.push(installCommand);
|
|
183
217
|
}
|
|
218
|
+
if (answers.useLint && (!answers.install || !(0, install_dependencies_1.hasGitRepository)(targetDir))) {
|
|
219
|
+
steps.push('npx --no-install lefthook install');
|
|
220
|
+
}
|
|
221
|
+
if (answers.useLint) {
|
|
222
|
+
steps.push(packageManager === 'yarn' ? 'yarn lint' : 'npm run lint');
|
|
223
|
+
}
|
|
184
224
|
steps.push(startCommand);
|
|
185
225
|
console.log();
|
|
186
226
|
console.log(` ${chalk_1.default.bold('Дальше')}`);
|
|
@@ -1,42 +1,54 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.appComponentTemplate = appComponentTemplate;
|
|
4
|
+
function tsString(value) {
|
|
5
|
+
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
6
|
+
}
|
|
4
7
|
function appComponentTemplate(ctx) {
|
|
8
|
+
if (ctx.useRouter) {
|
|
9
|
+
return `import React from 'react';
|
|
10
|
+
|
|
11
|
+
import { AppRoutes } from '../routes';
|
|
12
|
+
|
|
13
|
+
export function App() {
|
|
14
|
+
return <AppRoutes />;
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
5
18
|
const styleImport = ctx.cssModules
|
|
6
19
|
? "import styles from './app.module.css';"
|
|
7
20
|
: "import './app.css';";
|
|
8
21
|
const rootClass = ctx.cssModules ? '{styles.root}' : "'app'";
|
|
9
22
|
const titleClass = ctx.cssModules ? '{styles.title}' : "'app__title'";
|
|
23
|
+
const appNameLiteral = tsString(ctx.name);
|
|
10
24
|
const coreImports = `import { Button } from '@alfalab/core-components/button';
|
|
11
25
|
import { Gap } from '@alfalab/core-components/gap';
|
|
12
26
|
import { Typography } from '@alfalab/core-components/typography';`;
|
|
13
27
|
const view = (count) => ` <div className=${rootClass}>
|
|
14
28
|
<Typography.Title view='medium' tag='h1' className=${titleClass}>
|
|
15
|
-
{
|
|
29
|
+
{appName}
|
|
16
30
|
</Typography.Title>
|
|
17
|
-
|
|
18
31
|
<Gap size={16} />
|
|
19
|
-
|
|
20
32
|
<Typography.Text view='primary-medium'>Счетчик: {${count}}</Typography.Text>
|
|
21
|
-
|
|
22
33
|
<Gap size={16} />`;
|
|
23
34
|
if (ctx.useRtk) {
|
|
24
35
|
return `import React from 'react';
|
|
25
36
|
|
|
26
37
|
${coreImports}
|
|
27
38
|
|
|
28
|
-
import { useAppDispatch, useAppSelector } from '../store/hooks';
|
|
29
39
|
import { decrement, increment } from '../store/counter-slice';
|
|
40
|
+
import { useAppDispatch, useAppSelector } from '../store/hooks';
|
|
30
41
|
|
|
31
42
|
${styleImport}
|
|
32
43
|
|
|
44
|
+
const appName = ${appNameLiteral};
|
|
45
|
+
|
|
33
46
|
export function App() {
|
|
34
47
|
const count = useAppSelector((state) => state.counter.value);
|
|
35
48
|
const dispatch = useAppDispatch();
|
|
36
49
|
|
|
37
50
|
return (
|
|
38
51
|
${view('count')}
|
|
39
|
-
|
|
40
52
|
<Button view='accent' size={48} onClick={() => dispatch(increment())}>
|
|
41
53
|
+1
|
|
42
54
|
</Button>{' '}
|
|
@@ -54,12 +66,13 @@ ${coreImports}
|
|
|
54
66
|
|
|
55
67
|
${styleImport}
|
|
56
68
|
|
|
69
|
+
const appName = ${appNameLiteral};
|
|
70
|
+
|
|
57
71
|
export function App() {
|
|
58
72
|
const [count, setCount] = useState(0);
|
|
59
73
|
|
|
60
74
|
return (
|
|
61
75
|
${view('count')}
|
|
62
|
-
|
|
63
76
|
<Button view='accent' size={48} onClick={() => setCount((prev) => prev + 1)}>
|
|
64
77
|
+1
|
|
65
78
|
</Button>{' '}
|
|
@@ -2,30 +2,61 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.appStylesFileName = appStylesFileName;
|
|
4
4
|
exports.appStylesTemplate = appStylesTemplate;
|
|
5
|
+
const CORE_COMPONENTS_VARS_IMPORT = "@import '@alfalab/core-components/vars';";
|
|
5
6
|
function appStylesFileName(ctx) {
|
|
6
7
|
return ctx.cssModules ? 'app.module.css' : 'app.css';
|
|
7
8
|
}
|
|
8
9
|
function appStylesTemplate(ctx) {
|
|
9
10
|
if (ctx.cssModules) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const nav = ctx.useRouter
|
|
12
|
+
? `
|
|
13
|
+
.nav {
|
|
14
|
+
display: flex;
|
|
15
|
+
align-items: center;
|
|
16
|
+
padding: var(--gap-16);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.navLink {
|
|
20
|
+
color: var(--color-light-text-primary);
|
|
21
|
+
text-decoration: none;
|
|
22
|
+
}
|
|
23
|
+
`
|
|
24
|
+
: '';
|
|
25
|
+
return `${CORE_COMPONENTS_VARS_IMPORT}
|
|
26
|
+
|
|
27
|
+
.root {
|
|
28
|
+
padding: var(--gap-16);
|
|
13
29
|
}
|
|
14
30
|
|
|
15
31
|
.title {
|
|
16
|
-
margin: 0 0
|
|
17
|
-
|
|
32
|
+
margin: var(--gap-0) var(--gap-0) var(--gap-12);
|
|
33
|
+
@mixin headline_small;
|
|
18
34
|
}
|
|
19
|
-
`;
|
|
35
|
+
${nav}`;
|
|
20
36
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
const nav = ctx.useRouter
|
|
38
|
+
? `
|
|
39
|
+
.app__nav {
|
|
40
|
+
display: flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
padding: var(--gap-16);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.app__nav-link {
|
|
46
|
+
color: var(--color-light-text-primary);
|
|
47
|
+
text-decoration: none;
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
: '';
|
|
51
|
+
return `${CORE_COMPONENTS_VARS_IMPORT}
|
|
52
|
+
|
|
53
|
+
.app {
|
|
54
|
+
padding: var(--gap-16);
|
|
24
55
|
}
|
|
25
56
|
|
|
26
57
|
.app__title {
|
|
27
|
-
margin: 0 0
|
|
28
|
-
|
|
58
|
+
margin: var(--gap-0) var(--gap-0) var(--gap-12);
|
|
59
|
+
@mixin headline_small;
|
|
29
60
|
}
|
|
30
|
-
`;
|
|
61
|
+
${nav}`;
|
|
31
62
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.aruiScriptsConfigTemplate = aruiScriptsConfigTemplate;
|
|
4
|
-
// Безопасная вставка строки в конфиг
|
|
4
|
+
// Безопасная вставка строки в конфиг (одинарные кавычки как у prettier)
|
|
5
5
|
function tsString(value) {
|
|
6
|
-
return
|
|
6
|
+
return `'${value.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
7
7
|
}
|
|
8
8
|
function aruiScriptsConfigTemplate(ctx) {
|
|
9
9
|
const lines = [];
|