Mantener el control: una guía para Webpack y React, pt. 2

Publicado: 2022-03-11

En la primera parte de este tutorial de React-Webpack, discutimos cómo configurar los cargadores y realizar la optimización. Ahora, entraremos en técnicas más avanzadas relacionadas con casos de uso específicos de configuración de React/Webpack.

TypeScript y React con Webpack: Enter Babel

Hay varias formas en las que puede usar TypeScript en su proyecto React. Si bien ts-loader es una buena opción, me gustaría centrarme en cómo transpilar TypeScript usando @babel/preset-typescript porque muchas bibliotecas están publicando complementos de Babel para optimizar el tiempo de compilación. Además de procesar archivos TypeScript, nos permitirá usar complementos de Babel proporcionados por varias bibliotecas, como styled-components o react-intl.

Lo primero que tendremos que hacer es instalar las dependencias de TypeScript y Babel:

 npm install -D typescript @babel/preset-typescript @types/react @types/react-dom

Luego generaremos un archivo de configuración de TypeScript usando el programa de línea de comandos tsc :

 ./node_modules/.bin/tsc -init --lib dom --jsx react --isolatedModules

El comando anterior generará un tsconfig.json adecuado para escribir código para un entorno de navegador. La opción --isolatedModules impone algunas restricciones que aseguran que el código que escriba sea compatible con @babel/plugin-transform-typescript . Es útil tener esta opción para que su IDE le advierta cuando está escribiendo código de una manera que Babel no podrá transformar.

A continuación, actualizaremos babel.config.js introduciendo un nuevo ajuste preestablecido:

 @@ -6,7 +6,8 @@ module.exports = { modules: false } ], - "@babel/preset-react" + "@babel/preset-react", + "@babel/preset-typescript" ], plugins: [ "@babel/plugin-transform-runtime",

Y habilite la extensión de archivo .ts en webpack.config.js :

 @@ -11,7 +11,7 @@ module.exports = function(_env, argv) { return { devtool: isDevelopment && "cheap-module-source-map", - entry: "./src/index.js", + entry: "./src/index.tsx", output: { path: path.resolve(__dirname, "dist"), filename: "assets/js/[name].[contenthash:8].js", @@ -20,7 +20,7 @@ module.exports = function(_env, argv) { module: { rules: [ { - test: /\.jsx?$/, + test: /\.(js|jsx|ts|tsx)$/, exclude: /node_modules/, use: { loader: "babel-loader", @@ -61,6 +61,9 @@ module.exports = function(_env, argv) { } ] }, + resolve: { + extensions: [".js", ".jsx", ".ts", ".tsx"] + }, plugins: [ isProduction && new MiniCssExtractPlugin({

La configuración anterior es suficiente para poder transpilar nuestro código, pero en realidad no lo valida. Tendremos que realizar la verificación de tipos en un proceso paralelo separado usando fork-ts-checker-webpack-plugin .

Primero, necesitamos instalarlo:

 npm install -D fork-ts-checker-webpack-plugin

Luego, lo agregaremos a la sección de plugins en webpack.config.js :

 @@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require("html-webpack-plugin"); const webpack = require("webpack"); const TerserWebpackPlugin = require("terser-webpack-plugin"); const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -78,6 +79,9 @@ module.exports = function(_env, argv) { "process.env.NODE_ENV": JSON.stringify( isProduction ? "production" : "development" ) + }), + new ForkTsCheckerWebpackPlugin({ + async: false }) ].filter(Boolean), optimization: {

Especificar async: false evitará que Webpack emita código no válido y muestre errores de compilación en una superposición cuando se ejecuta un servidor de desarrollo.

Nota: También te pueden interesar las macros de Babel, que están ganando terreno.

CSS, mejorado a través de Webpack

En el artículo anterior, cubrimos el estilo básico usando css-loader . Hay varias formas en las que podemos mejorar esta configuración.

La configuración propuesta aprovechará las tecnologías CSS Modules, Sass y PostCSS. Aunque se complementan entre sí de alguna manera, no es necesario que los use todos al mismo tiempo. La configuración final tendrá todos los complementos anteriores habilitados, y dejaremos que usted deje algo fuera si está seguro de que "no lo necesitará".

Módulos CSS

Los módulos CSS abordan el problema del alcance global en los archivos CSS al generar un nombre único y aleatorio para cada clase CSS. Desde el punto de vista de un archivo JavaScript que consume un Módulo CSS, una asociación entre el nombre de la clase original y el aleatorio se representa mediante un objeto exportado por el cargador. Le permite encontrar y usar clases especificadas en un archivo CSS de una manera que hace que la colisión accidental sea casi imposible.

El soporte de módulos CSS ya está incluido en css-loader . Ahora vamos a necesitar agregar una nueva regla para que sea explícito cuándo se usan los módulos CSS:

 @@ -33,11 +33,25 @@ module.exports = function(_env, argv) { }, { test: /\.css$/, use: [ isProduction ? MiniCssExtractPlugin.loader : "style-loader", "css-loader" ] }, + { + test: /\.module.css$/, + use: [ + isProduction ? MiniCssExtractPlugin.loader : "style-loader", + { + loader: "css-loader", + options: { + modules: true + } + } + ] + }, { test: /\.(png|jpg|gif)$/i, use: {

Con eso, cualquier archivo que termine en .module.css se procesará con los módulos CSS habilitados.

PostCSS

PostCSS es un marco de procesamiento de CSS extensible con una gran biblioteca de complementos que puede usar para ampliar la sintaxis de CSS, realizar optimizaciones o proporcionar respaldos para navegadores más antiguos.

Primero, vamos a instalar las dependencias necesarias:

 npm install -D postcss-loader postcss-import postcss-preset-env

Y actualice nuestra configuración de CSS:

 @@ -47,9 +47,11 @@ module.exports = function(_env, argv) { { loader: "css-loader", options: { - modules: true + modules: true, + importLoaders: 1 } - } + }, + "postcss-loader" ] }, {

Vamos a configurar PostCSS usando los siguientes complementos:

  • postcss-import : permite que PostCSS procese declaraciones @import
  • postcss-preset-env : aplica polyfills para admitir funciones CSS modernas en la mayoría de los navegadores

Cree un archivo llamado postcss.config.js y rellénelo con lo siguiente:

 module.exports = { plugins: { "postcss-import": {}, "postcss-preset-env": {} } };

Puede consultar el directorio de complementos de PostCSS para ver otras extensiones que pueden resultarle útiles y agregarlas a su configuración.

Sass/SCSS

Sass es otro marco de procesamiento de CSS popular. A diferencia de PostCSS, Sass viene con "baterías incluidas". Fuera de la caja, Sass ofrece soporte para reglas anidadas, mixins y reglas de reescritura para compatibilidad con versiones anteriores. Si bien PostCSS tiene como objetivo preservar la sintaxis CSS estándar, la sintaxis Sass puede diferir de la especificación CSS. A pesar de esto, Sass es una solución tan ubicua que usarlo para crear CSS puede ser una opción más fácil, pero depende de sus requisitos.

Primero, vamos a instalar las dependencias necesarias:

 npm install -D sass-loader node-sass resolve-url-loader

Luego, agregue un nuevo cargador a nuestra configuración de Webpack:

 @@ -38,6 +38,25 @@ module.exports = function(_env, argv) { "css-loader" ] }, + { + test: /\.s[ac]ss$/, + use: [ + isProduction ? MiniCssExtractPlugin.loader : "style-loader", + { + loader: "css-loader", + options: { + importLoaders: 2 + } + }, + "resolve-url-loader", + { + loader: "sass-loader", + options: { + sourceMap: true + } + } + ] + }, { test: /\.(png|jpg|gif)$/i, use: {

Abordamos de manera preventiva un par de problemas con el fragmento anterior:

  1. Introdujimos resolve-url-loader después sass-loader para hacer que las importaciones relativas funcionen desde archivos @import ed Sass.

  2. Especificamos la opción importLoaders para css-loader para procesar archivos @import -ed usando los cargadores que lo siguen.

Con la configuración anterior, podemos comenzar a crear nuestros estilos utilizando Sass/SCSS además de los módulos PostCSS y CSS que describimos anteriormente. Aunque todas estas opciones se pueden habilitar simultáneamente, no tiene que usarlas todas dentro del mismo proyecto, por lo que puede elegir la herramienta que mejor se adapte a sus requisitos.

Trabajadores web

Los trabajadores web son un concepto poderoso de la web moderna. Le permite descargar cálculos costosos lejos del hilo principal. Los trabajadores web deben usarse con moderación y reservarse para cosas que no pueden optimizarse de otra manera mediante la programación inteligente dentro de un ciclo de eventos. El uso de trabajadores web es un buen candidato para optimizar operaciones sincrónicas largas.

Webpack facilita el uso de trabajadores web con worker-loader , que agrupa los archivos de trabajadores en el directorio de salida y proporciona una clase de trabajador al archivo de consumidor.

Primero, necesitamos instalar worker-loader :

 npm install -D worker-loader

Luego agréguelo a nuestro archivo de configuración:

 @@ -31,6 +31,10 @@ module.exports = function(_env, argv) { } } }, + { + test: /\.worker\.js$/, + loader: "worker-loader" + }, { test: /\.css$/, use: [

Ahora, todo lo que necesita hacer para comenzar a usar trabajadores web es crear una instancia de una clase importada desde un archivo que termina en .worker.js que implementa la API Worker ordinaria.

Trabajadores de servicios

Los trabajadores de servicio permiten técnicas avanzadas de optimización y mejoras en la experiencia del usuario. Permiten que su aplicación funcione sin conexión cuando un usuario pierde su conexión de red. También permiten que su aplicación se cargue instantáneamente incluso después de enviar una actualización.

Webpack facilita la configuración de trabajadores de servicio para su aplicación mediante el módulo workbox-webpack-plugin. Primero, necesitamos instalarlo:

 npm install -D workbox-webpack-plugin

Luego, agregaremos el complemento a la sección de plugins de nuestra configuración de Webpack:

 @@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require("html-webpack-plugin"); const webpack = require("webpack"); const TerserWebpackPlugin = require("terser-webpack-plugin"); const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); +const WorkboxPlugin = require("workbox-webpack-plugin"); module.exports = function(_env, argv) { const isProduction = argv.mode === "production"; @@ -75,6 +76,11 @@ module.exports = function(_env, argv) { "process.env.NODE_ENV": JSON.stringify( isProduction ? "production" : "development" ) + }), + new WorkboxPlugin.GenerateSW({ + swDest: "service-worker.js", + clientsClaim: true, + skipWaiting: true }) ].filter(Boolean), optimization: {

La configuración anterior utiliza las siguientes opciones:

  • swDest especifica el nombre del archivo de salida para el archivo de trabajo generado.
  • clientsClaim le indica al trabajador del servicio que tome el control de la página inmediatamente después del registro y comience a servir los recursos almacenados en caché en lugar de esperar a que se vuelva a cargar la página siguiente.
  • skipWaiting hace que las actualizaciones del trabajador del servicio surtan efecto inmediatamente en lugar de esperar a que se destruyan todas las instancias activas.

Hay una buena razón por la que las dos últimas opciones no son las predeterminadas. Cuando se habilitan simultáneamente, existe la posibilidad de que ocurran fallas en situaciones sensibles al tiempo, por lo que depende de usted tomar una decisión consciente sobre si mantener esas opciones habilitadas en su configuración.

Finalmente, debemos registrar el trabajador del servicio cuando un usuario abre nuestra aplicación:

 @@ -2,3 +2,9 @@ import React from "react"; import ReactDOM from "react-dom"; ReactDOM.render(<h3>React App</h3>, document.getElementById("root")); + +if ("serviceWorker" in navigator) { + window.addEventListener("load", () => { + navigator.serviceWorker.register("/service-worker.js"); + }); +}

Los trabajadores de servicio son capaces de mucho más que agregar capacidades fuera de línea a nuestra aplicación. Si necesita un mayor grado de control sobre el comportamiento del trabajador del servicio, puede usar el complemento InjectManifest en su lugar. Al escribir su propio archivo de trabajador de servicio, también puede habilitar el almacenamiento en caché para las solicitudes de API y utilizar otras funciones habilitadas por los trabajadores de servicio, como las notificaciones automáticas. Puede obtener más información sobre las capacidades de Workbox en la sección Recetas avanzadas de su documentación oficial.

Configuración avanzada de React Webpack: le da a su proyecto una ventaja

Esta segunda parte de nuestra serie de tutoriales de Webpack debería haberlo armado con el conocimiento necesario para ampliar su configuración de Webpack más allá de los casos de uso más generales de React. Espero que esta información le haya resultado útil y que pueda ampliar con confianza su configuración personalizada para lograr los objetivos específicos de su proyecto.

Como siempre, puede encontrar los archivos de configuración completos en GitHub y consultar la documentación de Webpack y su sección de complementos para encontrar más recetas aplicables a sus objetivos. ¡Gracias por leer!