Cargar archivos dinámicamente
En ocasiones, cuando necesitamos importar varios archivos de una carpeta (por ejemplo, imágenes, íconos o módulos), resulta poco práctico tener que importarlos uno por uno. Para resolverlo, Webpack nos ofrece la función require.context, una herramienta poderosa, ya que permite crear contexto dinámico de importación para todos los archivos dentro de una carpeta específica, sin necesidad de importarlos uno por uno.
¿Qué hace require.context?
En Webpack require.context es una función que permite crear un “contexto dinámico” para importar múltiples módulos a la vez desde de una carpeta o directorio específico (incluso dentro de subcarpetas). A diferencia de las importaciones estáticas de (ES6) (ES6) ES6, también conocido como ECMAScript 2015, es la sexta versión del estándar ECMAScript, en el cual se basa el lenguaje de programación JavaScript , que requiren que declares explícitamente cada archivo.
Sintaxis Básica:
1
2
3
4
5
require.context(
directory, // ¿Dónde buscar?
recursive, // ¿Buscar en subcarpetas?
pattern // ¿Qué archivos buscar?
);
directory: La ruta relativa a la carpeta donde Webpack debe buscar los archivos.recursive: Un valor booleano (trueofalse) que indica si Webpack debe buscar en las subcarpetas dentro dedirectory.pattern: Una expresión regular que define los archivos que deben ser incluidos (por ejemplo,\.js$para todos los archivos JavaScript).
Iniciar con el starter template
Para explorar el uso de require.context, vamos a utilizar un template preconfigurado que incluye toda la configuración básica necesaria de webpack:
Una vez creado el nuevo repositorio, clónalo en tu equipo local y luego instala las dependencias necesarias para el proyecto:
1
npm install
Finalizada la instalación, corremos el servidor de desarrollo:
1
npm run dev
A continuación, puedes reproducir el video y revisar cómo configurar el starter template:
Casos prácticos para require.context
1. Galería de imágenes
Lo primero es abrir el proyecto con VS Code, o con el editor de tu preferencia. Al hacerlo, notarás que dentro de la carpeta src existe una subcarpeta llamada assets. Ahí es donde puedes agregar las imágenes que desees utilizar para la galería.
En la carpeta
config/se encuentra el archivowebpack.common.jsy verás que tenemos configurado el Asset Module tanto para el entorno de desarrollo como para producción. Esto es necesario para poder cargar imágenes correctamente en el proyecto.![]()
Si quieres usar las mismas imágenes que se muestran en este ejemplo, puedes descargarlas directamente desde el siguiente enlace y colocarlas dentro de src/assets/tech-logos:
Una vez que tengas las imágenes en tu proyecto, asegúrate de que la estructura de carpetas quede así:
Ahora que tenemos las imágenes de los logos en la carpeta src/assets/tech-logos-svg. El siguiente paso será crear una función que importe automáticamente esos archivos sin tener que escribir una importación por cada archivo. Dentro de la carpeta src, crea un nuevo archivo llamado gallery.js y escribe o copia el siguiente código
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
export function Gallery() {
// Creamos el contenedor donde mostraremos las imágenes
const galleryContainer = document.createElement('div');
/**
* require.context(directorio, incluirSubdirectorios, expresiónRegular)
*
* - directorio: ruta relativa desde el archivo actual
* - incluirSubdirectorios: si se deben explorar carpetas dentro de la ruta
* - expresiónRegular: patrón para coincidir con los archivos deseados
*/
const logosContext = require.context('./assets/tech-logos-svg', false, /\.svg$/);
// Obtenemos un array con las rutas procesadas por Webpack
const logos = logosContext.keys().map(logosContext);
// Recorremos cada imagen y la insertamos en el contenedor
logos.forEach(src => {
const img = document.createElement('img');
img.src = src; // Ruta de la imagen procesada por Webpack
img.alt = 'Tech logo'; // Texto alternativo para accesibilidad
img.style.width = '100px';
img.style.margin = '10px';
img.style.objectFit = 'contain';
img.style.transition = 'transform 0.2s ease';
// Efecto visual simple al pasar el mouse
img.addEventListener('mouseenter', () => img.style.transform = 'scale(1.1)');
img.addEventListener('mouseleave', () => img.style.transform = 'scale(1)');
galleryContainer.appendChild(img);
});
return galleryContainer;
}
El resultado puede variar según los estilos que tengas definidos, pero lo importante es que ya contamos con la funcionalidad completa: las imágenes se cargan automáticamente desde la carpeta assets/tech-logos-svg gracias a require.context, sin necesidad de escribir código adicional o modificar rutas manualmente cada vez que se agregan nuevos archivos.
2. Generador de sitio estático
Supongamos que estás escribiendo un generador de sitios estáticos simple, donde el contenido se organiza en archivos Markdown. La idea es poder cargar automáticamente todos los archivos .md de una carpeta y convertirlos en secciones HTML, sin tener que importar cada archivo manualmente.
Podrías modelar el contenido de tu sitio dentro de una estructura de directorios, creando un directorio .pages/ que contenga los archivos Markdown.
1
2
3
4
5
6
7
8
src/
├─ assets/
├─ pages/
│ ├─ intro.md
│ ├─ webpack-tips.md
│ └─ about.md
├─ index.js
└─ markdownLoader.js
Antes de continuar, es necesario que instalemos y configuremos otros 2 loaders:
1
npm install --save-dev html-loader markdown-loader
markdown-loader: convierte Markdown en HTML.html-loader: permite que Webpack importe HTML como módulos JS.
Y ahora añadimos la siguiente regla:
Siguiendo con la estructura del starter template, añadelo en
config/webpack.common.jsque corresponde a las configuraciones que comparten ambos entornos.
1
2
3
4
5
6
7
{
test: /\.md$/,
use: [
{ loader: 'html-loader' },
{ loader: 'markdown-loader' }
]
}
Cada uno de estos archivos tendría un (front matter) (front matter) Sección de metadatos que aparece al principio de un archivo para sus metadatos. La URL de cada página podría determinarse a partir del nombre del archivo y mapearse. Para modelar la idea usando require.context, se podría considerar la siguiente estructura propuesta en el previsualizador de archivos:
# Introducción
Bienvenido a este sitio generado dinámicamente con Webpack y require.context.
# Acerca de
Este es un ejemplo educativo para entender cómo cargar archivos Markdown automáticamente.
.markdown-list {
padding: 20px;
max-width: 700px;
margin: auto;
}
.markdown-list h1 {
color: #003547;
margin-bottom: 10px;
}
.markdown-list section {
border-bottom: 1px solid #ddd;
margin-bottom: 20px;
padding-bottom: 10px;
}
// Carga todos los archivos Markdown desde /content
const markdownFiles = require.context('./content', false, /\.md$/);
export default function MarkdownLoader() {
const container = document.createElement('div');
container.classList.add('markdown-list');
markdownFiles.keys().forEach((path) => {
const section = document.createElement('section');
const content = markdownFiles(path);
section.innerHTML = content.default || content;
container.appendChild(section);
});
return container;
}
import './styles/markdown.css';
import MarkdownLoader from './markdownLoader.js';
const root = document.querySelector('#root');
root.appendChild(MarkdownLoader());
const { merge } = require('webpack-merge');
const common = require('./webpack.common');
/** @type {import('webpack').Configuration} */
const devConfig = {
mode: 'development',
devtool: 'eval-source-map',
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
],
},
devServer: {
hot: true,
open: true,
port: 4000,
}
};
module.exports = merge(common, devConfig);
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/** @type {import('webpack').Configuration} */
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, '../dist'),
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: 'asset/resource',
},
{
test: /\.md$/,
use: [
{ loader: 'html-loader' },
{ loader: 'markdown-loader' }
]
}
]
},
resolve: {
extensions: ['.js', '.json'],
}
}
const { merge } = require('webpack-merge');
const common = require('./webpack.common');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
/** @type {import('webpack').Configuration} */
const prodConfig = {
mode: 'production',
devtool: 'source-map',
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
};
module.exports = merge(common, prodConfig);
<!doctype html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Generador de sitio estático</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Selecciona un archivo para ver su contenido
En resumen:
require.contextes una característica avanzada que a menudo está oculta tras bastidores. Úsala si necesitas realizar búsquedas entre un gran número de archivos.- Una importación dinámica escrita de cierta forma genera una llamada a
require.context. En este caso, el código se lee un poco mejor. - Estas técnicas funcionan únicamente sobre el sistema de archivos. Si necesitas operar sobre URLs, deberías considerar soluciones del lado del cliente.






