# dev-configs — Требования ## Общее описание Monorepo библиотека с общими конфигами для TypeScript-проектов. Публикуется как набор npm-пакетов в Gitea npm registry. ## Архитектура - **Monorepo:** npm workspaces - **Scope:** `@vigdorov/` - **Registry:** Gitea npm (https://git.vigdorov.ru/api/packages/vigdorov/npm/) - **Сборка пакетов:** tsc → dist/ - **Версионирование:** Semver, независимое, ручное (`npm version -w`) - **Публикация:** Только пакеты с поднятой версией (CI сравнивает с registry) - **CI:** Drone CI, тип `library` в ci-templates, trigger только на main ## Пакеты ### @vigdorov/prettier-config **Тип:** Статичный объект (без функции-генератора) ```json { "printWidth": 120, "tabWidth": 4, "useTabs": false, "semi": true, "singleQuote": true, "trailingComma": "all", "bracketSpacing": false, "jsxSingleQuote": false, "arrowParens": "always" } ``` ### @vigdorov/eslint-config **Тип:** Функции-генераторы **Формат:** ESLint 9+ flat config **Пресеты:** `base`, `react`, `node` **Зависимости:** - eslint - typescript-eslint (v8+) - @stylistic/eslint-plugin - eslint-plugin-unused-imports - eslint-plugin-react (для react) - eslint-plugin-react-hooks (для react) **Правила — качество кода (base):** - `eqeqeq: "error"` - `no-console: ["warn", {allow: ["warn", "error"]}]` - `no-alert: "warn"` - `no-param-reassign: ["error", {props: true}]` - `no-useless-concat: "warn"` - `no-else-return: "warn"` - `no-lonely-if: "warn"` - `no-constructor-return: "warn"` - `no-sequences: "warn"` - `prefer-promise-reject-errors: "warn"` - `require-await: "warn"` - `no-new: "warn"` - `no-multi-str: "warn"` - `no-multi-assign: "warn"` - `no-nested-ternary: "warn"` - `no-useless-computed-key: "warn"` - `no-useless-constructor: "warn"` - `no-var: "warn"` - `no-duplicate-imports: "warn"` - `no-plusplus: "warn"` - `no-bitwise: "warn"` - `prefer-const: "warn"` - `prefer-rest-params: "warn"` - `prefer-template: "warn"` - `array-callback-return: ["warn", {allowImplicit: true, checkForEach: true}]` - `default-param-last: "warn"` - `yoda: "warn"` **Правила — TypeScript (base):** - `@typescript-eslint/no-explicit-any: "error"` - `@typescript-eslint/no-empty-object-type: "error"` - `@typescript-eslint/no-unsafe-function-type: "error"` - `@typescript-eslint/no-wrapper-object-types: "error"` - `@typescript-eslint/no-use-before-define: "warn"` - `@typescript-eslint/no-shadow: "warn"` **Правила — unused imports (base):** - `unused-imports/no-unused-imports: "warn"` - `unused-imports/no-unused-vars: ["warn", {vars: "all", varsIgnorePattern: "^_", args: "after-used", argsIgnorePattern: "^_"}]` **Правила — @stylistic (base):** - `@stylistic/no-multiple-empty-lines: ["warn", {max: 1}]` - `@stylistic/lines-between-class-members: ["warn", "always"]` - `@stylistic/line-comment-position: ["warn", {position: "above"}]` - `@stylistic/multiline-comment-style: ["warn", "starred-block"]` - `@stylistic/capitalized-comments: "warn"` - `@stylistic/max-len: ["warn", {code: 120, ignoreComments: true, ignoreUrls: true, ignoreStrings: true, ignoreTemplateLiterals: true, ignoreRegExpLiterals: true}]` **Правила — React (пресет react, поверх base):** - `react/prop-types: "off"` - `react/react-in-jsx-scope: "off"` - `react/jsx-filename-extension: ["warn", {extensions: [".tsx"]}]` - `react/jsx-props-no-spreading: "warn"` - `react/jsx-key: "warn"` - `react/no-array-index-key: "warn"` - `react/destructuring-assignment: "warn"` - `react/prefer-stateless-function: "warn"` - `react/jsx-fragments: ["off", "element"]` - `react-hooks/exhaustive-deps: "warn"` **Правила — Node (пресет node):** - Базовые правила из base - React-специфичные правила отключены ### @vigdorov/typescript-config **Тип:** JSON-файлы для extends (без сборки) **base.json:** ```json { "compilerOptions": { "strict": true, "target": "ES2022", "module": "ESNext", "lib": ["ES2022"], "moduleResolution": "bundler", "resolveJsonModule": true, "forceConsistentCasingInFileNames": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUnusedLocals": false, "allowUnreachableCode": false, "allowUnusedLabels": false, "allowSyntheticDefaultImports": true, "removeComments": true, "sourceMap": true, "incremental": true, "skipLibCheck": true, "isolatedModules": true } } ``` **react.json:** ```json { "extends": "./base.json", "compilerOptions": { "lib": ["DOM", "DOM.Iterable", "ES2022"], "jsx": "react-jsx" } } ``` ### @vigdorov/vite-config **Тип:** Функции-генераторы **Пресеты:** `spa`, `library` **spa:** ```ts import {spa} from '@vigdorov/vite-config'; export default spa({ port: 5176, aliases: {'@': 'src'}, proxy: {'/api': 'http://localhost:3003'}, }); ``` **library:** ```ts import {library} from '@vigdorov/vite-config'; export default library({ entry: 'src/index.ts', name: 'my-lib', aliases: {'@': 'src'}, external: ['react', 'react-dom'], formats: ['es', 'cjs'], }); ``` **Генератор spa:** - Подключает @vitejs/plugin-react - Преобразует aliases в resolve.alias с абсолютными путями - Настраивает server.port и server.proxy - Дефолты: base: "/", outDir: "dist" **Генератор library:** - Настраивает build.lib (entry, name, formats) - rollupOptions.external — исключает peer-зависимости - fileName: index.mjs / index.cjs - Алиасы работают так же как в SPA ### @vigdorov/jest-config **Тип:** Функция-генератор ```ts import {jestConfig} from '@vigdorov/jest-config'; export default jestConfig({ environment: 'jsdom', aliases: {'@': 'src'}, }); ``` **Базовый конфиг:** - clearMocks: true - collectCoverage: true - coverageReporters: ['html', 'text', 'text-summary', 'lcov'] - coverageDirectory: 'coverage' - testMatch: ['**/__tests__/**/*.(j|t)s?(x)', '**/?(*.)+(spec|test).(j|t)s?(x)'] - testPathIgnorePatterns: ['/node_modules/', '/dist/'] - transform: @swc/jest **Параметры:** - environment: 'node' | 'jsdom' - aliases: Record — преобразуется в moduleNameMapper ### @vigdorov/playwright-config **Тип:** Функция-генератор ```ts import {playwrightConfig} from '@vigdorov/playwright-config'; export default playwrightConfig({ baseURL: 'http://localhost:5176', testDir: 'e2e', retries: 0, }); ``` **Базовый конфиг:** - timeout: 30000 - retries: CI ? (params.retries ?? 2) : (params.retries ?? 0) - reporter: CI ? 'html' : 'list' - use.trace: 'on-first-retry' - use.screenshot: 'only-on-failure' - Три браузера: chromium, firefox, webkit ### @vigdorov/knip-config **Тип:** Функция-генератор ```ts import {knipConfig} from '@vigdorov/knip-config'; export default knipConfig({ entry: ['src/main.tsx'], }); ``` **Базовый конфиг:** - entry: params.entry ?? ['src/index.ts'] - project: params.project ?? ['src/**/*.{ts,tsx,js,jsx}'] - ignore: ['**/*.test.*', '**/*.spec.*', 'e2e/**', '**/*.d.ts', ...params.ignore] - ignoreDependencies: params.ignoreDependencies ?? [] - Knip завершается с exit code 1 при ошибках (используется в check-скрипте для блокировки сборки) ## CI/CD ### Тип `library` в ci-templates **Отдельный `library.drone.yml`** (не base.drone.yml) **Pipeline:** prepare → install → test → build → publish **Скрипт `publish-lib.sh`:** - Настраивает .npmrc с GITEA_TOKEN - Для каждого пакета в packages/ сравнивает версию с registry - Публикует только пакеты с новой версией **Trigger:** только main, только push ### service.yaml для dev-configs ```yaml service: name: dev-configs type: library library: scope: "@vigdorov" registry: "https://git.vigdorov.ru/api/packages/vigdorov/npm/" ``` ## Процесс работы с версиями 1. Разработка в feature-ветке 2. Merge в main 3. Поднятие версии: `npm version patch -w packages/eslint` 4. Commit + push: `git commit -am "release: eslint@1.0.1"` 5. CI публикует только пакеты с новой версией ## Потребители В каждом проекте-потребителе: **.npmrc:** ```ini @vigdorov:registry=https://git.vigdorov.ru/api/packages/vigdorov/npm/ ``` **.gitignore (добавить):** ``` coverage/ ``` ## Структура monorepo ``` dev-configs/ ├── packages/ │ ├── eslint/ → @vigdorov/eslint-config │ ├── prettier/ → @vigdorov/prettier-config │ ├── typescript/ → @vigdorov/typescript-config │ ├── vite/ → @vigdorov/vite-config │ ├── jest/ → @vigdorov/jest-config │ ├── playwright/ → @vigdorov/playwright-config │ └── knip/ → @vigdorov/knip-config ├── package.json (workspace root, private: true) ├── tsconfig.base.json (общий tsconfig для сборки пакетов) ├── .npmrc ├── service.yaml ├── .drone.yml ├── .gitignore └── CLAUDE.md ```