Halo lagi. Sentuhan Omelnitsky Sergey . Hari ini saya akan berbagi dengan Anda salah satu sakit kepala saya, yaitu, apa yang harus dilakukan ketika banyak programmer bertingkat menulis sebuah proyek menggunakan contoh aplikasi sudut.

Kebetulan bahwa untuk waktu yang lama saya hanya bekerja dengan tim saya, di mana kami telah lama menyetujui aturan untuk memformat, berkomentar, lekukan, dll. Saya terbiasa dengan mereka dan hidup bersama dengan bahagia. Untuk merayakannya, saya bahkan menerbitkan artikel tentang Habr tentang gaya kode kami . Karena itu, dari sesuatu yang ajaib, kami hanya menggunakan tslint pada pre-commit.
Lalu kami tumbuh. Sebuah proyek baru dengan kode yang diwariskan muncul, dan untuk itu, di samping pengembang baru, dalam jumlah 4 orang yang baik. Dan bahkan di sini tidak berjalan sesuai rencana.

Saya pikir banyak orang tahu bahwa bekerja dengan kode lama tidak tinggi. Dalam ingatan saya, saya hanya menerima satu proyek dari mana saya senang, dan sisanya ... Jadi apa yang saya bicarakan?) Oh ya.
Terus terang, arsitektur dalam proyek ini meninggalkan banyak yang harus diinginkan, dan kami hanya bermimpi berkomentar dan mengetik. Pada titik tertentu, saya sedih dengan kenyataan bahwa dokumen kami tidak berfungsi sesuai dengan aturan desain, komentar tidak ditulis, ketik - apa ini?). Di sini perlu untuk melakukan sesuatu dengan ini.
Bagi mereka yang tidak sabar untuk mengetahui semua langkah sekaligus:Kami membagi tslint menjadi aturan lunak (untuk pra-komitmen) dan aturan keras (untuk ide, sehingga mengingatkan kita tentang apa yang lupa dilakukan oleh pengembang)
Tunggu perbaikan pra-komit aturan yang mungkin dari hard tslint
Menulis aturan untuk yang lebih cantik
Ditarik dengan rebana untuk menjalankan serat dengan bertahap-serat
Langkah Satu - Bagilah dan Taklukkan
Ketika saya mendapat ide untuk memperketat aturan linter, saya pikir kita akan gantung diri. Kode tersebut diwarisi. Anda perlu memahaminya, dan dalam volume seperti itu Anda dapat menggali. Diputuskan untuk membuat linter ke-2 untuk ide, yang akan merusak pemandangan dan memaksa untuk menulis jsdoc untuk metode dan sv-c, menulis antarmuka atau nasib buruk padaPush, dll.
Jadi, di root, kami mulai meletakkan 2 file tslin:
tsconfig.json{ "rulesDirectory": [ "node_modules/codelyzer" ], "rules": { "arrow-return-shorthand": true, "callable-types": true, "class-name": true, "comment-format": [ true, "check-space" ], "curly": true, "deprecation": { "severity": "warn" }, "eofline": true, "forin": true, "import-blacklist": [ true, "rxjs/Rx" ], "import-spacing": true, "indent": [ true, "spaces" ], "interface-over-type-literal": true, "label-position": true, "max-line-length": [ true, 200 ], "member-access": false, "member-ordering": [ true, { "order": [ "static-field", "instance-field", "static-method", "instance-method" ] } ], "no-arg": true, "no-bitwise": true, "no-console": [ true, "debug", "info", "time", "timeEnd", "trace" ], "no-construct": true, "no-debugger": true, "no-duplicate-super": true, "no-empty": false, "no-empty-interface": true, "no-eval": true, "no-inferrable-types": [ false, "ignore-params" ], "no-duplicate-imports": true, "no-misused-new": true, "no-non-null-assertion": true, "no-redundant-jsdoc": true, "no-shadowed-variable": false, "no-string-literal": false, "no-string-throw": true, "no-switch-case-fall-through": true, "no-trailing-whitespace": [ true, "ignore-comments", "ignore-jsdoc" ], "no-unnecessary-initializer": true, "no-unused-expression": true, "no-use-before-declare": false, "no-var-keyword": true, "object-literal-sort-keys": false, "one-line": [ true, "check-open-brace", "check-catch", "check-else", "check-whitespace" ], "prefer-const": true, "quotemark": [ true, "single" ], "radix": false, "semicolon": [ true, "always" ], "triple-equals": [ true, "allow-null-check" ], "typedef-whitespace": [ true, { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace" } ], "unified-signatures": true, "variable-name": false, "whitespace": [ true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type" ], "directive-selector": [ true, "attribute", "app", "camelCase" ], "component-selector": [ true, "element", "app", "kebab-case" ], "no-output-on-prefix": false, "no-inputs-metadata-property": true, "no-outputs-metadata-property": true, "no-host-metadata-property": true, "no-input-rename": false, "no-output-rename": true, "use-lifecycle-interface": true, "use-pipe-transform-interface": true, "component-class-suffix": true, "directive-class-suffix": true, "no-consecutive-blank-lines": true } }
tslint.ide_only.json { "rulesDirectory": [ "node_modules/codelyzer" ], "rules": { "completed-docs": [ true, { "properties": true, "methods": true } ], "no-angle-bracket-type-assertion": true, "no-any": true, "prefer-output-readonly": true, "prefer-on-push-component-change-detection": true, "array-type": [ true, "array" ], "typedef": [ true, "call-signature", "arrow-call-signature" ], "arrow-return-shorthand": true, "callable-types": true, "class-name": true, "comment-format": [ true, "check-space" ], "curly": true, "deprecation": { "severity": "warn" }, "eofline": true, "forin": true, "import-blacklist": [ true, "rxjs/Rx" ], "import-spacing": true, "indent": [ true, "spaces" ], "interface-over-type-literal": true, "label-position": true, "max-line-length": [ true, 200 ], "member-access": [ true, "check-parameter-property", "check-accessor" ], "member-ordering": [ true, { "order": [ "public-static-field", "protected-static-field", "private-static-field", "public-instance-field", "protected-instance-field", "private-instance-field", "constructor", "public-static-method", "protected-static-method", "private-static-method", "public-instance-method", "protected-instance-method", "private-instance-method" ] } ], "no-arg": true, "no-bitwise": true, "no-console": true, "no-construct": true, "no-debugger": true, "no-duplicate-super": true, "no-empty": false, "no-empty-interface": true, "no-duplicate-switch-case": true, "no-eval": true, "no-inferrable-types": [ false, "ignore-params" ], "no-duplicate-imports": true, "one-variable-per-declaration": true, "no-misused-new": true, "no-non-null-assertion": true, "prefer-template": [ true, "allow-single-concat" ], "ordered-imports": true, "no-redundant-jsdoc": true, "no-shadowed-variable": false, "no-string-literal": false, "no-string-throw": true, "no-switch-case-fall-through": true, "no-trailing-whitespace": [ true, "ignore-comments", "ignore-jsdoc" ], "ban": [ true, { "name": [ "Object", "assign" ], "message": " cloneDeep (lodash) " } ], "max-classes-per-file": [ true, 1 ], "cyclomatic-complexity": [ true, 6 ], "static-this": true, "no-unnecessary-initializer": true, "no-unused-expression": true, "no-var-keyword": true, "object-literal-sort-keys": false, "one-line": [ true, "check-open-brace", "check-catch", "check-else", "check-whitespace" ], "prefer-const": true, "quotemark": [ true, "single" ], "radix": false, "semicolon": [ true, "always" ], "triple-equals": [ true, "allow-null-check" ], "typedef-whitespace": [ true, { "call-signature": "nospace", "index-signature": "nospace", "parameter": "nospace", "property-declaration": "nospace", "variable-declaration": "nospace" } ], "unified-signatures": true, "variable-name": false, "whitespace": [ true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type" ], "directive-selector": [ true, "attribute", "app", "camelCase" ], "component-selector": [ true, "element", "app", "kebab-case" ], "no-output-on-prefix": false, "no-inputs-metadata-property": true, "no-outputs-metadata-property": true, "no-host-metadata-property": true, "no-input-rename": false, "no-output-rename": true, "use-lifecycle-interface": true, "use-pipe-transform-interface": true, "component-class-suffix": true, "directive-class-suffix": true, "no-consecutive-blank-lines": true } }
Dalam file src/tslint
kami mengganti tslint standar dengan ide
src / tslint.json { "extends": "../tslint.ide_only.json", "rules": { "directive-selector": [ true, "attribute", "app", "camelCase" ], "component-selector": [ true, "element", "app", "kebab-case" ] } }
Dan memperbaiki peluncuran linter kami di skrip package.json
ng lint --tslint-config ./tslint.json --fix`
Setelah itu kami mulai menggantung diri dari hal-hal yang digarisbawahi yang perlu diperbaiki.
Langkah dua - perbaiki beberapa poin

Tslint memiliki aturan dengan has fixer
. Jadi mari kita gunakan.
tslint --project tslint.ide_only.json --fix --force
Di sini kita menjalankan aturan hard linter dengan perbaikan otomatis dari parameter yang tersedia dan mengatakan bahwa perintah ini tidak mengembalikan kesalahan (di sini tujuan kita masih melakukan koreksi otomatis).
Langkah Tiga - menulis dengan indah
Ketika semua orang menulis dengan cara mereka sendiri, itu akhirnya melelahkan. Kode harus ditulis sehingga tampaknya ini dilakukan oleh satu orang. Untuk ini, saya bermain lebih cantik, dengan pengaturan berikut:
.prettierr.yaml printWidth: 200 # - tabWidth: 2 # singleQuote: true # trailingComma: all # arrowParens: always # - (x) => x overrides: - files: "*.ts" # *.ts options: parser: typescript # *.ts
Dan dia menambahkan perintah: prettier --write --config .prettierr.yaml
Langkah Empat - Dan bagaimana Anda memerintahkan semuanya untuk dijalankan?
Sekarang mari kita lihat lebih dekat bagaimana memulai semua ini. Agar ini berfungsi, kita perlu mengunduh yang berikut:
npm i -D prettier lint-staged husky
Dengan husky, kita akan menggantung peluncuran perintah kita di hook git - pre-commit. lint-staged akan menjalankan perintah untuk kita tergantung pada file yang diubah (juga gantikan file-file ini dengan perintah).
Saya juga ingin segera menguraikan masalah yang saya temui. Dalam proyek kami, kami menggunakan serat. Ketika kita menggunakannya bersamaan dengan lint-staged, file yang dimodifikasi ditambahkan ke perintah kita. Ng lint memiliki kunci --files
untuk ini, tetapi seperti yang saya pahami, ia tidak melihat banyak file, dan perlu menambahkan kunci ini ke setiap file. Untuk melakukan ini, saya harus membuat file:
lint.sh #!/bin/bash PROJECT=$1 shift SOURCES=$@ DESTINATIONS="" DELIMITER="" for src in $SOURCES do DELIMITER=" --files " DESTINATIONS="$DESTINATIONS$DELIMITER${src}" done ng lint $PROJECT --tslint-config ./tslint.json $DESTINATIONS
Untuk menjalankan file ini, kita harus melewati nama proyek. Itu terletak di file angular.json
di properti proyek. Dalam kasus saya, ini adalah partner-account
partner-account-e2e
dan partner-account
partner-account-e2e
. Saya butuh 1.
Kembali ke pengaturan. Package.json kami sekarang terlihat seperti ini:
"husky": { "hooks": { "pre-commit": "lint-staged --relative" } }, "lint-staged": { "*.{ts,js}": [ "prettier --write --config .prettierr.yaml", "tslint --project tslint.ide_only.json --fix --force", "sh lint.sh partner-account", "git add" ], "*.{html,scss,css}": [ "prettier --write --config .prettierr.yaml", "git add" ] },
Perhatikan lint-staged --relative
. Parameter --relative
sana. Sekarang, ketika kita berkomitmen, lint-staged
diluncurkan. Dia, pada gilirannya, memilih file dan memulai daftar perintah tergantung pada mereka.
Sayangnya ini tidak membatalkan tinjauan kode, tetapi telah menjadi jauh lebih bersih. Saya perhatikan bahwa saya kurang sering mulai mengingatkan pengembang tentang pengubah akses, deskripsi metode dan sv, dan pekerjaan mereka mulai ditulis dengan gaya yang sama (well, hampir: D).
PS - Terima kasih atas gambarnya kepada PM kami.