
Hola a todos Recientemente me encontré con la tarea de configurar paquetes privados npm. Todo sonaba muy interesante y prometedor hasta que resultó que no había mucho que hacer allí. Todo habría terminado aquí, pero surgió la segunda tarea: escribir un repositorio de demostración para el paquete npm, que podría tomarse, clonarse y basarse en él para crear rápidamente algo útil y con el mismo estilo.
El resultado fue un proyecto con formato personalizado, estilo de código, pruebas para cada grupo, límites de cobertura de código, informe de cobertura de código y documentación automática. Más publicación conveniente en npm. Detalles sobre la configuración: debajo del corte.
Requisitos
Primero, descubrí lo que ya tenemos:
- Los nuevos proyectos se escriben en TypeScript
- Además de nuevos proyectos, hay un montón de proyectos en JavaScript puro
- Hay requisitos para escribir pruebas y los resultados deben enviarse para su análisis.
Luego estimó su lista de deseos, ya que hay tiempo y deseo, ¿por qué no tomarlo con calma? Lo que más quiero:
- Quiero un estilo de formato uniforme
- Quiero un estilo unificado de TypeScript
- Quiero documentación, pero no quiero escribirla.
- En general, quiero automatizar todo al máximo. ¿Qué sería fyr-fyr-fyr y en producción
Como resultado, los requisitos tomaron forma en lo siguiente:
- El módulo debe ser TypeScript y probado con TsLint
- El módulo debe usarse desde TypeScript y desde JavaScript
- Las pruebas deben configurarse en git hook, la cobertura mínima del código también debe configurarse, las estadísticas deben ser
- El formato debe estar configurado
- La documentación debe crearse a partir del código.
- La publicación debe ser conveniente y consistente.
- Todo lo que se puede automatizar.
Parece agradable, debes intentarlo.
Gestos preliminares
Creamos (clonamos) el repositorio, inicializamos package.json, establecemos TypeScript localmente. En general, establecemos todas las dependencias localmente, porque todo irá al servidor. No olvides arreglar las dependencias de la versión .
git init npm init npm i -D typescript ./node_modules/.bin/tsc --init
Inmediatamente en el acto, necesita ajustar tsconfig.json por usted mismo: establezca el objetivo, libs, include / exclude, outDir y otras opciones.
Para mantener un formato uniforme, tomé dos herramientas. El primero es el archivo .editorconfig. Lo entienden todos los IDE principales (WebStorm, VSCode, Visual Studio, etc.), no requiere la instalación de nada superfluo y funciona con una gran cantidad de tipos de archivos: 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
Ahora, el autoformato se comportará más o menos igual con mis colegas.
La segunda herramienta es más bonita . Este es un paquete npm que verifica y, si es posible, corrige automáticamente el formato de texto. Instálelo localmente y agregue el primer comando a package.json
npm i -D prettier
package.json
"prettier": "prettier --config .prettierrc.json --write src*.ts"
Prettier no tiene un comando init, por lo que debe configurarlo manualmente. Cree .prettierrc.json en la raíz del proyecto con algo como este contenido controvertido (en todo caso, la publicación no trata sobre qué citas son mejores, pero puede intentarlo)
.prettierrc.json
{ "tabWidth": 4, "useTabs": false, "semi": true, "singleQuote": true, "trailingComma": "es5", "arrowParens": "always" }
Ahora cree la carpeta src, cree index.ts con algún contenido condicional e intente ejecutar más bonito. Si no le gusta su formato, lo arreglará automáticamente. Muy comodo Si no desea recordar esto solo durante un commit / push, puede configurarlo para que se ejecute automáticamente o instalar una extensión para el estudio.
Estilo de código
Con el estilo de código, tampoco todo es complicado. Para JavaScript, hay eslint ; para TypeScript, hay tslint . Ponemos tslint y creamos tsconfig.js para almacenar la configuración
npm i -D tslint ./node_modules/.bin/tslint --init
package.json
"lint": "tslint -c tslint.json 'src/**/*.ts' 'tests/**/*.spec.ts'"
Puede escribir sus propias reglas o puede usar las reglas existentes usando el parámetro extender. Aquí , por ejemplo, una configuración de airbnb.
Los desarrolladores de Tslint están bromeando module.exports = { extends: "./tslint-base.json", rules: { "no-excessive-commenting": [true, {maxComments: Math.random() * 10}] } };
Bueno, ¿no es eso bonito?
Hay un punto importante: tslint y la intersección más bonita en la funcionalidad (por ejemplo, en la longitud de una cadena o comas "colgantes"). Por lo tanto, si usa ambos, deberá supervisar el cumplimiento o abandonar algo.
Y, sin embargo, para aquellos que desean verificar no todos los archivos, sino solo los organizados, hay un paquete con pelusas .
Pruebas
¿Qué necesitamos de las pruebas sobre todo? En primer lugar, para que comiencen automáticamente, en segundo lugar, el control de cobertura, en tercer lugar, algunos informes, preferiblemente en formato lcov (en todo caso, lcov es bien entendido por diferentes analizadores, desde SonarQube hasta CodeCov). Nos ocuparemos de la automatización un poco más tarde, mientras configuramos las pruebas ellos mismos.
Ponemos karma , jazmín y todo el kit de cuerpo correspondiente.
npm i -D karma karma-jasmine jasmine karma-typescript karma-chrome-launcher @types/jasmine ./node_modules/.bin/karma init
Modificamos un poco karma.conf.js e inmediatamente configuramos el trabajo con cobertura
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: {} } } }, }
Y, por supuesto, no olvide agregar un nuevo comando a package.json
package.json
"test": "karma start"
Si está usando o planea usar CI, entonces es mejor poner HeadlessChrome :
npm i -D puppeteer
Y preconfigure Karma (corrección de Chrome en ChromeHeadless) más algo más. Las ediciones se pueden ver en el repositorio de demostración .
Ejecute las pruebas, verifique que todo funcione. Al mismo tiempo, verifique el informe de cobertura (está en la carpeta de cobertura) y elimínelo del control de versiones, no es necesario en el repositorio.
Informe:

Comprometer estilo
Los commits también se pueden unificar (y al mismo tiempo llevar a alguien al rojo vivo, si se excede, por lo que es mejor sin fanatismo). Para esto, me comprometí . Funciona en forma de diálogo, admite el formato convencional de registro de cambios (puede crear un registro de cambios a partir de sus confirmaciones) y hay un complemento VsCode para ello.
npm i -D commitizen npm i -D cz-conventional-changelog
cz-convencional-changelog es un adaptador que se encarga de las preguntas y, como resultado, del formato de sus confirmaciones
Agregue un nuevo comando a la sección de secuencias de comandos
"commit":"git-cz"
Y una nueva sección package.json - config para commitizen
"config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" } }
El diálogo con commitizen se ve así:

La documentación
Ahora a la documentación. Tendremos dos tipos de documentación: de código y de confirmaciones. Para la documentación del código, tomé typedoc (análogo a esdoc pero para TypeScript). Es muy sencillo de configurar y trabajar. Lo principal es no olvidar eliminar los resultados de su trabajo del control de versiones.
npm i typedoc -D
y actualice package.json
package.json
"doc": "typedoc --out docs/src/ --readme ./README.md"
El indicador --readme forzará la inclusión del archivo readme en la página principal de documentación, lo cual es conveniente.
El segundo tipo de documentación es changelog, y el paquete convencional-changelog-cli nos ayudará con él.
npm i -D conventional-changelog-cli
package.json
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
Desde angular solo hay formato y nada más. Ahora para actualizar el registro de cambios simplemente ejecute npm run changelog. Lo principal es escribir cuidadosamente commits. Bueno, siempre escribimos commits perfectos, por lo que esto no debería ser un problema.
Construir
Dado que nuestro paquete también debería funcionar para JavaScript, necesitamos convertir TypeScript en JavaScript. Además, sería bueno hacer un paquete minificado, por si acaso. Para esto necesitamos uglifyjs y un pequeño paquete de ajustes.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"
Por cierto, si desea controlar el tamaño de su proyecto, hay dos paquetes más interesantes
También se pueden integrar en el proceso de confirmación / envío / publicación para mantenerse en el tamaño de paquete aceptable. Muy, muy servicial.
Automatización
Bueno, ya hemos tomado los pasos básicos, ahora todo necesita ser automatizado, de lo contrario será francamente inconveniente trabajar.
Para esto necesitamos un paquete más: husky . Reescribe git hooks y llama a los comandos asociados desde package.json. Por ejemplo, cuando se compromete, el precompromiso funcionará, push - prepush, etc. Si el script devuelve un error, la confirmación fallará.
npm i -D husky
package.json
"precommit":"npm run prettier", "prepush": "call npm run lint && call npm run test"
Aquí hay un matiz importante, el uso de la sintaxis de llamadas no es multiplataforma y no despegará en sistemas Unix. Entonces, si desea hacer todo honestamente, también debe instalar el paquete npm-run-all , lo mismo pero multiplataforma.
Publicar
Bueno, aquí llegamos a la publicación de nuestro paquete (aunque vacío). Pensemos lo que queremos de la publicación?
- Prueba todo de nuevo
- Recoge artefactos de construcción
- Recopilar documentación
- Elevar versión
- Disparar etiquetas
- Enviar a npm
Las manos lo hacen todo, triste. O te olvidas de algo, o necesitas escribir una lista de verificación. También es necesario automatizar. Puede poner otro paquete: desatar . Y puede usar los ganchos nativos de npm: preversión, versión, postversión, por ejemplo, así:
"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'
Queda por especificar para package.json qué incluir en el paquete, el punto de entrada y la ruta a nuestros tipos (no olvide especificar el indicador --declaration en tsconfig.json para obtener archivos d.ts)
package.json
"main": "./dist/index.min.js", "types": "./dist/index.d.ts", "files": [ "dist/", "src/", "tests/" ]
Bueno, eso parece ser todo. Ahora es suficiente hacer
npm version ... npm publish
Y todo lo demás se hará automáticamente.
Bono
Como beneficio adicional, hay un repositorio de demostración que admite todo esto + CI usando travis-ci. Permíteme recordarte que HeadlessChrome está configurado allí, así que si esto es importante para ti, te aconsejo que busques allí.
Agradecimientos
Muchas gracias a Alexei Volkov por su informe sobre JsFest, que se convirtió en la base de este artículo.
Gracias a max7z , indestructible , justboris por aclarar que se pueden omitir rutas a dependencias locales.
Y algunas estadísticas
- Tamaño de nodos_módulos: 444 MB (NTFS)
- Número de dependencias del primer nivel: 17
- Total de paquetes utilizados: 643
Enlaces utiles