Qwik — Integrar Bootstrap

Claves para poder integrar Bootstrap en nuestros proyectos de Qwik

Anartz Mugika Ledo🤗
11 min readMay 8, 2023

Comenzamos con un nuevo artículo en el que vamos a aprender a hacer paso a paso la integración de la librería Bootstrap en Qwik.

Veremos paso a paso lo que tenemos que ir haciendo, las claves para poder configurarlo, visualizar los problemas a la hora de configurarlo de una manera u otra (sirviendo como conocimiento para otras integraciones de librería de cliente) y etc.

Con esto ya podremos trabajar 100% en Bootstrap sin ningún problema.

Os recomiendo leer los artículos anteriores en orden y si practicáis, ¡¡mucho mejor!!.

Recordad, que si hay dudas, aun leyéndolo, podéis preguntarlo en los comentarios y sin dudas me gustaría que me comentéis también, para tener feedback.

Todos los artículos publicados del curso los encontraréis en la siguiente lista que iré actualizando semanalmente y estableciendo el orden natural recomendado:

Qwik paso a paso desde 0 al detalle

23 stories

La versión usada para el artículo es la versión 0.1.0 de Qwik (2023–05–07), puede que hayan cambios y por eso, si hubiese algo que consultar, os recomiendo ir a la documentación oficial.

Índice de contenidos

A continuación os muestro los puntos principales de lo que vamos a trabajar en este artículo.

  • Crear el proyecto
  • Instalación de Bootstrap
  • Añadir referencia de estilos de Bootstrap
  • Implementando Navbar y comprobando si su funcionamiento es correcto
  • Adaptando el contenido de la cabecera de Qwik
  • Extra — Personalizar Navbar
  • Conclusión

Crear el proyecto

Ejecutamos el siguiente comando aplicando la selección de la versión estable, la 1.0.0.

npm create qwik@1.0.0

(Actualmente es la más reciente)

También podéis trabajar desde la base de este proyecto que tengo preparado en el repositorio que usaré para trabajar lo que tenemos en este contenido y mostrar el resultado final.

https://github.com/Qwik-Spanish/qwik-app-bootstrap/tree/00-start

En este proyecto ya tendré quitada la información extra como componentes que no vamos a usar y como podréis ver, la página principal está más limpia con la siguiente apariencia:

Sabiendo esto, elegís con que queréis trabajar. Voy a comenzar con el proceso de integrar Bootstrap que es el objetivo final del artículo.

Instalación de Bootstrap

Vamos a instalar la versión 5 de Bootstrap y todo lo que ya se trabaje en el artículo, seguirá la referencia de esta versión que podréis encontrar en este enlace. Añadimos las dependencias de producción:

npm install bootstrap@5

Y los ahora los @types, necesarios para trabajar con Typescript, los añadimos con dependencias de desarrollo:

npm install -D @types/bootstrap@5

Añadir referencia de estilos de Bootstrap

Para poder trabajar con los componentes y elementos de Bootstrap, aplicando sus estilos, debemos de añadir la referencia del fichero CSS del paquete Bootstrap que acabamos de instalar.

Para hacer lo siguiente, debemos de ir dentro del proyecto al fichero root.tsx dentro de src y eliminar la referencia al CSS del fichero global.css que es lo que tienen los estilos globales que vienen por defecto con el proyecto de Qwik (y borrar el fichero aunque si queremos modificarlo, dejamos para futuros usos)

// import './global.css';

Añadimos la referencia de los estilos de Bootstrap

import './../node_modules/bootstrap/dist/css/bootstrap.min.css';

Ahora vamos a src/routes/styles.css y eliminamos todo el contenido (no eliminaría el fichero para añadir en el futuro nuevos estilos).

Ahora tenemos esta apariencia:

Ahora ya se están aplicando los estilos de Bootstrap, y podemos estructurar contenedores, añadir componentes como botones, menús de navegación,…

Como se puede apreciar los enlaces no se ven y tendremos que ir haciendo algunos ajustes provisionales para saber que está ahí el contenido.

En este caso, para que se vean los enlaces, añadimos esta regla en src/routes/styles.css, que será algo que ponemos provisionalmente, antes de empezar a usar las clases de Boostrap:

a, ._anchor_1g8hj_1 {
color:darkcyan !important
}

Y ahora guardando los cambios, podemos ver el contenido completo que tenemos:

Con esto, ya podemos empezar a trabajar con ello.

Como algunos de estos componentes están usando funciones de Javascript, debemos de comprobar que su funcionamiento es el correcto y un buen ejemplo para comprobar que se asigna bien la funcionalidad de Javascript de Bootstrap es haciendo con un menú de navegación (Navbar).

Implementando Navbar y comprobando si su funcionamiento es correcto

Modificaremos el apartado de la parte superior y vamos a personalizarlo usando Bootstrap y con estos enlaces que tenemos actualmente ahora en el componente Header, que lo encontramos en src/components/starter/header/index.tsx

Dentro de la documentación accedemos al apartado de componentes (Components) y seleccionamos Navbar y estaremos en la documentación para añadir el Navbar, se verá algo similar a esto (puede variar, pero no creo que mucho).

Ahora en la parte derecha, donde pone On this page, dentro de Responsive behaviours seleccionamos Toggler

Vamos al proyecto a src/components/starter y creamos un nuevo componente llamado que será el navbar (crear directorio navbar y luego fichero index.tsx), similar al header pero usando este código que hemos copiado y quitamos el selector del form y su contenido, ya que no me interesa:

import { component$ } from '@builder.io/qwik';
export default component$(() => {
return (
<nav class='navbar navbar-expand-lg bg-body-tertiary'>
<div class='container-fluid'>
<button
class='navbar-toggler'
type='button'
data-bs-toggle='collapse'
data-bs-target='#navbarTogglerDemo01'
aria-controls='navbarTogglerDemo01'
aria-expanded='false'
aria-label='Toggle navigation'
>
<span class='navbar-toggler-icon'></span>
</button>
<div class='collapse navbar-collapse' id='navbarTogglerDemo01'>
<a class='navbar-brand' href='#'>
Hidden brand
</a>
<ul class='navbar-nav me-auto mb-2 mb-lg-0'>
<li class='nav-item'>
<a class='nav-link active' aria-current='page' href='#'>
Home
</a>
</li>
<li class='nav-item'>
<a class='nav-link' href='#'>
Link
</a>
</li>
<li class='nav-item'>
<a class='nav-link disabled'>Disabled</a>
</li>
</ul>
</div>
</div>
</nav>
);
});

Cogemos y lo añadimos dentro de src/routes/layout.tsx sustituyendo el componente Header. Pasamos de esto:

import { component$, Slot, useStyles$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';

import Header from '~/components/starter/header/header'; // <== Esto se elimina
import Footer from '~/components/starter/footer/footer';

....

export default component$(() => {
useStyles$(styles);
return (
<>
<Header />
<main>
<Slot />
</main>
<Footer />
</>
);
});

A lo siguiente:

import { component$, Slot, useStyles$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';

import Footer from '~/components/starter/footer/footer';
import Navbar from '~/components/starter/navbar'; // <==== ESTO SE AÑADE

...

export default component$(() => {
useStyles$(styles);
return (
<>
<Navbar />
<main>
<Slot />
</main>
<Footer />
</>
);
});

Cuyo resultado será el siguiente:

Adaptando el contenido de la cabecera de Qwik

Antes de probar la funcionalidad, de si funciona bien o no, vamos a añadir el contenido con los enlaces originales.

Donde pone Hidden Brand cambiamos este código (dentro de src/components/starter/navbar:

<a class="navbar-brand" href="#">Hidden brand</a>

A esto, añadiendo el componente con el icono original de Qwik con estos valores:

<a class="navbar-brand" href="#">
<QwikLogo height={40} width={100} />
</a>

Ahora lo tenemos así:

Añadimos los enlaces cambiando de aquí:

<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">
Home
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">
Link
</a>
</li>
<li class="nav-item">
<a class="nav-link disabled">Disabled</a>
</li>
</ul>

A lo siguiente (cogiendo los enlaces del componente Header):

<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a
class="nav-link active"
aria-current="page"
href="https://qwik.builder.io/docs/components/overview/"
target="_blank"
>
Docs
</a>
</li>
<li class="nav-item">
<a
class="nav-link"
href="https://qwik.builder.io/examples/introduction/hello-world/"
target="_blank"
>
Examples
</a>
</li>
<li class="nav-item">
<a
class="nav-link"
href="https://qwik.builder.io/tutorial/welcome/overview/"
target="_blank"
>
Tutorial
</a>
</li>
</ul>

Mostrándose el siguiente resultado (podéis probar haciendo click en cada uno de ellos, debería de abrirnos una nueva pestaña):

Probamos y el menú responsive funciona, es decir, que se muestra el botón de hamburguesa (Toggler), cuando hacemos más pequeña la ventana de nuestra aplicación de Qwik mediante la herramienta para visualizar en diferentes resoluciones.

Si hacemos click sobre el botón para que se expandan las opciones de dicho menú (como esta señalado)

Al hacer click, podemos observar QUE NO FUNCIONA. Es lógico, este menú funciona con bootstrap (mediante las llamadas de funciones Javascript de la librería que NO estamos usando) y lo único que estamos usando actualmente es el apartado de estilos que hemos configurado al principio del artículo.

Usar funciones Javascript de Bootstrap en Qwik

En este caso, si vamos a trabajar solo con componentes que vamos a usar para distribuir lo que es el contenido de los contenedores, usar componentes que son de visualización,… con los estilos sería más que suficiente

Si vamos a trabajar con opciones como Acordion, el menú responsive y demás, si necesitamos el apartado de código de Javascript de la librería.

Vale, ¿Pero como solucionamos esto? Solo debemos de importar sus dependencias, y para que esté disponible en toda la aplicación, lo haremos en el fichero src/root.tsx y debemos de realizarlo dentro de la función useVisibleTask$ dentro del componente inicial, ya que bootstrap al ser una dependencia que trabaja en el navegador y requiere de elementos como window, document y estos solo se usan en el navegador, cuando esté listo, debemos de añadirlo ahí.

El hook useVisibleTask$ nos va a permitir ejecutar código una vez que el cliente se haya cargado. Si no está cargado, no se ejecuta y cuando lo esté ya tendremos acceso a por ejemplo window o document.

De manera opcional, al igual que useTask$, podemos pasarle el parámetro track, para poder ejecutar el código de dentro, por cambios que se den en ese valor que estemos observando. Esto lo explicaré en un artículo próximo con más detalle, tengo ganas de explicar bien las funciones useTask$ y useVisibleTask$

Os voy a mostrar un ejemplo de lo que no hay que implementar para que funcione, pero que seguramente os habéis planteado hacerlo así.

Siempre pienso que es bueno enseñar también las cosas que NO SE DEBEN de hacer con sus argumentos, para que si nos enfrentamos a un problema así, sepamos como actuar.

Añadiendo el import fuera del componente (component$) como se haría normalmente:

import { component$ } from '@builder.io/qwik';
....
import { RouterHead } from './components/router-head/router-head';

// import './global.css';
import './../node_modules/bootstrap/dist/css/bootstrap.min.css';

import 'bootstrap'; // <== Esto es lo que debemos de añadir, pero aquí da error!

export default component$(() => {
...
);
});

Nos va a dar el siguiente error donde nos dice que document no está definido (document is not defined) y obviamente, esto es porque no hemos llegado al ciclo de vida de que este elemento esté preparado (el navegador preparado) y como requiere de ello, al no tenerlo, salta ese error.

Para solucionarlo, vamos dentro del componente y añadimos la función useVisibleTask$ con el import dentro de esta:

import { component$, useVisibleTask$ } from '@builder.io/qwik';
....

// import './global.css';
import './../node_modules/bootstrap/dist/css/bootstrap.min.css';

// import 'bootstrap'; <=== Esto lo quitamos

export default component$(() => {
/**
* Aquí añadimos la función que pertenece al ciclo de vida para decir
* que el navegador y sus elementos están disponibles
*/

useVisibleTask$(async () => {
// Hasta que no esté el navegador no intentará cargarlo
await import('bootstrap');

// En este punto, como document está listo, podemos trabajar con el DOM
// por ejemplo entre otras cosas que ya sería en el cliente
})

return (
<QwikCityProvider>
...
</QwikCityProvider>
);
});

Esto que habéis visto de introducirlo dentro de la función useVisibleTask$ es necesario para casos que vamos a usar librerías de cliente como Bootstrap, Leaflet,… Podría darnos en vez de document is not defined también window is not defined, para que lo tengáis en cuenta si os aparece, para que sepáis por donde tirar.

Volvemos a refrescar y se elimina el error, visualizándose el contenido como antes y supuestamente funcionando que se solape el menú:

¿Será suficiente esto para que funcione el botón del menú? Vamos a ver, hacemos click sobre dicho elemento:

Y como podréis observar, ¡¡ahora si funciona!!

Con esta configuración ya podemos trabajar al 100% con Bootstrap, con sus componentes, contenedores y otros aspectos como el uso de colores predefinidos.

En este punto, teniendo Bootstrap al completo operativo y con vuestros conocimientos y usando la documentación, podréis trabajar perfectamente y volveros loc@s haciendo interfaces chulas y elegantes.

Personalizar Navbar

Vamos a darle un poco de estilo del navbar, pintarlo de otro color y estos cambios los hacemos en base a esta referencia (esto ya son cambios que podéis hacer bajo vuestro criterio, que cada persona tenemos el nuestro).

Este cambio no es indispensable, lo importante ya hemos completado para poder trabajar con la librería al 100% y esto es un extra

En este apartado con las opciones de los colores, nos dan 3 ejemplos:

  1. Color predefinido para navbar oscuro.
  2. Color predefinido para navbar primario, en este caso color claro.
  3. Color personalizado, añadiendo mediante al atributo style el color de fondo que deseemos mediante background-color.

Voy a añadirle un color personalizado, un tono tipo turquesa (uso este generador de código hexadecimales), que sería este código de referencia:

#37D5AB

Añadimos al navbar, la propiedad del estilo con el color de fondo:

<nav
class="navbar navbar-expand-lg bg-body-tertiary"
style="background-color: #37D5AB"
>
...
</nav>

Y ahora el color de fondo cambiará a lo siguiente:

Ahora con este color de fondo, quizás es mejor añadir el texto en un tono más claro y eso hacemos añadiendo la clase navbar-dark dentro del selector nav (Recordad, todo lo que saco está en la documentación, experimentarlo)

<nav
class="navbar navbar-expand-lg bg-body-tertiary navbar-dark"
style="background-color: #37D5AB"
>
...
</nav>

Y en src/routes/styles.css, dejamos de esta forma, eliminando el elemento a con el color verde, dejando el del pie de página que seguramente tengamos que eliminar a posteriori, por ir haciendo más cambios, cosa que ya tendréis que hacerlo por vuestra cuenta:

._anchor_1g8hj_1 {
color:darkcyan !important
}

Quedando de la siguiente forma:

Y como en este artículo el objetivo es poder trabajar con Bootstrap en Qwik y ya se ha mostrado en los pasos anteriores con este extra, doy por finalizado el artículo, hasta el siguiente.

Conclusión

Y llegados a este punto, se podría decir que ya sabemos integrar y utilizar en Qwik la librería Bootstrap

Hemos aprendido la forma de identificar el problema que da si no usamos useVisibleTask$() para este caso y para futuros problemas que podamos tener usando librerías que se ejecutan en cliente.

Llevamos aprendido muchísimo, os animo a que repaséis si hiciese falta.

Me gustaría que en los comentarios dejaseis resultados de cosas que vayáis practicando, ya que cuanta más variedad, todo el mundo nos beneficiamos de ello.

Todos los artículos publicados del curso los encontraréis en la siguiente lista que iré actualizando semanalmente y estableciendo el orden natural recomendado:

Qwik paso a paso desde 0 al detalle

23 stories

Resultado del proyecto

https://github.com/Qwik-Spanish/qwik-app-bootstrap/tree/01-finish-article

Presencia en redes sociales

Podéis encontrarme en las siguientes redes.

--

--

Anartz Mugika Ledo🤗

[{#frontend:[#mobile:{#android, #kotlin, #ionic}}, {#web:{#angular, #qwik, #bootstrap}}],{#backend: [{#graphql, #nestjs,#express, #mongodb, #mysql}]}]