En el día a día programando en Javascript, necesitamos hacer importaciones desde diferentes ficheros, y a medida que la aplicación web o página crece, crecerá también su cantidad de ficheros y carpetas. Por lo tanto, será muy común necesitar hacer muchas importaciones.
El problema de las rutas relativas
El problema, a la hora de las importaciones suele llegar cuando tenemos que utilizar un tipo de ruta para indicar los ficheros. Como solemos trabajar a diferentes niveles de carpeta, suelen ocurrir cosas como estas:
import { getLevel } from "../levels.js";
import { Manager } from "../../components/InformationManager.js";
import { setColor } from "../../../Colors/ColorUtils.js";
Como se puede ver, las rutas están a diferentes niveles y no queda muy legible desde donde estamos obteniendo la información. Al estar trabajando en desarrollo, muchas veces las rutas que utilizamos no son las mismas en la web final, por lo que tampoco podemos utilizar rutas absolutas.
Vamos a ver varios mecanismos que tenemos a nuestra disposición, para hacer que este código de importaciones, pase a ser más legible, algo como el siguiente fragmento de código:
import { getLevel } from "@/modules/levels.js";
import { Manager } from "@/components/InformationManager.js";
import { setColor } from "@/classes/Colors/ColorUtils.js";
Como puedes ver, @/
apunta a la ruta principal de nuestra estructura de ficheros Javascript, y queda mucho más claro y legible la estructura de carpetas de esta forma.
Formas de solucionarlo
Esto se puede conseguir de varias formas, dependiendo de las herramientas que estemos utilizando. Vamos a ir comentándolas una por una, para que puedas decidir según sea tu caso, y se adapte lo mejor posible.
Lo primero es tener claras las rutas que vamos a crear. Veamos algunos ejemplos:
Alias | Ruta real |
---|---|
@/components | Acceso directo a ./src/components |
@/modules | Acceso directo a ./src/modules |
@/classes | Acceso directo a ./src/classes |
En nuestro caso, para simplificar lo máximo posible, vamos a resumirlo todo en una sola ruta ./src
, ya que la intención principal es eliminar los cambios de niveles con ../
(o similares). El desarrollador, sin embargo, puede crear las rutas que considere convenientes para su caso.
Vite es una herramienta que sirve de automatizador de tareas de desarrollo frecuentes, haciendo que escribir código sea algo mucho más cómodo, menos tedioso y más automático.
Si estás utilizando Vite para hacer frontend, puedes crear o modificar el fichero vite.config.js
e incluir o modificar la propiedad resolve
de su configuración, añadiendo las rutas que quieres utilizar. En nuestro caso, haríamos lo siguiente:
/* ... */
export default defineConfig({
/* ... */
resolve: {
alias: {
"@": new URL("./src", import.meta.url).pathname
}
},
/* ... */
});
Observa que hemos creado un alias, donde le hemos dicho que al encontrarse un @
en la ruta de una importación, lo modifique por la ruta del fichero en cuestión, que está dentro de la carpeta src
, por lo que siempre buscará a partir de ahí.
- ✅ Fácil y rápido de configurar (Sólo modificar un fichero de configuración)
- ✅ Funciona si escribes Javascript para front-end con Vite
- ❌ No funciona el autocompletado de rutas en VSCode
- ❌ Puede no servir si escribes Javascript para back-end
► En este artículo tienes más información sobre cómo empezar con Vite
Si estás utilizando Typescript en lugar de Javascript, puedes aprovechar las capacidades de Typescript para evitar los puntos negativos del apartado anterior. Sin embargo, esta modalidad requiere más configuración.
En el archivo tsconfig.json
añadimos lo siguiente:
{
/* ... */
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
}
}
}
En los paths
es donde vamos a añadir las rutas que queramos. En el punto anterior lo hacíamos en los alias
de la configuración de Vite. En este caso, lo hacemos en el fichero de configuración de Typescript, y le decimos a Vite que los lea de ahí, utilizando el plugin vite-tsconfig-paths
que habrá que instalar con npm/pnpm:
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
/* ... */
plugins: [tsconfigPaths()],
/* ... */
});
De esta forma, podemos utilizar las rutas con @/
en nuestros archivos .ts
y no necesitamos tener el apartado resolve
/ alias
en nuestro fichero vite.config.js
, ya que este plugin lo crea por nosotros.
- ✅ Funciona si escribes Javascript para front-end con Vite
- ✅ Funciona el autocompletado de rutas en VSCode
- ✅ Funciona si escribes Javascript para back-end
- ❌ Opción orientada a proyectos con Typescript (si usas JS, ver siguiente)
- ❌ Requiere más configuración y dependencias
Si no trabajamos con Typescript, no hay necesidad de complicarse ya que sigue existiendo una pequeña posibilidad de utilizar estos aliases. En lugar de tener un fichero tsconfig.json
, creamos un fichero jsconfig.json
con exactamente el mismo contenido del tsconfig.json
del apartado anterior. A grandes rasgos, es como tener un tsconfig.json
con la propiedad allowJs
a true
.
Este fichero hará que editores como VSCode puedan usar ciertas características de Typescript sin necesidad de tenerlo en el proyecto.
Por otro lado, aunque no utilicemos Typescript, necesitamos también tener instalado y configurado el plugin de vite vite-tsconfig-paths
, exactamente como en el apartado anterior.
Las ventajas y desventajas son las mismas que el anterior, sólo que en este caso si lo podemos utilizar con Javascript, aunque no utilicemos ficheros .ts
de Typescript.
Si estamos en un caso en el que no utilizamos Typescripts, y ni siquiera utilizamos un automatizador como Vite, podemos hacer uso de una característica llamada Import Maps. Se basa en crear un JSON en el index.html
a modo de índice con las librerías o rutas que queremos utilizar.
<!DOCTYPE html>
<html lang="es">
<head>
<!-- ... -->
<script type="importmap">
{
"imports": {
"@/": "/js/modules/"
}
}
</script>
<!-- ... -->
</head>
Ahora, en nuestro código, podemos escribir importaciones a esa ruta @/
ficticia, consiguiendo que importe realmente un fichero de la carpeta /js/modules/
:
import { getMessage } from "@/welcome.js";
Ten en cuenta que este caso no es equivalente a los anteriores, donde trabajabamos en desarrollo. En este caso, las rutas van a ser reales, por lo que quizás sea más interesante utilizar rutas absolutas como
/js/modules/
. No obstante, crear atajos puede ser algo interesante si tenemos rutas muy largas o queremos cambiarlas de forma transparente al desarrollo.
► En este artículo tienes más información sobre los Import Maps.