Nous avons mis en place un projet npm pratique pour nous-mêmes et pour l'équipe ou un peu sur les outils frontaux modernes


Bonjour à tous. Récemment, je suis tombé sur la tâche de configurer des packages npm privés. Tout semblait très intéressant et prometteur jusqu'à ce qu'il s'avère qu'il n'y avait pas grand-chose à faire là-bas. Tout se serait terminé ici, mais la deuxième tâche a surgi - écrire un référentiel de démonstration pour le paquet npm, qui pourrait être pris, cloné et basé sur lui pour créer rapidement quelque chose d'utile et dans le même style.


Le résultat a été un projet avec un formatage personnalisé, un style de code, des tests pour chaque pool, des limites de couverture de code, un rapport de couverture de code et une documentation automatique. De plus, une publication pratique dans npm. Détails sur le réglage - sous la coupe.


Prérequis


Tout d'abord, j'ai compris ce que nous avons déjà:


  • Les nouveaux projets sont écrits en TypeScript
  • En plus de nouveaux projets, il y a un tas de projets en pur JavaScript
  • Il y a des exigences pour écrire des tests et les résultats doivent être envoyés pour analyse

Puis il a estimé sa liste de souhaits - car il y a du temps et du désir, pourquoi ne pas y aller doucement. Ce que je veux de plus:


  • Je veux un style de formatage uniforme
  • Je veux un style TypeScript unifié
  • Je veux de la documentation, mais je ne veux pas l'écrire
  • En général, je veux tout automatiser au maximum. Que serait fyr-fyr-fyr et en production

En conséquence, les exigences ont pris forme comme suit:


  • Le module doit être TypeScript et testé à l'aide de TsLint
  • Le module doit être utilisé sous TypeScript et sous JavaScript
  • Les tests doivent être configurés sur git hook, la couverture minimale du code doit également être configurée, les statistiques doivent être
  • Le formatage doit être configuré
  • La documentation doit être créée à partir du code.
  • La publication doit être pratique et cohérente.
  • Tout ce qui peut être automatisé

Ça a l'air sympa, il faut essayer.


Gestes préliminaires


Nous créons (clonons) le référentiel, initialisons package.json, définissons TypeScript localement. En général, nous définissons toutes les dépendances localement, car tout ira au serveur. N'oubliez pas de corriger les dépendances de version .


git init npm init npm i -D typescript ./node_modules/.bin/tsc --init 

Immédiatement sur place, vous devez modifier tsconfig.json pour vous-même - définir la cible, les bibliothèques, inclure / exclure, outDir et d'autres options.


Style de formatage


Pour maintenir une mise en forme uniforme, j'ai pris deux outils. Le premier est le fichier .editorconfig. Il est compris par tous les principaux IDE (WebStorm, VSCode, Visual Studio, etc.), ne nécessite aucune installation superflue et fonctionne avec un grand nombre de types de fichiers - js, ts, md, etc.


 #root = true [*] indent_style = space end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true max_line_length = 100 indent_size = 4 [*.md] trim_trailing_whitespace = false 

Maintenant, la mise en forme automatique se comportera plus ou moins de la même manière avec mes collègues.


Le deuxième outil est plus joli . Il s'agit d'un package npm qui vérifie et, si possible, corrige automatiquement la mise en forme de votre texte. Installez-le localement et ajoutez la première commande à package.json


 npm i -D prettier 

package.json


 "prettier": "prettier --config .prettierrc.json --write src/**/*.ts" 

Prettier n'a pas de commande init, vous devez donc la configurer manuellement. Créez .prettierrc.json à la racine du projet avec quelque chose comme ce contenu controversé (si quoi que ce soit, le post n'est pas du tout sur les meilleures citations, mais vous pouvez essayer)


.prettierrc.json


 { "tabWidth": 4, "useTabs": false, "semi": true, "singleQuote": true, "trailingComma": "es5", "arrowParens": "always" } 

Maintenant, créez le dossier src, créez index.ts avec du contenu conditionnel et essayez d'exécuter plus joli. S'il n'aime pas votre mise en forme, il le corrigera automatiquement. Très confortable. Si vous ne souhaitez pas vous en souvenir uniquement lors d'un commit / push, vous pouvez le configurer pour exécuter automatiquement ou installer une extension pour le studio.


Style de code


Avec le style de code, tout n'est pas compliqué non plus. Pour JavaScript, il y a eslint ; pour TypeScript, il y a tslint . Nous mettons tslint et créons tsconfig.js pour stocker les paramètres


 npm i -D tslint ./node_modules/.bin/tslint --init 

package.json


 "lint": "tslint -c tslint.json 'src/**/*.ts' 'tests/**/*.spec.ts'" 

Vous pouvez écrire vos propres règles ou utiliser des règles existantes à l'aide du paramètre extend. Voici , par exemple, une configuration d'Airbnb.


Les développeurs de Tslint plaisantent
 module.exports = { extends: "./tslint-base.json", rules: { "no-excessive-commenting": [true, {maxComments: Math.random() * 10}] } }; 

Eh bien, n'est-ce pas joli?


Il y a un point important - tslint et plus joli se croisent dans la fonctionnalité (par exemple, dans la longueur d'une chaîne ou des virgules «suspendues»). Donc, si vous utilisez les deux, vous devrez surveiller la conformité ou abandonner quelque chose.


Et pourtant, pour ceux qui veulent vérifier pas tous les fichiers, mais seulement les étapes - il y a un paquet étagé


Les tests


De quoi avons-nous besoin avant tout des tests? Premièrement, pour qu'ils démarrent automatiquement, deuxièmement, le contrôle de la couverture, troisièmement certains rapports, de préférence au format lcov (le cas échéant, lcov est bien compris par différents analyseurs - de SonarQube à CodeCov). Nous traiterons de l'automatisation un peu plus tard, lors de la configuration des tests eux-mêmes.


Nous mettons du karma , du jasmin et tout le kit corporel correspondant


 npm i -D karma karma-jasmine jasmine karma-typescript karma-chrome-launcher @types/jasmine ./node_modules/.bin/karma init 

Nous modifions un peu karma.conf.js et configurons immédiatement le travail avec la couverture


karma.conf.js
 karmaTypescriptConfig : { include: ["./src/**/*.ts", "./tests/**/*.spec.ts"], tsconfig: "./tsconfig.json", reports: { "html": "coverage", "lcovonly": { directory: './coverage', filename: '../lcov.dat' } }, coverageOptions: { threshold: { global: { statements: 60, branches: 60, functions: 60, lines: 60, excludes: [] }, file: { statements: 60, branches: 60, functions: 60, lines: 60, excludes: [], overrides: {} } } }, } 

Et, bien sûr, n'oubliez pas d'ajouter une nouvelle commande à package.json


package.json


 "test": "karma start" 

Si vous utilisez ou prévoyez d'utiliser CI, il est préférable de mettre HeadlessChrome :


 npm i -D puppeteer 

Et préconfigurez Karma (correction de Chrome sur ChromeHeadless) et autre chose. Les modifications peuvent être consultées dans le référentiel de démonstration .


Exécutez les tests, vérifiez que tout fonctionne. Dans le même temps, vérifiez le rapport de couverture (il se trouve dans le dossier de couverture) et supprimez-le du contrôle de version, il n'est pas nécessaire dans le référentiel.


Rapport:



Style de validation


Les commits peuvent également être unifiés (et en même temps amener quelqu'un à chauffer à blanc, si vous en faites trop, c'est mieux sans fanatisme). Pour cela, je me suis engagé . Il fonctionne sous la forme d'un dialogue, prend en charge le format de journal des modifications conventionnel (vous pouvez créer un journal des modifications à partir de ses validations) et il existe un plugin VsCode pour cela.


 npm i -D commitizen npm i -D cz-conventional-changelog 

cz-conventionnel-changelog est un adaptateur qui est responsable des questions, et par conséquent, du format de vos commits


Ajouter une nouvelle commande à la section des scripts


 "commit":"git-cz" 

Et une nouvelle section package.json - config pour commitizen


 "config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" } } 

La boîte de dialogue avec commitizen ressemble à ceci:



La documentation


Passons maintenant à la documentation. Nous aurons deux types de documentation - à partir du code et des commits. Pour la documentation du code, j'ai pris typedoc (analogue à esdoc mais pour TypeScript). C'est très simple à installer et à travailler. L'essentiel est de ne pas oublier de supprimer les résultats de son travail du contrôle de version.


 npm i typedoc -D 

et mettre à jour package.json


package.json


 "doc": "typedoc --out docs/src/ --readme ./README.md" 

L'indicateur --readme forcera le readme à être inclus dans la page de documentation principale, ce qui est pratique.


Le deuxième type de documentation est le journal des modifications, et le package conventionnel-changelog-cli nous aidera avec cela.


 npm i -D conventional-changelog-cli 

package.json


 "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s" 

De angulaire, il n'y a que le formatage et rien de plus. Maintenant, pour mettre à jour le journal des modifications, lancez simplement npm run changelog. L'essentiel est d'écrire soigneusement les commits. Eh bien, nous écrivons toujours des commits parfaits, donc cela ne devrait pas être un problème.


Construire


Étant donné que notre package devrait également fonctionner pour JavaScript, nous devons transformer TypeScript en JavaScript. De plus, ce serait bien de faire un bundle minifié, juste au cas où. Pour cela, nous avons besoin de uglifyjs et d'un petit package tweak.json


 npm i -D uglifyjs 

package.json


 "clean":"rmdir dist /S /Q", "build": "tsc --p ./ --sourceMap false", "bundle": "uglifyjs ./dist/*.js --compress --mangle --output ./dist/index.min.js" 

Soit dit en passant, si vous souhaitez contrôler la taille de votre projet, il existe deux autres packages intéressants



Ils peuvent également être intégrés dans le processus de validation / push / publication pour conserver la taille de bundle acceptable. Très, très utile.


Automatisation


Eh bien, nous avons déjà pris les mesures de base, maintenant tout doit être automatisé, sinon ce sera franchement gênant de fonctionner.


Pour cela, nous avons besoin d'un autre paquet - husky . Il réécrit les hooks git et appelle les commandes associées à partir de package.json. Par exemple, lorsque vous vous engagez, precommit fonctionnera, push - prepush, etc. Si le script renvoie une erreur, la validation échouera.


 npm i -D husky 

package.json


 "precommit":"npm run prettier", "prepush": "call npm run lint && call npm run test" 

Il y a une nuance importante ici, l'utilisation de la syntaxe d'appel n'est pas multiplateforme et ne décollera pas sur les systèmes Unix. Donc, si vous voulez tout faire honnêtement, vous devez également installer le package npm-run-all , il fait de même mais sur plusieurs plates-formes.


Publication


Eh bien, nous arrivons à la publication de notre package (bien que vide). Pensons ce que nous voulons de la publication?


  • Testez tout à nouveau
  • Récupérer des artefacts de construction
  • Recueillir la documentation
  • Augmenter la version
  • Balises de déclenchement
  • Soumettre à npm

Les mains font tout - triste. Ou vous oubliez quelque chose, ou vous devez rédiger une liste de contrôle. Il est également nécessaire d'automatiser. Vous pouvez mettre un autre paquet - libérer . Et vous pouvez utiliser les hooks natifs de npm lui-même - préversion, version, postversion, par exemple comme ceci:


 "preversion": "npm run test", "version": "call npm run clean && call npm run build && npm run bundle && call npm run doc && call npm run changelog && git add . && git commit -m 'changelogupdate' --no-verify", "postversion": "git add . && git push && git push --tags", 

Il reste à spécifier pour package.json ce qu'il faut inclure dans le package, le point d'entrée et le chemin vers nos types (n'oubliez pas de spécifier l'indicateur --declaration dans tsconfig.json pour obtenir les fichiers d.ts)


package.json


 "main": "./dist/index.min.js", "types": "./dist/index.d.ts", "files": [ "dist/", "src/", "tests/" ] 

Eh bien, cela semble être tout. Maintenant fais juste


 npm version ... npm publish 

Et tout le reste se fera automatiquement.


Bonus


En prime, il existe un référentiel de démonstration qui prend en charge tout cela + CI en utilisant travis-ci. Permettez-moi de vous rappeler que HeadlessChrome est configuré là-bas, donc si cela est important pour vous, je vous conseille d'y regarder.


Remerciements


Un grand merci à Alexei Volkov pour son rapport sur JsFest, qui est devenu la base de cet article.


Merci à max7z , indestructible , justboris pour avoir clarifié que les chemins vers les dépendances locales peuvent être omis.


Et quelques statistiques


  • Taille des Node_modules: 444 Mo (NTFS)
  • Nombre de dépendances du premier niveau: 17
  • Total des paquets utilisés: 643

Liens utiles


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


All Articles