Programando un blog desde 0. #1 Create una React App sin Create-React-App 7


Photo by Aaron Burden on Unsplash

Foto de Aaron Burden en Unsplash

Una de las razones por las que tengo abandonado este blog es que no me gusta demasiado wordpress. Funciona bien, es innegable, Pero todo está demasiado sobredimensionado.  Me abruma la cantidad de herramientas que tengo para gestionar una página que en su pico llegó a 200 usuarios al mes. Ejemplos como Yoast SEO diciendome que mi entrada no está bien escrita. O el maldito Wordfence pidiendo actualizarse cuasi a diario, cuando aun no sé ni lo que hace. Un sistema de comentarios cuyas notificaciones se pierden en el ruido de actualizaciones y avisos. O el plugin de social networks, cuyo botón de facebook jamas he conseguido hacer funcionar. Tambien estan los temas visuales, que sí, muy bonitos, pero no puedo modificar ni un apice sin pasar por caja. Al final son una cantidad de detalles que me dejan un poso de «Si lo hubiese hecho yo, lo habría hecho así» y que me resultan muy frustrantes, dado que cambiar cualquier cosa me exige un tiempo y esfuerzo que me termina disuadiendo de meter mano ahí. Todo eso juntado con lo difícil que es buscar tiempo, ganas, un tema, documentarse y escribir sobre el, pues han hecho que lleve mas de seis meses sin dejar una entrada por aquí.

Pero esta semana se me ha encendido la bombilla: Puedo lidiar con todo eso rehaciendo yo mismo el blog. Una aplicación hecha a medida de mis gustos y necesidades, utilizando todo el conocimiento que he ido adquiriendo desde que comencé este viaje. Aprovechando ademas para documentar el proceso en el blog, podría arrasar con todos esos impedimentos que he comentado en el párrafo anterior. Y oye, que me he entusiasmado con la idea y heme aquí un domingo por la tarde escribiendo esta primera entrada de, espero, una larga serie de artículos explicando como construyo un aplicación.

 

Preambulo

Lo normal sería plantear el alcance del proyecto, establecer unos objetivos globales, montar un trello y dividir el trabajo en historias, establecer unas lineas de diseño, maquetar las vistas, implementar una lógica… Pero el cuerpo me pide ir poco a poco, viendo las necesidades que surjan y pivotando segun me apetezca, aunque no sea la manera profesional de hacerlo. Este es un proyecto personal con el que quiero pasármelo bien, aprender y crear contenido interesante para el blog. Tampoco  quiero enfocar esto como una serie de tutoriales. Mas bien como un Walktrought que puedas disfrutar leyendo como aficionado a la programación web, con muchas imágenes y explicaciones pero sin entrar en el grano fino de las cosas. Voy a usar mi stack habitual en el trabajo, node y react, puesto que son las herramientas con las que mejor me manejo ahora mismo y, ademas, me divierto mucho con ellas. Por el camino haré uso de otras muchas, aunque eso prefiero ir desgranandolo poco a poco conforme avance el proyecto.

 

Si todo va bien, al final tendremos una aplicación alojada en internet que susituirá a este blog y, en el último capitulo, cambiaremos este dominio franbosquet.com para que apunte a esa aplicación. Si nó, pues siempre nos quedará wordpress. ¡A por ello!

Objetivo del día

Para esta entrada de hoy, me gustaría montar una aplicación node que sea capaz de buildear una aplicacion React con un hola mundo. No es muy ambicioso, lo sé. Pero prefiero arrancar flojo y no empacharme que no pegarme un atracón y abandonar pronto este proyecto.

Paquete npm, el folio en blanco

Como la gran mayoría de aplicaciones Javascript modernas, todo empieza con un npm init en una solitaria carpeta. Aun no he decidido como voy a llamar a todo esto, pero por el momento nos referiremos a ello como FranPress:

Creando el paquete NPM

Creando el paquete NPM para empezar a trabajar en el proyecto

Básicamente he creado la carpeta en mi directorio de documentos y he ejecutado npm init en su interior. Este comando te realiza una serie de preguntas para rellenar tu package.json. Solo comentar qué:

  • He añadido una descripción :«A simple cms for regular people»Por que en este mundillo ser naif y pretencioso es NECESARIO.
  • He añadido los keywords blog cms. Totalmente inutiles puesto que no voy a publicar esto como paquete NPM.
  • Me he añadido a mi como autor, porque soy un egolatra.
  • He cambiado la licencia a MIT, para que cualquiera pueda hacer con este proyecto lo que se le antoje. Puedes leer bastante sobre tipos de licencias y qué permite cada una aquí.

¿Por qué no Create-React-App?

Pues sería una opción totalmente válida. Mi único reparo con el mismo es que te ofusca la configuración de webpack. Y no me gustan este tipo de cajas negras donde no puedes pinchar ni cortar. Así que como en este proyecto no tengo prisa y sí libertad creativa, vamos a montar un proyecto React desde cero y a añadir lo que nos de la gana en el, sin abstraernos de como funciona webpack por debajo. En realidad es bastante chorra, a poco que sepas quien es quien en la ensalada que vamos a montar. Así que puede ser una buena ocasión para perderle el miedo.

Por cierto, CRA (create-react-app) es el mas famoso y el «oficial» en cierto modo, pero existen otros proyectos base para arrancar una aplicación React. Aquí tienes una buena lista por si te apetece descansar de el.

Git

Antes de nada, es recomendable iniciar el control de versiones (git en este caso) y cambiar a una rama de desarrollo. Voy a crear una rama para cada entrada en este diario de viaje y así mantener ordenado el trabajo.

Iniciando el repositorio

Iniciando el repositorio para el control de versiones

Aquí inicio un nuevo repositorio con git init. Seguidamente, utilizo git add . para añadir todos los cambios actuales al stage. Despues, comiteo ese stage con el nombre «Initial commit», que es un poco convención para arrrancar un repo. Finalmente, creo y cambio a la rama «Chapter-1» con git checkout -b «chapter-1». Todo esto es de primero de control de versiones, así que voy a intentar no perder tiempo explicando estas cosas.

Estructura del proyecto

Este paso es la mar de sencillo, crear las carpetas que voy a necesitar para organizar el proyecto:

  • src, para guardar el código de la aplicación. Todo lo que vaya aquí tendrá que ser procesado por webpack antes de ser consumible por el navegador.
  • public, para archivos estáticos como imagenes o documentos html. Todo lo que vaya aquí se sirve tal cual al navegador.
Creando la estructura de carpetas del proyecto

Creando la estructura de carpetas del proyecto

Index

El index.html es el archivo que serviremos al navegador cuando cargue nuestra página. Como tal, es un archivo estático, por lo que va en /public:

Index html vacio

Index html vacio

He utilizado el snippet html:5 de emmet para rellenar esas doce lineas. Simplemente escribe html:5 y el propio editor te sugerira autocompletar el resto. Viene instalado por defecto en VS Code y está disponible en otros editores, como Atom. Tras esto, solamente he cambiado el título de la página por un provisonal Franpress. Ahora mismo ya podriamos poner la dirección de este archivo en el navegador y veriamos una pagina en blanco con un título en la pestaña. Algo es algo. Obviamente a esto le falta mucho para ser una aplicación react. Debemos olvidarnos un rato del index.html antes de eso.

Babel

Saltemos a Babel. Babel es un transpilador de código. Esto es: coge un código en Javascript y lo convierte en otro código también en Javascript. Esto no parece muy impresionante. El matiz está en que el primer código no puede ser interpretado por el navegador, pero el segundo si.

Entonces ¿Por qué no escribir el segundo código directamente?

Pues, básicamente, porque es un coñazo. Babel nos permite escribir código moderno, facil de crear y mantener, y convertirlo en arcaico código javascript que (casi) cualquier navegador pueda interpretar. Por el camino podemos minificar el código, uglificarlo, añadir tipado estático a javascript o cualquier cosa que se te ocurra. Ademas, en React hacemos uso intensivo de JSX, que es una sintaxis que emula XHTML dentro de javascript, permitiéndonos describir nuestros componentes de una forma natural. JSX no sería posible sin un transpilador, y eso es lo que nos aporta Babel.

Instalando babel

Instalando babel

Menos chachara:

Como puedes ver, he utilizado la directiva -D al instalar babel. Esto indica que es una dependencia solo de desarrollo. No necesito babel una vez el código está transpilado. Por otro lado, he instalado:

  • babel-core, el nucleo de babel. Es necesario para hacer cualquier cosa con el idem.
  • babel-cli, permite utilizar babel desde la linea de comandos.
  • babel-preset-env, es una plantilla de babel que transforma código ES6 y posterior en javascript tradicional (ES5). Nos permite utilizar caracteristicas modernas del lenguaje aunque el navegador que cargue nuestro programa no las implemente.
  • babel-preset-react. Otra plantilla. En este caso, transforma código JSX en código interpretable para el navegador.

.babelrc

Este archivo debe situarse en la raiz del proyecto y simplemente indica a babel la configuración a utilizar:

Configuración de babel

Configuración de babel

Básicamente, los dos presets que hemos utilizado con anterioridad. Es importante resaltar que este archivo se escribe en notacion JSON por lo que, a diferencia de en JavaScript, es importante mantener las comillas incluso en los nombres de las propiedades del objeto.

Por el momento, podemos olvidarnos de babel y saltar al siguiente punto.

.gitignore

Inciso. Quizas te haya dado la tentación de commitear los últimos cambios en tu repositorio. Para ello, tal vez se te haya ocurrido repetir el git add . que hicimos antes. ¡Quieto insensato! Al instalar babel has hecho lo propio con TODAS sus dependencias. Si te fijas en la penúltima captura, eso son 180 paquetes. Cada uno con su código, sus readmes, sus tests… Todo ello metido en la carpeta /node_modules. Es código que no es propio de tu aplicación y que puedes obtener fácilmente con un npm install. Así que vamos a indicar a git que lo ignore. Para ello solo hay que crear un fichero .gitignore y añadir todo lo que no queramos que trace el control de versiones. De momento, node_modules:

Antes de guardar .gitignore

Antes de guardar .gitignore

Despues de guardar .gitignore

Despues de guardar .gitignore

Si te fijas en las capturas, antes de guardar el archivo .gitignore, VS Code me indica que tengo 4000 o mas cambios pendientes (El tercer icono en la barra de la izquierda). Después de guardarlo, git ignora /node_modules y los cambios se reducen a 5. Ahora si podría hacer un git add . y comitear.

No obstante, utilizar git add . es una práctica que desaconsejo. Es preferible ponerle un poco de cariño al tema del control de versiones y meter pocas cambios pero relacionados entre si y con el mensaje del commit. A este respecto, puedes usar las herramientas integradas en tu IDE para añadir los archivo que te interesen. O mejor, usar git add -p e ir marcando qué partes de tu código quieres incluir en el stage mediante el terminal.

Webpack

Webpack se define como un module bundler. El concepto es algo etereo, pero podriamos traducirlo como un empaquetador. Básicamente coge todo tú código no procesado (el que teniamos en src/ ¿Recuerdas?) y lo empaqueta en un solo archivo .js que se puede distribuir como un estático. En el proceso, tambien puede empaquetar tu codigo css, tus imagenes y demas cóntenido. De hecho, puede hacer cualquier cosa puesto que está diseñado de forma modular, de modo que eres tú quien decide en que consiste ese empaquetado. En nuestro caso no solo vamos a querer que empaquete, sino que ademas transpile nuestro javascript (de ahí Babel) y algunas cosas mas.

Webpack se distribuye por medio de otro paquete npm, así que vamos a instalarlo:

Instalando Webpack

Instalando Webpack

 

Al igual que con Babel, he utilizado el flag -D para indicar que se trata de dependencias de desarrollo que no queremos en nuestro producto final. Vamos a desgranar todo lo que he instalado aquí:

  • webpack, obviamente. El nucleo del bundler y quien va a hacer el trabajo.
  • webpack-cli. La interfaz para linea de comandos, nos va a permitir interectuar con webpack desde la terminal.
  • webpack-dev-server. Un servidor de desarrollo, va a transpilar el código en tiempo real y a servirlo por el puerto que le digamos en localhost. Va a realizar este trabajo cada vez que cambiemos un archivo, de modo que nos va a facilitar mucho el ver en tiempo real el resultado de nuestro trabajo. Un must.
  • css-loader. Webpack se nutre de loaders, pequeños modulos que extienden su funcionalidad. Añadiendo loaders es como transformas webpack para que haga lo que tú quieres. Este primer módulo permite cargar  archivos .css directamente en tu codigo javascript mediante la directiva import o la función require. Este loader se encargara de transformarlos en un tag <link> en tu html. Para que funcione necesitamos tambien style-loader.
  • babel-loader. Transpila tú código antes de empaquetarlo.

Para que todo esto funcione necesitamos un archivo de configuración que webpack pueda interpretar. Ese será webpack.config.js. Debemos colocarlo en la raiz del proyecto y consiste simplemente en un fichero js que va a ejecutar nodejs, y que exporta un objeto de configuración:

Configurando webpack

Configurando webpack

  • Importamos webpack y path. Este último es un paquete de node que permite trabajar con rutas.
  • Exportamos un objeto de configuración.
  • Este debe tener un punto de entrada. A partir de ahí, webpack ira tirando del hilo de import y/o require para ir obteniendo el resto de archivos del proyecto. Si hay un archivo que no importa nadie (es decir, que no se usa), webpack no lo va a empaquetar. El punto de entrada será el archivo index.js, que colocaremos dentro de src/
  • Y un punto de salida, una carpeta. Como he usado mucho Create-React-App, a mi me gusta llamarlo build, pero tambien es comun llamarlo dist. Tambien tenemos que indicar un nombre de archivo para nuestro javascript empaquetado, en este caso build.js

Aun faltan mas cosas:

Configurando Webpack

Configurando Webpack

Entre entry output metemos un module (linea 6). Aquí, dentro de una clave rules, vamos a configurar cada uno de esos loaders que hemos instalado.

El primero es el de babel. Necesitamos que actúe sobre todos los archivos con extensión .js, asi que introducimos un campo test con una expresión regular que capture todos los nombres de archivo con esa extensión (linea 9). El siguiente paso es añadir un campo exclude e incluir una expresión regular que capture node_modules, por aquello de no transpilar todas tus dependencias y liar un circo bastante desagradable (linea 10). A continuación, en un campo loader, indicamos, pues eso, qué loader se encarga de actuar en eso archivos (linea 11), que en este caso es el de babel. También podemos añadir opciones adicionales mediante el campo options (linea 12) . En este caso indicamos los presets que queremos pasarle a babel, ahora mismo solo ‘env’ (Si recuerdas, el que nos transpilaba código ES6+ en ES5-).

El segundo es para el css. Indicamos qué archivos queremos tratar (linea 17) y el loader a utilizar. En este caso utilizamos la notación use (linea 18) en vez de loader (linea 11) ¿por qué? Puede darse el caso de que queramos usar más de un cargador sobre un determinado tipo de archivo. loader es una notación alternativa a use para los casos en los que solo necesitemos un loader.  Metemos aquí css-loader y su style-loader (recuerda, el primero necesita al segundo para funcionar). También podríamos meter aquí un cargador de sass, aunque en este proyecto, en principio, no lo voy a usar.

Configurando Webpack

Configurando Webpack

La propiedad resolve nos permite indicar qué extensiones va a asumir de forma implicita webpack. Gracias a esta linea podremos escribir import ‘../utils’  en lugar de import ‘../utils.js’. Puedes añadir aquí otras extensiones si te apetece, por ejemplo .json .css. Eso sí, ojo con las colisiones de nombres. La inclusión del asterisco se debe a que si especificamos extensiones, estaremos sobrescribiendo el comportamiento por defecto y Webpack no va a saber resolver un import si la extensión indicada no está en la lista. Con el asterisco evitaremos esto.

Configurando Webpack

Configurando Webpack

Para terminar, configuramos el servidor de desarrollo. Especificamos que vamos a usar devServer (linea 29). En su interior, especificamos:

  • contenBase: El contenido base (los archivos estáticos) que tenemos en la carpeta /public
  • port: El puerto en el que vamos a servir el contenido. A mi me gusta el 8080 para el front y dejar el 3000 para mis APIs.
  • publicPath: Donde está nuestro código ya empaquetado.

Finalmente cargamos el plugin de HMR (linea 34). Este es el que nos va a permitir recargar el contenido cada vez que haya cambios en nuestros ficheros. Y ya está, hemos configurado webpack. 35 lineas. No era para tanto ¿no? Comiteo los cambios y sigo.

React

Lo primero para usar esta librería es instalarla.

Instalando React

Instalando React

En algún punto de su desarrollo react se volvió tan grande que decidieron partir la librería en dos:

  • Por un lado el propio React, que implementa el interprete de jsx y la lógica de componentes, como se renderizan y como funcionan internamente.
  • Por otro ReactDOM, que se encarga de traducir el DOM virtual en cambios en el DOM del navegador.

En la practica, ReactDOM solo se llama una vez en tu archivo de entrada, por lo que solo debes preocuparte de el una vez. Creamos un archivo index.js dentro de src/ que será nuestro punto de entrada (tal y como le indicamos webpack).

El embrion del nuevo blog

El embrion del nuevo blog

Vamos a desgranar esto:

  • Primero importar React y ReactDOM (lineas 1-2). Si te fijas, veras que al primero no lo llamamos en ningun sitio. Sin embargo, cuando escribimos código JSX React debe estar en scope, así que hemos de importarlo en todos los archivos que utilicemos esta notación.
  • ReactDOM.render(…)  (linea 4) es una función que «engancha» nuestra aplicación a un nodo de la página estática index.html. Es la forma en la que conectamos nuestra aplicación al navegador.
  • Como primer argumento, hemos de pasarle un componente React, nuestra aplicación (lineas 5-7). Aquí es donde entra JSX: Hemos escrito un texto dentro de un div que babel se encargará de convertir en código legible para el navegador. Recuerda, estamos en javascript, no en html. Sin babel esas lineas darían un error de sintaxis.
  • El elemento al que nos enganchamos. Podemos utilizar cualquier metodo que nos devuelva un nodo del DOM. Lo optimo es seleccionar por id, como en este caso. Sin embargo, no escribimos ningun nodo con el id App cuando escribimos nuestro index.html. Es el momento de hacerlo:
Completando nuestro index.html

Completando nuestro index.html

Dentro del body, añadimos ese nodo con el id App. Ya tenemos un punto del que colgar nuestra aplicación. Por otro lado, podemos añadir un tag <noscript>…</…> que se mostrará solo si el navegador no tiene javascript habilitado. Finalmente, aprovechamos que estamos por aquí y cargamos el build.js que nos va a generar webpack. Quizas podriamos cambiar este nombre porque /build/build.js queda muy reiterativo, pero lo dejaremos así de momento.

NPM script

Para terminar, necesitamos un script que ejecute webpack y nos sirva nuestra página con el webpack-dev-server. Vamos a nuestro package.json y escribimos lo siguiente:

Start script

Start script

Cuando ejecutemos npm start se iniciará nuestro webpack-dev-server en modo desarrollo y nos abrirá un navegador mostrando el resultado. Probamos y…

Resultado del trabajo de hoy

Resultado del trabajo de hoy

¡Listo! Tenemos una infraestructura lista para empezar a escribir nuestra aplicación React y partiremos de aquí en el siguiente capítulo. Con esto ya habríamos llegado al objetivo de hoy. He creado un repo en GitHub en el que puedes consultar todo el código descrito aquí.

No es la primera vez que monto una infraestructura de este tipo, pero configurar webpack es una de esas cuestiones que no te aprendes de memoria. Por lo tanto he tirado de blogs para realizar el proceso con ciertas garantías. Este de Evheniy Bystrov está muy completo, pero mete muchísima configuración adicional y puede resultar muy confuso si es la primera vez que te pones con esto. Este otro de Linh Nguyen My me resulta mas conciso y me parece mejor opción si solo quieres echar a andar un aplicación. Yo personalmente me he guiado principalmente por este otro de Jedai Saboteur, por ser directo y sencillo de seguir. Hay cientos de tutoriales a este respecto solo en Medium. Mi recomendación es seguir varios e ir aclarando dudas sobre el proceso. Webpack puede resultar un poco abrumador, pero es una herramienta muy potente y me parece una buena oportunidad para coger mas soltura con ella. Por otro lado, está empezando a sonar con fuerza Parcel, otro webbundler que promete ser mas sencillo de configurar. Para este proyecto nos quedaremos con el primero, aunque quizas en el futuro le dedique un artículo a este último. Aquí tienes mas información.

Espero que hayas disfrutado de la lectura y nos veamos en el siguiente capitulo. Como siempre cualquier duda estaré encantado de resolverla en los comentarios, twitter o por correo.

Un saludo!

 


Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

7 ideas sobre “Programando un blog desde 0. #1 Create una React App sin Create-React-App

      • Alberto

        Hola cuando hago el npm start me tira este error

        ERROR in ./src/index.js
        Module build failed (from ./node_modules/babel-loader/lib/index.js):
        Error: Cannot find module ‘@babel/core’
        babel-loader@8 requires Babel 7.x (the package ‘@babel/core’). If you’d like to use Babel 6.x (‘babel-core’), you should install ‘babel-loader@7’.
        at Function.Module._resolveFilename (module.js:547:15)
        at Function.Module._load (module.js:474:25)
        at Module.require (module.js:596:17)
        at require (internal/module.js:11:18)
        at Object. (E:\Proyectos\webpersonal\node_modules\babel-loader\lib\index.js:10:11)
        at Module._compile (module.js:652:30)
        at Object.Module._extensions..js (module.js:663:10)
        at Module.load (module.js:565:32)
        at tryModuleLoad (module.js:505:12)
        at Function.Module._load (module.js:497:3)
        @ multi (webpack)-dev-server/client?http://localhost:3000 ./src/index.js main[1]

  • Alberto

    Hola cuando ejecuto el comando npm start para iniciar me tira este error

    ERROR in ./src/index.js
    Module build failed (from ./node_modules/babel-loader/lib/index.js):
    Error: Cannot find module ‘@babel/core’
    babel-loader@8 requires Babel 7.x (the package ‘@babel/core’). If you’d like to use Babel 6.x (‘babel-core’), you should install ‘babel-loader@7’.
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at Object. (E:\Proyectos\webpersonal\node_modules\babel-loader\lib\index.js:10:11)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    @ multi (webpack)-dev-server/client?http://localhost:3000 ./src/index.js main[1]

    Muchas gracias por el post y la ayuda !!

    • Fran Autor

      Según indica el error, tienes instalada la versión 6 de babel pero el babel-loader que has instalado necesita la 7. Hace poco salio babel 7 y puede que el contenido de este post no funcione con la nueva versión :S En tu caso, prueba a hacer un «npm i babel-loader@7 babel-core@6» para forzar que uses las mismas versiones que he usado yo, con lo cual debería funcionarte.