Si e rregullova projektin ku kishte një kaos të drejtpërdrejtë (konfigurimet e tslint, prettier, etj.)

Pershendetje përsëri. Jam në kontakt Omelnickiy Sergey. Sot do të ndaj me ju një nga dhimbjet e mia të kokës, dmth - çfarë të bëni kur një projekt shkruhet nga shumë programues me nivele të ndryshme, për shembull në një aplikacion angular.

Si e rregullova projektin ku kishte një kaos të drejtpërdrejtë (konfigurimet e tslint, prettier, etj.)

Kështu ndodhi, që unë kam punuar për një kohë të gjatë vetëm me ekipin tim, ku ne kishim rregulluar prej kohësh rregullat e formatimit, komentimit, hapësirave dhe të tjera. Ne e kthyem në një zakon dhe jetuam në harmoni dhe lumturi. Kënaqësinë e madhe e ndaja edhe një artikull në Habr për stilin tonë të kodit. Prandaj, nga ndonjë magji ne përdorëm vetëm tslint në pre-commit.

Dhe këtu u zgjeruam. Pati një projekt të ri me kod të trashëguar, dhe përveç kësaj, shumë zhvillues të rinj, katër burra të mirë. Dhe gjërat nuk shkuan sipas planit.

Si e rregullova projektin ku kishte një kaos të drejtpërdrejtë (konfigurimet e tslint, prettier, etj.)

Mendoj se shumë e dinë që punën me kodin e trashëguar nuk është e lehtë. Në memorien time kam marrë vetëm një projekt nga i cili isha i ngazëllyer, ndërsa të tjerat... Çfarë përmenda? Ah, po.

Të flas sinqerisht, arkitektura e projektit la për të dëshiruar, ndërsa komentet dhe tipizimi ishin diçka që mund të ëndërroshim. Në një moment, u zhgënjeva nga fakti që dokumentacioni ynë për rregullat e formatimit nuk funksionon, komentet nuk shkruhen, tipi - çfarë është kjo?). Kjo duhet të trajtohej.

Për ata që nuk mund të presin të dinë të gjitha hapat menjëherë:

  • Ne e ndamë tslint në rregulla të buta (për pre-commit) dhe rregulla të forta (për ide, që të kujtonte se zhvilluesit harrojnë të bëjnë)

  • Kemi vendosur auto-fiksimin e mundshëm të rregullave nga tslint i fortë në pre-commit

  • Kemi shkruar rregulla për prettier

  • Dançuam me tambur që të fillonim ng lint me lint-staged

Hapi i parë - ndaje dhe sundo

Kur më erdhi ideja për të ashpërsuar rregullat e linters, mendoja se do të vdisnim. Kodi është i trashëguar. Duhet të merremi me të, dhe në një masë të tillë mund të humbasim. U mor vendimi për të krijuar një linters të dytë për ide, që do të na godiste sy më sy dhe do të na detyronte të shkruanim jsdoc për metodat dhe vetit, të shkruanim ndërfaqet ose të njohurën onPush dhe kështu me radhë.

Pra, në rrënjë fillestare kishim 2 skedarë 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": "Përdorni cloneDeep (lodash) për të kopjuar objektin"
      }
    ],
    "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
  }
}

Në skedar src/tslint ne zëvendësuam tslint standard me ide

src/tslint.json

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

И поправил запуск нашего линтера в скритах package.json

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

Pas kësaj, filluam të shqetësohemi për gjërat e theksuara që duhet të rregullohen.

Hapi i dytë — rregullo disa momente

Si e rregullova projektin ku kishte një kaos të drejtpërdrejtë (konfigurimet e tslint, prettier, etj.)

Të tslint ka rregulla me ka korrigjues. Pra, le të përfitojmë.

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

Këtu ne aktivizojmë rregullat e linters rigoroz me automatikë për rregullimin e parametrave të disponueshëm dhe i themi kësaj komande që të mos kthejë gabime (qëllimi ynë është të realizojmë automatikisht rregullime).

Hapi i tretë — shkruaj bukur

Kur secili shkruan në mënyrën e tij, në fund të fundit, bëhet e lodhshme. Kodi duhet të shkruhet në mënyrë që të duken se e bën një person. Për këtë, kam integruar prettier, me cilësimet e mëposhtme:

.prettierr.yaml

printWidth: 200     # Numri maksimal i simboleve në rresht
tabWidth: 2         # Hapësirat në Tab
singleQuote: true   # Përdorenação e thonjzave të vetme
trailingComma: all  # Përdorimi i presjeve kur është e mundur
arrowParens: always # Funksionet me shigjeta shfaqen (x) => x
overrides:
  - files: "*.ts"   # Kontrollimi i skedarëve *.ts
    options:
      parser: typescript  # Gjuha në skedarët *.ts

Dhe shtova komandën: prettier --write --config .prettierr.yaml

Hapi i katërt — Si do të urdhërosh të gjithë këto?

Le të shqyrtojmë tani më në detaje se si ta aktivizojmë të gjithë këtë. Për të bërë që gjithçka të funksionojë, duhet të shkarkojmë bibliotekat e mëposhtme:

npm i -D prettier lint-staged husky

Me ndihmën e husky, ne do të aktivizojmë ekzekutimin e komandave tona në git hook — pre-commit. lint-staged do të ekzekutojë komandat tona në përputhje me skedarët e ndryshuar (po ashtu do të futë këta skedarë në komandat tona).

Doja gjithashtu të shpjegoja problemin me të cilin u ndesha. Ne në projektin tonë përdorim ng lint. Kur e përdorim në lidhje me lint-staged, skedarët e ndryshuar shtohen në komandën tonë. Ng lint ka një çelës për këtë --files, por, si e kuptova, ai nuk e sheh një grup skedarësh dhe i duhet të shtojë këtë çelës për çdo skedar. Për këtë, më duhet të krijoj skedarin:

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

Për të ekzekutuar këtë skedar, ne duhet të kalojmë emrin e projektit. Ai ndodhet në skedarin angular.json në pronën projekt. Në rastin tim është partner-account dhe partner-account-e2e. Më nevojitet i pari.

Do të kthehem tek konfigurimi. Paketimi ynë.json tani duket kështu:

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

Vini re lint-staged --relative. Parametri --relative është e detyrueshme. Tani, kur bëjmë commit, ater ndodh lint-staged. Ai nga ana e tij seleksionon skedarët dhe ekzekuton një listë komandash në varësi të tyre.

Fatkeqësisht, kjo nuk e anullon shqyrtimin e kodit, por ai është bërë shumë më i pastër. Dua të vënë në dukje se kam filluar të ju kujtoj më rrallë zhvilluesve për modifikatorët e qasjes, përshkrimin e metodave dhe veti, dhe krijimtaria e tyre tani shkruhet në një stil të njëjtë (në të vërtetë pothuajse 😀 ).

P.S. — Faleminderit për imazhet tonë PM.

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster