DEV Community

Rubén Aguilera Díaz-Heredero
Rubén Aguilera Díaz-Heredero

Posted on • Updated on

Montar SPA de cero con Vanilla y Jest

TL;DR

Aquí el repo con el resultado de seguir la guía: https://github.com/raguilera82/vanilla-spa-starter

Introducción

En un mundo frontend dominado actualmente por los tres frameworks: React, Angular y Vue; es importante no perder las bases y ver que nada es magia y que todo se puede hacer con VanillaJS.

En este primer tutorial vamos a ver cómo montar el entorno necesario para comenzar nuestro proyecto sin frameworks, utilizando únicamente alguna librería como Jest para realizar el testing.

Creación del proyecto y primeros ficheros

Partimos de que nuestra máquina de desarrollo cuenta con un runtime de NodeJS y vamos a utilizar la terminal y como editor el Visual Studio Code.

Así que lo primero será abrir la terminal y crear el directorio donde vamos a empezar nuestro proyecto de cero.

$> mkdir /path/vanilla-starter
$> cd /path/vanilla-starter
Enter fullscreen mode Exit fullscreen mode

Ahora para inicializar el proyecto hacemos uso del comando init de npm, y con el modificador -y aceptamos todos los valores por defecto:

$> npm init -y
Enter fullscreen mode Exit fullscreen mode

Para ayudar en la edición de los ficheros vamos a abrir el proyecto con Visual Studio Code y el resto de comandos los ejecutaremos desde el terminal del editor:

$> code .
Enter fullscreen mode Exit fullscreen mode

Nos apoyamos en el editor para crear una carpeta llamada "src" que va a contener inicialmente los ficheros "index.html", "main.css" y "main.js".

El fichero index.html va a tener el siguiente contenido donde no hacemos ninguna referencia al CSS ni al JavaScript, esa será labor de webpack.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vanilla</title>
  </head>
  <body>
    <h1>Vanilla</h1>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

En el fichero "main.css" podemos añadir algún estilo:

body {
  background-color: grey;
}
Enter fullscreen mode Exit fullscreen mode

E igual podemos hacer con el fichero "main.js" para ver que vamos bien, si vemos en la consola el mensaje y donde importamos el fichero main.css que luego será reconocido por webpack:

import './main.css';
console.log('Vanilla');
Enter fullscreen mode Exit fullscreen mode

Añadimos webpack al proyecto

A fin de que nuestro proyecto sea una SPA y para realizar todas las operaciones necesarias para su puesta en producción como minificado, tener refresco automático en desarrollo y otras tareas, vamos a incluir webpack como dependencia de desarrollo del proyecto.

$> npm install webpack webpack-cli webpack-dev-server webpack-merge --save-dev
Enter fullscreen mode Exit fullscreen mode

Instalamos también todos los plugins de webpack que inicialmente vamos a utilizar en nuestro proyecto:

$> npm install html-webpack-plugin mini-css-extract-plugin css-loader style-loader html-loader @babel/core @babel/preset-env babel-loader --save-dev
Enter fullscreen mode Exit fullscreen mode

Ahora en el raíz del proyecto vamos a crear un fichero llamado "webpack.common.js" donde vamos a incluir todos los comportamientos que queremos que webpack nos ejecute independiente de que el entorno sea de desarrollo o de producción.

const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        clean: true
    },
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.html$/i,
                loader: 'html-loader'
            },
            {
                test: /\.m?js$/,
                exclude: /node_modules/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }
        ]
    },
    plugins: [
        new HTMLWebpackPlugin({
            template: './src/index.html'
        })
    ]
};
Enter fullscreen mode Exit fullscreen mode

Y luego vamos a crear uno para el entorno de desarrollo llamado webpack.dev.js

const { merge } = require('webpack-merge');

const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  target: 'web',
  devServer: {
    historyApiFallback: true //Evita GET /page not found
  }
});
Enter fullscreen mode Exit fullscreen mode

Y otro con la configuración para producción, llamado webpack.prod.js:

const { merge } = require('webpack-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'production',
  devtool: 'source-map',
  plugins: [new MiniCssExtractPlugin()],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  }
});
Enter fullscreen mode Exit fullscreen mode

Añadimos los siguientes scripts al fichero package.json, también le vamos a añadir la configuración de browserlist para que la usen las herramientas compatibles como babel-preset-env:

"scripts": {
    "start": "webpack serve --config=webpack.dev.js",
    "build": "webpack --config=webpack.prod.js"
},
"browserslist": [
    "defaults",
    "not IE 11"
],
Enter fullscreen mode Exit fullscreen mode

De forma que cuando estamos desarrollando utilizamos la configuración de desarrollo y cuando construimos el bundle lo hacemos con la configuración para producción.

Para comprobar que la configuración es la correcta podemos arrancar el proyecto:

$> npm run start
Enter fullscreen mode Exit fullscreen mode

y comprobar la URL: http://localhost:8080

Y para ver que nos genera correctamente los ficheros estáticos, ejecutamos:

$> npm run build
Enter fullscreen mode Exit fullscreen mode

y comprobamos que nos genera la carpeta "dist", la cual es buena idea que introduzcamos dentro del fichero .gitignore

node_modules/
dist/
Enter fullscreen mode Exit fullscreen mode

Configuración de pruebas automáticas con Jest

A fin de poder ejecutar pruebas automáticas en el proyecto, añadimos la dependencia de Jest junto con su soporte de babel y la librería que permite pruebas con DOM:

$> npm install jest babel-jest @testing-library/dom --save-dev
Enter fullscreen mode Exit fullscreen mode

creamos el fichero babel.config.json con el siguiente contenido:

{
  "presets": ["@babel/preset-env"]
}
Enter fullscreen mode Exit fullscreen mode

y el siguiente script al fichero package.json, quedando de esta forma:

"scripts": {
    "start": "webpack serve --config=webpack.dev.js",
    "build": "webpack --config=webpack.prod.js",
    "test": "jest --coverage"
},
"jest": {
    "transform": {
      "^.+\\.[t|j]sx?$": "babel-jest"
    }
  }
Enter fullscreen mode Exit fullscreen mode

De forma que podemos ejecutar npm run test para lanzar todas las pruebas del proyecto (cuando las tenga) y recoger el informe de cobertura gracias al modificador --coverage.

Configuración de linters

Linter de código

A fin de que todo el equipo de desarrollo haga uso de una misma guía de estilo, vamos a incluir la dependencia:

$> npm install --save-dev semistandard
Enter fullscreen mode Exit fullscreen mode

y el siguiente script en el fichero package.json, también vamos a añadir configuración para que no marque errores en los tests, quedando de esta forma:

"scripts": {
    "start": "webpack serve --config=webpack.dev.js",
    "build": "webpack --config=webpack.prod.js",
    "test": "jest --coverage",
    "lint": "semistandard --fix"
},
"semistandard": {
    "globals": [
      "describe",
      "context",
      "before",
      "beforeEach",
      "after",
      "afterEach",
      "it",
      "expect"
    ]
  },
Enter fullscreen mode Exit fullscreen mode

Pudiendo ejecutar npm run lint para descubrir las violaciones en las reglas de estilo y con el modificador --fix solucionarlas de forma automática.

Nota: por defecto no se comprobarán los ficheros que estén dentro del fichero .gitignore.

Linter de mensajes de commit

Vamos a añadir a nuestro proyecto la dependencia de husky, la cual nos permitirá establecer una serie de hooks de Git que nos permitan verificar que los mensajes de commit cumplen con el standard de Conventional Commits

$> npm install husky @commitlint/cli @commitlint/config-conventional --save-dev
Enter fullscreen mode Exit fullscreen mode

Creamos en la raíz del proyecto el directorio .husky y dentro creamos el fichero "commit-msg" con el siguiente contenido para comprobar que el mensaje cumple con el formato de Conventional Commits:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit $1
Enter fullscreen mode Exit fullscreen mode

Y otro llamado "pre-commit" para ejecutar los test antes de hacer un commit:

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npm test
Enter fullscreen mode Exit fullscreen mode

Es muy importante darle permisos de ejecución a todos estos ficheros.

$> cd .husky
$> sudo chmod -R +x *
$> cd ..
Enter fullscreen mode Exit fullscreen mode

Y en el fichero package.json incluimos el siguiente script para instalar husky al hacer un prepare del proyecto y añado la siguiente configuración:

"scripts": {
    "prepare": "husky install",
    "start": "webpack serve --config=webpack.dev.js",
    "build": "webpack --config=webpack.prod.js",
    "test": "jest",
    "lint": "semistandard"
},
"commitlint": {
    "extends": "@commitlint/config-conventional"
},
Enter fullscreen mode Exit fullscreen mode

Para probarlo tenemos que inicializar git en el proyecto:

$> git init
Enter fullscreen mode Exit fullscreen mode

Ejecutar un install de npm:

$> npm install
Enter fullscreen mode Exit fullscreen mode

Al tratar de hace un commit tenemos que ver que ejecuta los tests y nos saca un mensaje de error si no se cumple con el formato marcado.

Conclusiones

Con estos pasos ya tenemos preparado nuestro proyecto para poder implementar la solución que necesitemos. En caso estar trabajando con Visual Studio Code, es altamente recomendable las siguientes extensiones:

  • Jest Runner: para poder ejecutar cualquier test case o test suite de forma aislada al resto.

Oldest comments (0)