Cómo crear, publicar y distribuir un paquete de Node js 2017-10-16

Aprende a como crear tu propio paquete en NodeJs y distribuirlo a travéz de npm, y que además este pueda ser utilizado universalmente, ya sea en el browser, en requireJS, en commonJS, etc.

Cómo crear, publicar y distribuir un paquete de Node js

Introducción

A continuación vamos a dar a conocer un poco más acerca de Node js y su sistema de paquetes y dependencias

Nuestras metas a cumplir son:

  • Crear, publicar y mantener paquetes para Node js.
  • Buenas prácticas y recomendaciones a la hora de contruir tú propio paquete.
  • Flujo de git para el buen mantenimiento del paquete (branchestagsetc).
  • Como versionar tu paquete y crear releases.

 

¿Qué es un paquete y para que nos sirve?

Un paquete es una forma encapsular y extraer de nuestro proyecto principal: librerias, componentes, funcionalidades, etc. Para que mediante un gestor de paquetes, las podamos instalar y reutilizar, en diferentes proyectos, siguiendo asi el principio DRY (Do not repeat yourself).

Lo cual no ofrece muchas ventajas como:

  • Modularización.
  • Instalación de subdependencias.
  • Distribución mas fácil y efectiva, siguiendo el versionamiento de cada componentes, etc.

Cada lenguaje tiene su propio sistema para distribuir y modularizar componentes reutilizables como por ejemplo:

  • Ruby: Gems
  • Python: Eggs
  • PHP: packages
  • Node js: packages

 

¿Qué es un gestor de paquetes?

Un gestor de paquetes es el que se encarga de distribuir, instalar, actualizar y controlar las dependiencias de los paquetes a través de un package descriptor o manifest

En la mayoria de lenguajes de programación modernos, existen gestores de paquetes y dependencias como:

Nota: si todavia ocupan npm, por favor comienzen a migrar a yarn. Yarn ofrece muchas más ventajas y ademas provee un archivo de bloqueo de versiones de las dependecias (tipo: Gemfile.lock, composer.lock) y ya no es necesario ocupar el comando shrinkwrap de npm el cual tenia ciertas dificultades.

Manifest / Package Descriptor

Es el archivo en el cual nosotros declaramos, las características de nuestro paquete, como:

  • El nombre
  • La versión
  • Las dependencias, tanto en ambiente de desarrollo como en ambiente normal
  • Archivos a incluir
  • Información acerca del paquete, como:
    • Nombre del autor
    • Nombre de los contribuyentes
    • Dirección URL del paquete, etc
  • Y muchas cosas más.

Ejemplos de package descriptors:

 

Requerimientos para la creación de un paquete en Node js

Software requerido:

Software adicional recomandado y que se utilizarán en esta guía:

 

Contructores de módulos (Module bundlers)

Son herramientas que nos ayudan compilar pequeños trozos de código en algo mas grande y complejo como, una libreria o una aplicación.

Entre los más conocidos tenemos:

Tipos de formato para las librerias:

  • amd: requireJS
  • cjs: CommonJS (NodeJS)
  • es: ES6
  • iffe: Funciones autoejecutables
  • umd: Universal Module Definition

Como crear un paquete

Ejecutamos el siguiente comando

mkdir hjs-demo
cd hjs-demo
yarn init

Esto nos creara una carpeta con el archivo package.json

El cual posee muchas propiedas, como:

  • name: Este es el nombre de nuestro paquete (cuando es una organizacion lleva el prefijo de la organizacion precedido por una @ y separado por /)

  • version: Aqui se describe la versión del paquete, que debe seguir el semver

  • main: Indica el archivo de entra hacia nuestra app

  • dependencies: Listado de pendencias del paquete

  • devDependencies: Listado dependencias para el desarrollo del paquete

  • Podemos ver el listado completo aquí

 

Iniciar repositorio GIT

Inicializamos el repo con el siguiente comando:

git init

Para un mejor control del versionamiento de nuetro paquere vamos a utilizar git-flow. Inicializamos git flow en nuestro proyecto, con el siguiente comando.

git flow init

Creamos nuestro archivo .gitignore (nano .gitignore) y agregamos:

node_modules/
bower_components/

Creamos nuestro archivo .npmignore (nano .npmignore) y agregamos:

src/
test/
bower_components/

Como buena práctica es bueno crear los siguientes archivos:

changelog.md
readme.md

Ahora hacemos commit de nuestros cambios

git add -A; git commit -am "Initial commit"

Y comenzamos a crear nuestro primer release con git-flow el cual será la versión 0.1.0.

git flow release start v0.1.0

Y el primer paso antes de crear nuestro módulo será, cambiar la versión en el package.json para que haga match con nuestro release.

  "version": "0.1.0",

 

Creación del ambiente de desarrollo

Instalación de dependencias de desarrollo

yarn add -D autoprefixer gulp postcss rollup rollup-plugin-minify rollup-plugin-scss run-sequence

Creamos nuestro archivo gulpfile.js y agregamos:

var  gulp, gutil, minify, packageName, pkg, rollup, runSequence, globals, scss, autoprefixer, postcss;

gulp = require("gulp");

gutil = require("gulp-util");

runSequence = require('run-sequence').use(gulp);

rollup = require("rollup");

scss = require("rollup-plugin-scss");

autoprefixer= require("autoprefixer");

postcss= require("postcss");

scss = require("rollup-plugin-scss");

minify = require('rollup-plugin-minify');

pkg = require("./package.json");

packageName = pkg.name;

globals = {

};

gulp.task("dist", function() {
  console.log("Dist");
  return rollup.rollup({
    entry: "./src/" + packageName + ".js",
    plugins: [
      scss({
        outputStyle: "compressed",
        indentedSyntax: true,
        processor: css => postcss([autoprefixer({browsers: ["last 2 versions"]})])
          .process(css)
          .then(result => result.css),
        output: "dist/" + packageName + ".min.css",
      }), minify({
        umd: "dist/" + packageName + ".min.js"
      })
    ],
    external: []
  }).then(function(bundle) {
    var options;
    options = {
      sourceMap: true,
      moduleName: "HjsDemo",
      format: "umd",
      exports: "default",
      dest: "dist/" + packageName + ".js",
      globals: globals
    };
    return bundle.write(options);
  });
});


gulp.task("watchfiles", function() {
  console.log("Watchfiles");
  return gulp.watch("./src/**/**/**/*.js", function(callback) {
    return runSequence("dist");
  });
});

gulp.task("default", function(callback) {
  if (callback == null) {
    callback = function() {};
  }
  runSequence('dist');
  return runSequence("watchfiles");
});

 

Crear nuestro módulo

Modificamos la propiedad main de nuestro packaje.json para que apunte al archivo compilado:

  "main": "dist/hjs-demo.js",

Creamos el archivo src/hjs-demo.sass y agregamos:

body
  background-color: red

Creamos el archivo src/hjs-demo.js y agregamos:

import css from "./hjs-demo.sass";

var HjsDemo = {

  word: "Hola Mundo!",

  say: function() {
    console.log(this.word);
  }
}


export default HjsDemo;

 

Compilar nuestro paquete

Para compilar nuestro paquete corremos el comando gulp.

Y si queremos probar nuestro paquete, podemos crear un archivo test.js, agregarle

HjsDemo = require("./dist/hjs-demo.js");

console.log(HjsDemo.say());

y ejecutarlos con node test.js

 

Publicación y distribución de un paquete

Ahora hacemos commit de nuestros cambios

git add -A; git commit -am "new release"

Finalizamos el release

git flow release finish v0.1.0

Hacemos push al branch develop

git push origin develop

Nos cambiamos al branch master y luego hacemos push junto con todos los tags creados a partir del release. Esto nos creará el tag en el repositorio remoto.

git checkout master
git push --tags origin master 
 

Después de esto nos registramos en la página de npm.

Una vez que ya hemos creado el usuario iniciamos sesión en la terminal, con el siguiente comando.

yarn login

E introducimos nuestro nombre de usuario y correo electrónico.

Luego de esto, hoy si ya podemos finalmente publicar nuestro paquete y que este disponible en los registros de npm, con el siguiente comando.

yarn publish

Y si tu usuario es organización y quieres que tu paquete este público, hay que correr el siguiente comando

yarn publish --access public

Nota: Cuando tu usuario de npm es una organización, el nombre del paquete en tu package.json debe ser @nombre-de-la-organizacion/nombre-del-paquete. Ejemplo: @horchatajs/hjs-multiselect


Acerca del autor

Emilio Forrer Full stack developer

Fanático de Ruby, Nodejs, CoffeeScript. Siempre en búsqueda constante para mejorar, optimizar y modularizar el código.

Compartir este artículo