No existe un enfoque único con los módulos CSS para crear las plantillas de JavaScript, los archivos CSS o los pasos de compilación para que funcionen. En esta publicación, que es parte de una serie sobre módulos CSS, veremos un enfoque. El objetivo de esta publicación es poner en marcha un proyecto de módulos CSS.
Serie de artículos:
- ¿Qué son los módulos CSS y por qué los necesitamos?
- Introducción a los módulos CSS (¡está aquí!)
- React + Módulos CSS = 😍
En los proyectos en los que trabajo, existe el requisito de que CSS nunca debe depender de JavaScript del lado del cliente para funcionar, por lo que el paso de compilación debe procesar todo en HTML y CSS antes de implementarlo. Usaremos Webpack, un sistema de compilación y un paquete de módulos. En la próxima publicación, nos centraremos en hacer que el código siguiente sea adecuado para un proyecto de la vida real que genera HTML estático en el navegador.
¡Vamos a empezar!
Instalación de Webpack
Después de instalar NPM y el nodo, necesitamos configurar un directorio vacío en algún lugar y ejecutar lo siguiente:
npm init --y
Esto hará un package.json
archivo y rellénelo con un montón de valores predeterminados. Este es nuestro manifiesto de dependencia: las instrucciones para lo que se descarga e instala cuando otras personas npm install
este proyecto.
Webpack se encargará de nuestro proceso de construcción. Observará nuestro CSS, JavaScript y HTML y realizará toda la magia en el medio. Pero, ¿qué es Webpack? Maxime Fabre se preguntó si Webpack es un sistema de compilación o un paquete de módulos:
Bueno, es ambas cosas, y con esto no quiero decir que haga ambas cosas, quiero decir que combina ambas. Webpack no construye sus activos y luego agrupa sus módulos por separado, considera que sus activos son módulos en sí mismos … que se pueden importar, modificar, manipular y que, en última instancia, se pueden empaquetar en su paquete final.
Si esto suena extraño, no se preocupe. ¿Recuerdas cuando Sass, Gulp y npm eran desconocidos y aterradores? Lo resolveremos.
Asegurémonos de que Webpack esté “agrupando” los módulos correctamente haciendo que un archivo JavaScript defina una dependencia para que podamos importar ese fragmento de código. Primero, necesitamos instalar Webpack globalmente, que nos dará acceso a la webpack
comando en nuestros terminales:
npm install webpack -g
Una vez que haya terminado, necesitamos instalar Webpack localmente en nuestro proyecto, así:
npm i -D webpack
Ahora tenemos que hacer un index.js
archivar en un /src
directorio. Por lo general, me gusta crear un directorio donde residen todos los activos estáticos (como imágenes, fuentes, archivos CSS y marcado). Cualquier código que escriba vivirá normalmente en un /src
directorio, mientras que cualquier código escrito por una máquina o interpretado en un determinado proceso debe vivir en un /build
directorio. Mi opinión es que debería estar totalmente bien eliminar un /build
directorio y no sufrir ningún problema de ningún tipo porque simplemente podemos ejecutar un comando y procesará las cosas desde /src
directorio y reconstruir completamente el /build
directorio. En este caso, queremos que Webpack eche un vistazo a todo en /src
, realice un determinado proceso y luego mueva ese código a /build
.
En el /src
directorio también podemos agregar un vacío alert.js
archivo (volveremos a él en un minuto). También necesitaremos un webpack.config.js
archivo que se encuentra en la raíz de nuestro proyecto, fuera del /src
directorio para que la estructura de nuestro proyecto ahora se vea así:
package.json
webpack.config.js
/node_modules
/src
index.js
alert.js
Dentro de `webpack.config.js` (un archivo para configurar Webpack), podemos agregar lo siguiente:
module.exports = {
entry: './src',
output: {
path: 'build',
filename: 'bundle.js',
},
};
Siempre que ejecutamos el webpack
comando de aquí en adelante, Webpack examinará todos los activos en /src
para construir un árbol de dependencia.
Volviendo a nuestro src/index.js
archivo podemos agregar esto:
require("./alert.js");
Y dentro de nuestro alert.js
archivo podemos escribir esto:
alert("LOUD NOISES");
Ahora hagamos un index.html
archivo en nuestra raíz y agregue nuestro paquete en una etiqueta de secuencia de comandos justo antes de la <body>
cierra:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document name</title>
</head>
<body>
<h1>CSS Modules demo</h1>
<script src="https://css-tricks.com/css-modules-part-2-getting-started/build/bundle.js"></script>
</body>
</html>
Ese bundle.js
será generado por Webpack. Para generarlo todo lo que tenemos que hacer es ejecutar el webpack
mando. Para facilitarnos esto, podemos actualizar nuestro package.json
archivo con un script de compilación. Esto es lo que debería encontrar en ese archivo:
"scripts": {
"test": "echo 'Error: no test specified' && exit 1"
},
Esos son los valores predeterminados que npm
nos dio, pero podemos reemplazar lo anterior con el siguiente código para crear nuestro propio script de línea de comando que ejecutará Webpack por nosotros y abrirá una ventana del navegador:
"scripts": {
"start": "webpack && open index.html"
},
Así que cada vez que corremos npm start
ejecutaremos automáticamente el webpack
comando y abra nuestro archivo de índice en el navegador. Hagamos eso ahora y veamos qué pasa.
¡Hurra, algo está funcionando! Esto prueba que nuestro index.js
archivo está importando nuestro código de alert.js
y ese Webpack está agrupando todo correctamente. Si ahora borramos el alert.js
archivo encontraremos un error cuando ejecutamos npm start
de nuevo:
Ese es el error que revelará Webpack si no puede encontrar un módulo importado. Pero ahora que hemos confirmado que todo esto funciona, podemos descartarlo. require
declaración en nuestro index.js
y continúe con el siguiente paso para aprender sobre Webpack.
Añadiendo nuestro primer cargador
Un cargador en Webpack es realmente importante. Maxime Fabre tiene esto que decir sobre el tema:
Los cargadores son pequeños complementos que básicamente dicen “Cuando encuentre este tipo de archivo, hágalo con él”.
En el tutorial de Maxime agrega el cargador de Babel, que es un muy buen punto de partida porque Babel nos permite usar ES2015 y las últimas mejoras en el lenguaje JavaScript. Entonces, en lugar de la función Common.js que usamos anteriormente para require
otro módulo que podemos usar import
en lugar de. Con Babel también podemos usar clases, funciones de flecha y un grupo de otras características interesantes:
Herramientas como Babel nos permiten escribir nuevo código ES2015 hoy y realizar una tarea llamada transpilación (muy parecida al preprocesamiento) para convertir el código en una versión anterior de JavaScript que tenga mayor compatibilidad con el navegador. Esto es similar a cómo funciona Sass; inicialmente escribiendo su código en sintaxis Sass, y luego un preprocesador lo compila en CSS estándar.
Lo siguiente instalará el cargador de babel de Webpack y las dependencias que necesitamos para ejecutar Babel:
npm i -D babel-loader babel-core babel-preset-env
en un .babelrc
en la raíz de nuestro proyecto, podemos configurar el ajuste preestablecido para que otros sepan qué sintaxis de JavaScript usaremos:
{
"presets": ["babel-preset-env"]
}
Ahora queremos ejecutar Babel en todos nuestros .js
archivos, pero solo los archivos que escribimos, cualquier otra dependencia que instalemos más tarde puede tener su propia sintaxis y no queremos meternos con ese código. Aquí es donde entra en juego el cargador de Webpack. Podemos abrirnos webpack.config.js
archivo y reemplace ese código con esto:
module.exports = {
entry: './src',
output: {
path: 'build',
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /.js/,
loader: 'babel-loader',
include: __dirname + '/src',
}
],
}
};
Ese test
par clave / valor dentro del loaders
array es cómo le decimos a Webpack en qué tipo de archivo queremos realizar una acción mientras include
indica con precisión en qué parte de nuestro proyecto queremos que se lleve a cabo esa acción.
Probemos que Babel está funcionando junto con Webpack. En un nuevo archivo (`src / robot.js`), escribamos lo siguiente:
const greetings = (text, person) => {
return `${text}, ${person}. I read you but I’m sorry, I’m afraid I can’t do that.`;
}
export default greetings;
Este archivo JavaScript utiliza un montón de características específicas de ES2015, como export
, const
y let
, funciones de flecha y literales de plantilla.
Ahora podemos import
ese módulo en nuestro src/index.js
archivo, así:
import greetings from './robot.js'
document.write(greetings("Affirmative", "Dave"));
Finalmente, todo lo que tenemos que hacer es ejecutar npm start
nuevamente y nuestro navegador debería aparecer con el texto: “Afirmativo, Dave. Te leí pero lo siento, me temo que no puedo hacer eso “. Esto simplemente confirma que Babel está funcionando como debería.
¡Viva! Ese no es un módulo CSS todavía, aunque ciertamente estamos un paso más cerca. Pero antes de continuar, eliminemos src/robot.js
y todo el código de src/index.js
.
Cargando los estilos
Ahora que tenemos nuestras plantillas casi funcionando, necesitaremos agregar dos cargadores más: css-loader y style-loader, que instalaremos:
npm i -D css-loader style-loader
El cargador css toma un archivo CSS y lee todas sus dependencias, mientras que el cargador de estilos incrusta esos estilos directamente en el marcado. Probemos esto escribiendo algo de CSS en src/app.css
:
.element {
background-color: blue;
color: white;
font-size: 20px;
padding: 20px;
}
Entonces podemos import
esa hoja de estilo en nuestro archivo `src / index.js`:
import styles from './app.css'
let element = `
<div class="element">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur laudantium recusandae itaque libero velit minus ex reiciendis veniam. Eligendi modi sint delectus beatae nemo provident ratione maiores, voluptatibus a tempore!</p>
</div>
`
document.write(element);
¡Espera! ¿Acabamos de convertir una hoja de estilo en una dependencia de un archivo JavaScript? Demonios, sí lo hicimos. Pero antes de que funcione correctamente, y antes de que veamos por qué es útil, primero debemos reconfigurar nuestro webpack.config.js
de nuevo:
module.exports = {
entry: './src',
output: {
path: 'build',
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /.js/,
loader: 'babel',
include: __dirname + '/src',
},
{
test: /.css/,
loaders: ['style', 'css'],
include: __dirname + '/src'
}
],
}
};
Corriendo npm start
nos dejará algo como esto:
En consecuencia, si “inspeccionamos el elemento” en nuestro documento, encontraremos que el cargador de estilo ha colocado ese archivo en un <style>
etiqueta en el <head>
del documento:
Hagamos un balance de lo que acaba de suceder. Creamos un archivo JavaScript que solicitaba otro archivo CSS y luego ese código se incrustaba en una página web. Entonces, en un ejemplo más realista, podríamos crear un buttons.js
archivar y hacer buttons.css
una dependencia de él, y luego importar ese JavaScript en otro archivo que organiza nuestras plantillas y escupe algo de HTML. ¡Esto debería hacer que nuestro código sea absurdamente modular y fácil de leer!
Personalmente, solo para mantener las cosas limpias, preferiría tener un archivo CSS separado en lugar de agregar todo el código en línea. Para hacer eso, necesitaremos usar un complemento de Webpack llamado extraer texto que:
mueve cada requerimiento (‘style.css’) en trozos de entrada a un archivo de salida css separado. Por lo tanto, sus estilos ya no están integrados en javascript, sino que están separados en un archivo de paquete css (styles.css). Si el volumen total de la hoja de estilo es grande, será más rápido porque el paquete de la hoja de estilo se carga en paralelo al paquete de javascript.
Tenemos que instalar eso con npm:
npm i -D extract-text-webpack-plugin
Ahora podemos actualizar nuestro archivo `webpack.config.js` nuevamente solicitándolo y colocando nuestro cargador de CSS en él:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './src',
output: {
path: 'build',
filename: 'bundle.js',
},
module: {
loaders: [
{
test: /.js/,
loader: 'babel',
include: __dirname + '/src',
},
{
test: /.css/,
loader: ExtractTextPlugin.extract("css")
}
],
},
plugins: [
new ExtractTextPlugin("styles.css")
]
};
ExtractTextPlugin
ahora creará un archivo `styles.css` para nosotros!
Es posible que haya notado que nos hemos deshecho del cargador de estilos por completo. Eso es porque ya no queremos que esos estilos se inyecten en nuestro marcado. Así que ahora si abrimos el /build
directorio, deberíamos encontrar que un styles.css
El archivo se ha creado con todo nuestro código dentro. Y dentro de nuestro index.html
archivo, ahora podemos agregar nuestra hoja de estilo en el <head>
:
<link rel="stylesheet" href="https://css-tricks.com/css-modules-part-2-getting-started/build/styles.css">
Correr npm start
de nuevo y ¡blammo! – nuestros estilos aparecen mágicamente en la página a la que pertenecen.
Ahora que tenemos nuestro CSS y HTML funcionando en la página, ¿cómo manipulamos los nombres de las clases para obtener todos los beneficios de un ámbito local? Todo lo que tenemos que hacer es actualizar nuestro webpack.config.js
archivo así:
{
test: /.css/,
loader: ExtractTextPlugin.extract('css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]'),
}
Esto agregará el texto loco generado al final del nombre de la clase. Eso es todo lo que son realmente los módulos CSS, un hash que cambia las clases que se pueden agregar en Webpack a través de un cargador de CSS.
A continuación, tenemos que actualizar nuestro index.js
archivo con el styles.element
clase:
import styles from './app.css'
let element = `
<div class="${styles.element}">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequatur laudantium recusandae itaque libero velit minus ex reiciendis veniam. Eligendi modi sint delectus beatae nemo provident ratione maiores, voluptatibus a tempore!</p>
</div>
`
document.write(element);
¡Mira lo que pasa! Uno mas npm start
y nuestro código ahora ha sido procesado por Webpack, por lo que el alcance local ya no es un problema, ya que la clase que se inyecta en la página web ahora se ve así:
<div class="app__element___1MmQg">
...
</div>
Todavía no hemos terminado, ya que quedan muchas preguntas sin respuesta. ¿Cómo podríamos escribir código como este en desarrollo? ¿Cómo nos las arreglamos con eso? document.write
regla que estamos usando para inyectar el marcado en la página? ¿Cómo debemos estructurar nuestros módulos y archivos? Poner en funcionamiento los módulos CSS es solo la mitad del trabajo, luego tenemos que pensar en cómo podríamos portar una base de código desde otro sistema.
En el siguiente tutorial veremos cómo React puede ayudarnos a generar pequeños módulos ordenados, también veremos cómo podemos generar marcado estático a partir de una serie de plantillas y cómo agregar otras características como Sass y PostCSS a nuestro proyecto.
Serie de artículos:
- ¿Qué son los módulos CSS y por qué los necesitamos?
- Introducción a los módulos CSS (¡está aquí!)
- React + Módulos CSS = 😍