كيف أرتب الأشياء في مشروع حيث توجد مجموعة من الأيدي المباشرة (tslint ، أجمل ، الإعدادات ، إلخ)

مرحبا مرة اخرى على اتصال Omelnitsky سيرجي . سوف أشارككم اليوم أحد الصداع ، وهو ما يجب فعله عندما يكتب الكثير من المبرمجين متعددي المستويات مشروعًا باستخدام مثال للتطبيق الزاوي.



لقد حدث أنني عملت لفترة طويلة مع فريقي فقط ، حيث اتفقنا منذ فترة طويلة على قواعد التنسيق والتعليق والمسافة البادئة وما إلى ذلك. اعتدت عليهم وعاشوا معًا بسعادة. للاحتفال ، قمت بنشر مقال عن هبر عن أسلوب الكود الخاص بنا . لذلك ، من شيء سحري ، استخدمنا tslint فقط على الالتزام المسبق.


ثم كبرنا. ظهر مشروع جديد برمز موروث ، بالإضافة إلى مطورين جدد ، بمبلغ 4 زملاء جيدين. وحتى هنا لم يتم وفق الخطة.



أعتقد أن الكثير من الناس يعرفون أن العمل بالكود القديم ليس بالأمر العالي. في ذاكرتي ، تلقيت مشروعًا واحدًا فقط أسعدت منه ، والباقي ... إذن ما الذي أتحدث عنه؟) أوه نعم.


بصراحة ، تركت بنية المشروع الكثير مما هو مرغوب فيه ، وقد حلمنا فقط بالتعليق والكتابة. في مرحلة ما ، شعرت بالحزن لأن وثيقتنا لم تعمل وفقًا لقواعد التصميم ، ولم تتم كتابة التعليقات ، اكتب - ما هذا؟). هنا كان من الضروري أن تفعل شيئا مع هذا.


بالنسبة لأولئك الذين لا يستطيعون الانتظار لمعرفة جميع الخطوات في وقت واحد:
  • قمنا بتقسيم tslint إلى قواعد سهلة (للالتزام المسبق) وقواعد صلبة (لـ ide ، بحيث تذكرنا بما نسي المطورون فعله)


  • تعليق على الالتزام التلقائي للقواعد المحتملة من tslint الثابت


  • كتب القواعد لأجمل


  • رقصت مع الدف لتشغيل نانوغرام الوبر مع مرحلت الوبر



الخطوة الأولى - فرق تسد


عندما حصلت على فكرة لتشديد قواعد linter ، اعتقدت أننا سوف شنق أنفسنا. الرمز موروث. تحتاج إلى فهم ذلك ، وفي مثل هذا المجلد يمكنك الحفر. تقرر إنشاء linter الثاني لـ ide ، والذي سيكون بمثابة عين وقوة لكتابة jsdoc للطرق و sv-c أو كتابة الواجهات أو onPush المشؤومة ، إلخ.


لذلك ، في الجذر ، بدأنا في وضع 2 ملفات 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 } } 

في src/tslint استبدلنا tslint القياسي بـ ide


src / tslint.json
 { "extends": "../tslint.ide_only.json", "rules": { "directive-selector": [ true, "attribute", "app", "camelCase" ], "component-selector": [ true, "element", "app", "kebab-case" ] } } 

وثابت إطلاق لدينا linter في البرامج النصية من package.json


 ng lint --tslint-config ./tslint.json --fix` 

بعد ذلك بدأنا في شنق أنفسنا من الأشياء المسطرة التي تحتاج إلى تصحيح.


الخطوة الثانية - إصلاح بضع نقاط



تسلينت لديها قواعد مع has fixer . لذلك دعونا نستخدمها.


 tslint --project tslint.ide_only.json --fix --force 

هنا نقوم بتشغيل قواعد linter الثابت مع المراجعة التلقائية للمعلمات المتوفرة ونقول أن هذا الأمر لا يُرجع الأخطاء (هدفنا هنا هو إجراء التصحيح التلقائي).


الخطوة الثالثة - الكتابة الجميلة


عندما يكتب الجميع بطريقتهم الخاصة ، يتعب الأمر في النهاية. يجب كتابة الكود بحيث يبدو أن ذلك يتم بواسطة شخص واحد. لهذا ، أنا ثمل أجمل ، مع الإعدادات التالية:


.prettierr.yaml
 printWidth: 200 #  -    tabWidth: 2 #    singleQuote: true #    trailingComma: all #     arrowParens: always #  -  (x) => x overrides: - files: "*.ts" #   *.ts options: parser: typescript #    *.ts 

وأضاف الأمر: prettier --write --config .prettierr.yaml


الخطوة الرابعة - وكيف يمكنك تشغيل كل شيء؟


دعونا الآن نلقي نظرة فاحصة على كيفية بدء كل هذا. لكي يعمل هذا ، نحتاج إلى تنزيل ما يلي:


 npm i -D prettier lint-staged husky 

مع أجش ، سنعلق إطلاق أوامرنا على خطاف بوابة - الالتزام المسبق. سيتم تشغيل أوامر lint-staged بالنسبة لنا اعتمادًا على الملفات التي تم تغييرها (استبدل هذه الملفات أيضًا بنا في الأوامر).


أود أيضًا أن أوجز المشكلة التي واجهتها على الفور. في مشروعنا نستخدم نانوغرام الوبر. عندما نستخدمها جنبًا إلى جنب مع الملفات التي يتم وضعها في الوبر ، تتم إضافة الملفات المعدلة إلى قيادتنا. يحتوي Ng lint على مفتاح --files لهذا ، لكن كما أفهمها ، فإنه لا يرى مجموعة من الملفات ، ويحتاج إلى إضافة هذا المفتاح إلى كل ملف. للقيام بذلك ، اضطررت إلى إنشاء ملف:


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 

لتشغيل هذا الملف ، يجب أن نمرر اسم المشروع. وهو موجود في ملف angular.json في خاصية المشروع. في حالتي ، هذا partner-account partner-account-e2e و partner-account-e2e . أحتاج 1st.


العودة إلى الإعداد. package.json لدينا الآن يبدو مثل هذا:


  "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" ] }, 

إيلاء الاهتمام lint-staged --relative . المعلمة ذات --relative هناك. الآن ، عندما نلتزم ، lint-staged إطلاق lint-staged . هو ، بدوره ، يختار الملفات ويبدأ قائمة بالأوامر حسبها.


للأسف هذا لا يلغي مراجعة الكود ، لكنه أصبح أكثر نظافة. ألاحظ أنني بدأت في كثير من الأحيان بتذكير المطورين بمعدلات الوصول ووصف للطرق و sv ، وبدأت أعمالهم في الكتابة بنفس الأسلوب (جيدًا ، تقريبًا: D).


PS - شكرا على الصور لدينا PM.

Source: https://habr.com/ru/post/ar464383/


All Articles