Crear librería en JavaScript instalable con NPM
A medida que aumentas tu nivel como desarrollador y vas creando funcionalidades en uno y otro proyecto, te das cuenta que bien podrías crear una librería centralizada e instalarla en todos tus demás proyectos. Esta librería podría ser privada o pública, pero la idea central es que sea un proyecto de código independiente, mantenible y centralizado. Es por esto que hoy veremos cómo crear una librería JavaScript que puedas fácilmente instalar en todos tus proyectos.
Requerimientos
Para poder desarrollar este tutorial, es necesario que cumplas con lo siguiente:
- Tener instalado NPM en tu máquina
- Haber creado una cuenta en NPM Registry
- Tener una cuenta en GitHub
Creación del archivo package.json
Lo primero que debes hacer es crear un repositorio nuevo en GitHub. Para efectos de este tutorial vamos a suponer que creaste el repositorio proyecto/mi-repo. Después de esto vas a descargar de manera local tu proyecto.
git clone git@github.com:proyecto/mi-repo.git
Ingresas a tu repo en la consola de tu sistema operativo y ejecutas el siguiente comando de npm.
npm init
Inmediatamene después de esto npm te solicitará algunos datos de manera interactiva como el vendor name, la descripción y otros datos relevantes. Al final, obtendrás una respuesta similar a la siguiente:
npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (mi-repo) @proyecto/mi-repo
version: (1.0.0) 0.1.0
description: Alguna descripción
entry point: (index.js)
test command:
git repository: (https://github.com/proyecto/mi-repo.git)
keywords: keyword
author: Your Name <email@example.com> (http://example.com)
license: (ISC) MIT
About to write to /path/proyecto/mi-repo/package.json:
...
Is this OK? (yes) yes
npm notice
npm notice New minor version of npm available! 8.3.1 -> 8.5.4
npm notice Changelog: https://github.com/npm/cli/releases/tag/v8.5.4
npm notice Run npm install -g npm@8.5.4 to update!
npm notice
En la parte del autor tanto el email como el website son opcionales. Después de esto npm creará un archivo llamado package.json similar al siguiente:
{
"name": "proyecto/mi-repo",
"version": "0.1.0",
"description": "Alguna descripción",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/proyecto/mi-repo.git"
},
"keywords": [
"keyword"
],
"author": "Your Name <email@example.com> (http://example.com)",
"license": "MIT",
"bugs": {
"url": "https://github.com/proyecto/mi-repo/issues"
},
"homepage": "https://github.com/proyecto/mi-repo#readme"
}
Deberás crear para este propósito una organización en NPM que se llame proyecto y así poder subir tu paquete. Si lo que deseas es subir la librería a nombre tuyo puedes usar el nombre @username/tu-repo. El símbolo @ actúa como un namespace para evitar colisiones de paquetes.
De igual forma podrás colocar un nombre de paquete sin namespace, por ejemplo tu-repo pero muchas veces los nombres que queremos ya están registrados.
Creación del código
Por supuesto, debes crear el código de tu proyecto. Por lo general las librerías suelen guardar el código en una carpeta llamada src. Tu eres libre de decidir si haces esto y encapsulas todo tú código allí, o creas una carpeta por cada namespaces en la raíz del proyecto.
De cualquier forma, deberás crear un archivo que sea el entry point de la librería. En este caso será index.js. Para efectos de este tutorial vamos a crear una clase Calculator
que realice una suma básica.
Módulos CommonJS
Los módulos CommonJS son la manera más utilizada en este momento en Node para cargar paquetería de terceros. Utilizando este enfoque nuestra clase quedaría de la siguiente manera.
class Calculator
{
sum($a, $b)
{
return $a + $b;
}
}
module.exports = {Calculator};
Cuando utilizamos CommonJS en otros proyectos o librerías debemos cargar los objetos con la función require
.
const { Calculator } = require("@pleets/js-validators")
const calc = new Calculator()
console.log('sum ' + calc.sum(3,5))
Módulos ES
Los módulos ES te permiten cargan archivos mediante la sentencia import
y permite que se carguen o exporten mediante export
. A la fecha de hoy hay un soporte experimental de este estándar por parte de Node así que se recomienda utilizarlo a discreción. Para esto, lo primero que debes hacer es agregar lo siguiente a tu archivo package.json.
{
"type": "module"
}
Seguido a esto puedes crear la clase Calculator.
class Calculator
{
sum($a, $b)
{
return $a + $b;
}
}
export default Calculator;
Cada desarrollador que use tu librería deberá tener también soporte para módulos ES si quiere usar tu código. A menos que utilice alguna herramienta como webpack para interpretar dicho código y transpilarlo.
Una desventaja de este enfoque es que cuando cambias el tipo de módulos a ES otros archivos dejarán de funcionar si están con CommonJS. Entonces necesitarás renombrarlos con la extensión .csj. Si no los renombras tal vez te encuentres alguna vez con este error.
ReferenceError: module is not defined in ES module scope ...
To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
Módulos ES mediante Webpack
Debido a los inconvenientes que puede generar que tu librería utilice de manera nativa módulos ES existe una forma sencilla de seguir utilizando esta funcionalidad sin tener que expresarlo explícitamente en tu archivo package.json. Esto se logra mediante webpack. Lo único que debes hacer es instalar webpack, la cli de webpack y compilar los assets a una carpeta dist.
npm i webpack --save-dev
npm i webpack-cli --save-dev
npx webpack --entry ./index.js --output-path ./dist/ --mode production
Esto puede servir en el caso de que estés probando tu librería internamente con el comando de node.
node index.js
Ya que si no tienes los módulos ES especificados en el package.json obtendrás un error como el siguiente.
Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension..
Así podrás probar tu script de la siguiente manera.
node ./dist/main.js
Si vas a importar el archivo generado en el navegador deberás agregar lo siguiente al output de webpack en el archivo webpack.config.js.
output: {
...
libraryTarget: 'umd',
globalObject: 'window',
},
Si vas a utilizar el archivo generado en node deberás agregar lo siguiente.
output: {
...
libraryTarget: 'umd',
globalObject: 'this',
},
Agrega un scaffolding para pruebas unitarias (opcional)
Agregar pruebas unitarias a tu proyecto seguramente te diferenciará de aquellos que suben repositorios por cumplir alguna tarea o que están en proceso de aprendizaje, de aquellos que lo hacen de manera regular y profesional. A continuación te dejo un enlace a un post diferente si deseas agregar pruebas unitarias a tu proyecto.
Implementa ESLint en tu proyecto o librería (opcional)
ESLINT es un linter para JavaScript. Un Linter no es más que una herramienta que nos ayuda a cumplir las buenas prácticas de codificación, estilos , identificación de code smells, entre otros aspectos en un lenguaje de programación. Si deseas que tu librería se utilizada por miles de personas y que tengas un prestigio en la red por tus aportes esta integración no puede faltar. A continuación te dejo un enlace a un post diferente si deseas implementar PSR.
Qué es ESLINT, para qué sirve y cómo utilizarlo
Sube tu proyecto a GitHub
Sube tus cambios de manera organizada a GitHub. Recuerda que GitHub es un VCS hosting service, no es un servicio de almacenamiento en donde simplemente subes tu código. Crea cada funcionalidad y súbela en un commit. Puedes utilizar GitFlow también, esto te presentará como un desarrollador profesional.
Cuando los desarrolladores vean tu librería en NPM tendrá un enlace directo a GitHub por lo cual es importante que subas tu código allí y tengas actualizado el repositorio.
Versiona tu librería
Debes versionar tu librería en GitHub para mantener una consistencia con las vesiones en NPM. Esto lo puedes hacer creando tags que serían el simil al version
del archivo package.json
.
Carga de tu librería en NPM Registry
NPM Registry es un repositorio para paquetes de npm. Cuando ejecutas npm install para instalar las dependencias de un proyecto npm busca todos estos paquetes en npm registry y descarga las versiones adecuadas colocándolas en la carpeta node_modules.
Para publicar tu librería en npm debes loguearte mediante el siguiente comando:
npm login
Deberás ingresar tu username, password y el OTP que llega a tu correo. Después de esto deberás obtener una salida similar a la siguiente:
npm notice Log in on https://registry.npmjs.org/
Username: yourUser
Password:
Email: (this IS public) user@example.com
npm notice Please check your email for a one-time password (OTP)
Enter one-time password: 60536287
Logged in as yourUser on https://registry.npmjs.org/.
NPM por defecto intenta crear los paquetes o librerías de manera privada. Es por esto que al publicar un nuevo paquete deberás hacerlo de la siguiente manera.
npm publish --access=public
Verifica que puedes instalar tu librería
Una vez hayas publicado tu paquete búscale en NPM y verifica que quedó con la versión correcta. Después de esto prueba que lo puedes instalar en un nuevo proyecto.
npm install @proyecto/tu-repo
En este nuevo proyecto puedes por ejemplo crear un archivo index.js con el siguiente contenido.
import Calculator from "@pleets/js-validators";
const calc = new Calculator()
console.log('sum ' + calc.sum(3,5))
Y después de esto ejecutarlo con node así.
npm index.js
Obtendremos una respuesta como la siguiente:
sum 8