Qwik: Primeros pasos y nociones básicas

Después de presentarme y hablaros de lo que vamos a ir aprendiendo sobre Qwik a lo largo del libro, necesitamos empezar desde un punto inicial y que mejor que hacerlo con una breve introducción para hablar de lo que es Qwik, sus características principales y que nos ofrecerá este Framework que no puedan ofrecer opciones como otras tecnologías Javascript que podrían ser Angular, React, Vue,…

En esta comparativa es donde encontraremos el concepto de la hidratación (se da en Angular, React, Vue, etc.), que es uno de los responsables de ralentizar nuestras aplicaciones y vamos a ver como Qwik evita ese proceso, el de la hidratación, aumentando el rendimiento de nuestras aplicaciones.

Una vez realizada la introducción y teniendo claro más sobre lo que es Qwik con sus características, vamos a crear el primer proyecto de una aplicación de Qwik, paso a paso donde vamos a ver los detalles de su estructura principal y organización para conocer todos los detalles que componen un proyecto con este Framework.

El objetivo será dar los primeros pasos mientras extraemos los primeros conocimientos que nos servirán para ir haciendo proyectos pequeños con el objetivo de ir asimilando e interiorizando todos los conceptos que vayamos viendo durante el libro.

Contenido del capítulo

Introducción a Qwik

Se han creado muchos frameworks / librerías de JavaScript para resolver problemas de carga lenta a lo largo de los años, y la mayoría de ellos intentan resolver el mismo problema de cargas sin mucho éxito. En lo que respecta al rendimiento podemos afirmar que no han llegado a buen puerto partiendo desde el objetivo inicial que buscaban.

Actualmente, los sitios web están enviando JavaScript al navegador para proporcionar interactividad y la cantidad de JavaScript que se descarga en el navegador aumenta y aumenta, haciendo que la velocidad de procesamiento sea cada vez más lenta, sobre todo a medida que aumenta la complejidad de estos sitios web con el tiempo.

La mayoría de los frameworks / librerías de JavaScript descargan y ejecutan todo el código a la vez. ¿Qué ocurre con esto? Estamos descargando el código de todas las funcionalidades y puede que solo vamos a usar una o un par de ellas, con lo que estaremos gastando recursos por no descargar únicamente lo que necesitemos.

El tiempo de carga será cada vez más lento, ya que el tiempo de carga será O(n).

Los creadores de Qwik afirman que mediante este Framework se puede solucionar este problema que otros frameworks / librerías no pueden solucionar. Después de varios años de duro trabajo, el framework ha superado la etapa beta y ahora está disponible la primera versión estable, desde principios de mayo del 2023.

¿Qué es Qwik?

Es un nuevo tipo de framework que representa un árbol de componentes y como resultado nos dará una aplicación interactiva de tipo frontend, que hace posible que las aplicaciones web de cualquier tamaño o complejidad se carguen instantáneamente con cargas ultrarrápidas y se ejecuten de la misma manera a cualquier escala.

Su objetivo principal es descargar de manera perezosa o diferida (Lazy Loading) el código a medida que el usuario interactúa.

Su objetivo es tener aplicaciones instantáneas, incluso en dispositivos móviles solo con lo necesario, ni más ni menos.

Funcionamiento y estrategias usadas en Qwik para un mejor rendimiento

Ahora analizamos con más detalle estas estrategias, para entender mejor su funcionamiento.

Retrasar ejecución y descarga

Retrasa la ejecución y la descarga de JavaScript (excepto el código de inicio, alrededor de 1KB que es lo imprescindible en Qwik para poder iniciarse) durante el mayor tiempo posible, retrasando la ejecución de cualquier otro Javascript en la página hasta que sea necesario.

Con esto se conseguirá eliminar la hidratación dada en otros frameworks / tecnologías de Frontend como Angular, React,…

La hidratación puede tardar varios segundos, dependiendo de la complejidad de tu aplicación y de la velocidad del dispositivo móvil. Las aplicaciones de Qwik son instantáneamente interactivas incluso en dispositivos móviles lentos, lo que lleva a una puntuación perfecta de Google PageSpeed algo que nos beneficiará mucho.

Su tiempo de carga es O(1), mejorando mucho el O(n) de tecnologías Javascript como Angular, React,… mencionadas anteriormente.

Qwik no es React, aunque se parece mucho a React, y utiliza JSX. Ofrece el tiempo de carga de página más rápido posible, independientemente de la complejidad del sitio web que se está ejecutando. Aparte de ser muy similar a React, podemos trabajar con componentes de React originales en Qwik. Este aspecto lo veremos más adelante en el apartado de integraciones en el que os mostraré lo indispensable para poder hacerlo, paso a paso.

¿Qué es la hidratación?

Leyendo esta primera estrategia para llegar al objetivo de ser más eficientes en las cargas, encontramos un nuevo concepto que es la de eliminar la hidratación, proceso que se da en Qwik.

Según la definición en Wikipedia (Buscad "Hydratation (Web development)" ) enfocada al desarrollo web:

La hidratación es tal y como funcionan tecnologías como Angular, Vue y React (entre otras opciones) donde es una técnica de Javascript dada en lado de nuestro cliente donde se ejecuta una descarga de todo nuestro bundle completo, luego se efectúa una pequeña ejecución de nuestro Javascript para finalizar añadiendo los listeners como las acciones tipo onClick y similares. Seguramente en más de una ocasión, muchas de las cosas descargadas no se usan y eso hace que su descarga se considere inútil.

Se reflejaría ese proceso en la siguiente imagen:

Este proceso no se da en Qwik (si en Angular, React, Vue,…), esto se elimina, con la descarga de lo necesario a medida de nuestras necesidades, ni más ni menos.

Resumabilidad (Resumability)

La capacidad de reanudación (Resumability) permite que las aplicaciones de Qwik continúen ejecutándose donde las dejó el servidor.

Todos los frameworks / tecnologías deben realizar un seguimiento de las estructuras de datos internas sobre el estado de la aplicación para proporcionados la información que estamos requiriendo, como un formulario de contacto, nuestro catálogo de proyectos, etc.

La generación actual de frameworks / tecnologías no conservan esta información cuando se realiza la transición del servidor al navegador.

Como resultado, las estructuras de datos del marco deben reconstruirse en el navegador, duplicando el trabajo que se realizó en el servidor. La reconstrucción de las estructuras de datos y la conexión de los oyentes se denomina hidratación y esto es lo que evita Qwik.

Ejemplos de Resumability:

  • CD / Casette (lo mismo podía ser con DVD / VHS) : Muy bien explicado por parte de Bezael Pérez (Domini Code) en este punto de su introducción a Qwik (recomendado para complementar con los conocimientos de este capítulo del libro donde muestra algunos aspectos con más detalle)

  • Videos de Youtube (con login y sin login): Si accedemos a un navegador sin loguearnos, vemos un video concreto, dejando este en el 02:02 por poner un ejemplo y pasamos a otro equipo. Seleccionamos el mismo video, pero nos empieza desde el principio, como el CD. En cambio, si lo hacemos logueados y accedemos con esa misma cuenta en otro equipo, empezaremos ese video en el punto que lo hemos dejado.

En resumen, esto es lo que hará el resumability:

El proceso que se da en el resumability desgranando el proceso en el código su funcionamiento será el siguiente:

  • Fase 1: Añadimos el código y las funcionalidades necesarias en nuestro componente a renderizar.

  • Fase 2: Se codifica el path de código Javascript en nuestro HTML y ya desde ahora, no tendremos necesidad de descargarlo en nuestro navegador después de la primera descarga. En este caso aplica el proceso de Lazy Loading.

  • Fase 3: Es la porción de código que podremos ver después del proceso de “juntar todo” el HTML con el Javascript en modo Lazy Loading siempre que tengamos la necesidad de usarlo. Si no vamos a usar por ejemplo la interacción de ese botón, no descarga esa información.

Finalizando con este punto, estas serán las diferencias entre usar la hidratación o no:

Serialization (Serialización)

Qwik serializa los listeners, las estructuras de datos internas y el estado de la aplicación en el HTML durante la transferencia del servidor al navegador. Debido a que toda la información se serializa en HTML, el cliente puede reanudar la ejecución donde la dejó el servidor.

Recordad el ejemplo del Casette con Qwik (que empieza donde lo hemos dejado) y CD con Angular, React,… que empieza desde el inicio al iniciarlo en otro equipo, o en el mismo después de haberlo reiniciado.

Aplicándolo en el código, podemos observar el proceso de serialización. Por ejemplo, en este contenido se muestra un ejemplo sencillo en el que se define un botón con una acción de click:

Si entramos en los elementos dentro del inspector de elementos, podemos observar como está serializando ese fichero en un string, con un identificador único, para poder retornar posteriormente y hacer uso de ese código asociado a esa línea en el caso de retornar y usar ese código en esta misma página u otras páginas que hacen uso de una misma función.

Y accediendo en ese fichero, vemos la referencia usada para marcar esa referencia mediante la serialización como si fuese el minuto y segundo concreto de lo que sería una cinta de casette o video VHS:

Viendo estas estrategias, sacamos estas principales conclusiones a favor de Qwik:

  • Carga cero: NO hay hidratación porque es resumible.

  • Carga perezosa (Lazy Loading): No hay que preocuparse de ello, ya que Qwik se ha construido alrededor de la carga perezosa como su núcleo primitivo, haciendo que el desarrollador se ahorre este proceso de optimización y solo descargaremos lo que vayamos a usar, ni más ni menos.

  • Renderización reducida: Reactividad que permite reducir la cantidad de código de renderizado descargado y ejecutado. El código se construye en el servidor y se restaura en el cliente sin necesidad de que el código de la aplicación esté presente y se vuelva a ejecutar.

  • Escabilidad: Proporcional a la complejidad de la interacción con el usuario, no al tamaño de todos los componentes de la ruta actual. El rendimiento no se altera aunque vaya creciendo en complejidad la aplicación.

  • Codificar una vez.

Llegados a este punto, ya sabemos las diferencias que trae respecto a tecnologías como Angular, React, Vue,…

Vamos a comenzar con el proceso básico de crear un proyecto y analizaremos su estructura principal con sus ficheros y configuraciones para entender más el proceso inicial para dar nuestros primeros pasos en Qwik. Así podemos ir comprobando todo lo que os he hablado de sus ventajas y su funcionamiento básico.

Comenzando a trabajar con Qwik

Requisitos del sistema

Tal y como os habrá ocurrido siempre que habéis empezado a trabajar con otros frameworks y con JavaScript en general, tenemos que tener en cuentas unos requisitos mínimos para poder trabajar en esa tecnlogía y Qwik no es una excepción. ¿Qué necesitamos para empezar?

Una vez que ya tenemos los requisitos mínimos cubiertos seguimos.

Trabajando con el CLI de Qwik y creación del proyecto

No necesitamos instalar nada, ya que usando la herramienta CLI con la que Qwik viene, esta nos ayudará a montar nuestra aplicación de una manera muy sencilla en unos pocos pasos.

Información a tener en cuenta

La herramienta del CLI la podemos encontrar en el siguiente enlace (por si tenéis curiosidad): https://shorten-up.vercel.app/j3WbcOI6Vq

Para crear nuestra aplicación debemos de ejecutar el siguiente comando:

// En mayo del 2023 se ha publicado la versión estable 1.0.0 
// y en este caso se trabajará en base a la más actual que es la 1.5.1(abril 2024)
// en todo el libro (con posibles cambios en la versión digital, 
// en el futuro)
npm create qwik@1.5.1

// Para usar la más reciente (puede que no  funcione ya 
// como en el libro y haya posibles cambios, tendréis que consultar 
// en la documentación oficial)
npm create qwik@latest

El comando abrirá una especie de asistente donde nos pedirán los siguientes datos:

  • Nombre de la aplicación (por defecto: ./qwik-app).

  • Tipo de aplicación: Aplicación completa con el sistema de enrutamiento y estilos, aplicación completa con el sistema de enrutamiento incorporado y sin estilos, aplicación para generar documentación y librería de componentes.

  • ¿Instalar dependencias? Lo lógico es que respondamos que si con un Y, aunque tenemos la opción de decir que no (N).

  • ¿Iniciar repositorio de Git? En mi caso le voy a decir que NO (N) ya que voy a tener un repositorio principal donde iré almacenando todos los proyectos agrupados, en orden de lo que se va a ir viendo en el libro, para evitar tener infinidad de repositorios.

  • Al finalizar la instalación se nos pregunta si queremos añadir una broma y decimos que NO (N) ya que no nos hará falta añadir ficheros ni opciones extra. Vamos a hacerlo lo más sencillo posible.

Algo como lo siguiente:

Donde nuestras selecciones serán las especificadas:

  • Nombre de la aplicación: 01-first-steps

  • Tipo de aplicación: Empty App

  • Instalar dependencias: Y (Si)

  • ¿Iniciar repositorio de Git? N (No).

  • ¿Iniciar broma? N (No).

Nos dirigimos al directorio 01-first-steps:

cd 01-first-steps

Una vez dentro, ejecutamos el comando para iniciar nuestra aplicación:

npm start

Para arrancar la app, accedemos a la siguiente url: http://localhost:5173/ (el puerto puede variar) y esta es la apariencia inicial que tendremos por defecto (si queremos, la podemos cambiar fácilmente, sin ningún problema).

Esto podría sufrir cambios en base a las nuevas versiones aunque no afectaría apenas en estos primeros pasos.

Información a tener en cuenta

Hemos seleccionado la opción Empty App. A partir de este momento, cuando mencione que hay que crear un proyecto nuevo seleccionaremos la opción Empty App, que es la plantilla que usaremos en todo el libro.

Estructura de la aplicación Qwik

Al abrir el proyecto dentro de nuestro editor de código podemos visualizar la siguiente estructura:

    carpeta-proyecto-qwik
        ├── README.md
        ├── public
        │   └── favicon.svg
        │   └── manifest.json
        │   └── robots.txt
        ├── src
        │   ├── components
        │   ├── routes
        │   ├── entry.dev.tsx
        │   ├── entry.preview.tsx
        │   ├── entry.ssr.tsx
        │   ├── global.css
        │   └── root.tsx
        ├── vite.config.ts
        ├── tsconfig.json
        ├── node_modules
        ├── package.json
        ├── package-lock.json
        ├── .eslintignore
        ├── .eslintrc.cjs
        ├── .gitignore
        └── .prettierignore

Y aquí vemos los detalles para que sirve cada una de ellas en sus directorios / ficheros principales:

Y aunque hay más ficheros, estos se pueden considerar los más importantes en esta etapa de la introducción.

A medida que avancemos iremos analizando algunos de los que no están mencionados, cuando entremos más en detalles en diferentes funcionalidades como el Routing.

Rutas — Primeros pasos

Para poder trabajar con las rutas en Qwik, el proyecto hace uso de Qwik City que es la implementación que usamos en proyectos Qwik para gestionar las rutas de nuestros proyectos.

Información sobre Qwik City

Más información sobre Qwik City en el siguiente enlace: https://shorten-up.vercel.app/4vwjQzLolW

En este primer capítulo, os explicaré lo básico y esencial, para tener una base de como trabaja el enrutamiento dentro de este framework.

De esta manera daremos un enfoque algo más práctico a este capítulo y así terminar con la sensación de que hemos trabajado algo con lo que respecta a la práctica.

Centrándonos en el proyecto tenemos una plantilla base que será la siguiente:

01-first-steps/src/routes/layout.tsx donde tenemos el esqueleto de lo que será nuestra app base y donde podemos encontrar el punto de entrada para las diferentes rutas, que irá cargando el contenido acorde a la selección. Esto sería el contenido del layout, que es donde se irán cargando los diferentes contenidos.

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

export default component$(() => {
  return <Slot />; // Línea 4
});

Si observamos en la línea 4 (return <Slot />), tenemos el componente <Slot /> que será el componente que usaremos para ir cargando los diferentes contenidos mediante una proyección de lo seleccionado.

¿Qué se va a proyectar? Podrían ser las diferentes páginas como podrían ser dentro de un blog páginas como Inicio, Sobre el autor y Contacto.

Antes de seguir, vamos a añadirle una cabecera fija en ese fichero layout.tsx, para diferenciarlo con el elemento <Slot /> y así, cuando creamos una nueva ruta, podamos ver que esa cabecera sigue sin recargarse, ya que se ha cargado la primera vez y no es necesario más.

Nos ubicamos en el fichero src/routes/layout.tsx y cambiamos de este código:

export default component$(() => {
  return <Slot />;
});

Al siguiente código, metiendo dentro de un div con borde de color verde el elemento Slot, para identificar que lo de dentro de ese div, será lo que se vaya cargando en base a la ruta seleccionada:

export default component$(() => {
  return <>
    <h2>Curso Qwik - Primeros pasos</h2>
    <div style="border: 3px dotted green; margin: 1rem; padding: 1rem">
      <Slot />
    </div>
  </>
});

Por defecto se cargará la información relacionada al fichero index.tsx, que es la ruta del índice principal, dentro del directorio routes. Puedes encontrarlo aquí: 01-first-steps/src/routes/index.tsx.

Aspecto fundamental sobre como nombramos los ficheros y extensiones

Los ficheros que proyectarán su contenido se llamarán index y podemos usarlo con las siguientes extensiones: .ts, .tsx, .js, .jsx, .md, ó .mdx

Más detalles en el próximo capítulo.

El contenido que se cargará cuando ya hemos creado el proyecto y hemos iniciado la ejecución es el correspondiente a la ruta /:

Este fichero index.tsx define la interfaz de usuario que se coloca en la ranura (en el recuadro verde) con el componente Slot dentro de src/routes/layout.tsx, cuando la URL es / que hace referencia a la página principal. Aparte, ya podemos diferenciar lo que se cargará fijo (Curso Qwik...).

Analizando los directorios dentro de routes, podemos observar las posibles rutas que existirán:

Por el momento solo disponemos de la página inicial:

Por lo tanto, si queremos tener más páginas debemos de seguir unos sencillos pasos, pasamos al siguiente punto para ver los detalles iniciales.

¿Cómo añadir una nueva página y asociarla a una ruta?

Por ejemplo, imaginaros que queremos crear la página de contactos de nuestro proyecto de portfolio, lo que debemos de hacer es lo siguiente:

Quedará de la siguiente forma:

Y para tener algo de contenido, tenemos que rellenar el apartado del componente (component$) y lo vamos a hacer de una manera ligera y rápida utilizando el snippet que os he recomendado instalar.

Dentro de src/routes/contact/index.tsx escribimos q-component (1) y seleccionamos el elemento correspondiente al código del componente de Qwik (2)

El código generado sería el siguiente:

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

export const Index = component$(() => {
  return <div>Hello Qwik!</div>
});

Cambiamos

export const Index = ...

Por

export default

Y quedará de la siguiente forma

import { component$ } from '@builder.io/qwik';
import { DocumentHead } from '@builder.io/qwik-city';

export default component$(() => {
    return <div>Hello Qwik!</div>
});

¿Cuál es la razón de este cambio? Debemos de cargar el la función component$ como el elemento principal y por defecto (default) de la página y no como componente en línea (Inline Components), por lo que cuando usemos este snippet para generar el contenido de una nueva ruta, tener en cuenta este pequeño detalle.

Nos faltaría añadir la información de la cabecera (Document Head).

import { component$ } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';

    ...
// Para especificar el título de la página y descripción de la metadata (SEO)
export const head: DocumentHead = {
  title: 'Contact',
  meta: [
    {
      name: 'description',
      content: 'Anartz Mugika contact page',
    },
  ],
};

Y el código de esta página quedaría de la siguiente forma:

import { component$ } from '@builder.io/qwik';
import { DocumentHead } from '@builder.io/qwik-city';

export default component$(() => {
    return <div>Hello Qwik!</div>
});

// descripción de la metadata (SEO)
export const head: DocumentHead = {
    title: 'Contact',
    meta: [
        {
            name: 'description',
            content: 'Anartz Mugika contact page',
        },
    ]
}

En estos momentos vamos a entrar en más detalles sobre lo que hay que tener en cada punto, estamos estudiando lo básico para ir profundizando en otros capítulos, ¡poco a poco!.

Posible problema que se puede dar al hacer cambios

Si añadimos una nueva página y vemos que no detecta estas nuevas rutas, mi recomendación sería PARAR Y REINICIAR LA EJECUCIÓN DEL SERVIDOR apagando la ejecución y ejecutando de nuevo npm run start

Ahora si accedemos a /contact deberíamos de visualizar lo siguiente:

El contenido que viene en esta página lo podemos cambiar de una manera super sencilla (aplicando estos conceptos podemos hacer lo mismo con la ruta `/` correspondiente a `src/routes/index.tsx`), cambiando el siguiente código:

import { component$ } from '@builder.io/qwik';
import { DocumentHead } from '@builder.io/qwik-city';

export default component$(() => {
    return <div>Hello Qwik!</div>
});

// descripción de la metadata (SEO)
...

Por el siguiente:

import { component$ } from '@builder.io/qwik';
import { DocumentHead } from '@builder.io/qwik-city';

export default component$(() => {
  return (
    <div>
      Bienvenido a la página de contacto. Prácticando con Qwik los primeros
      pasos
    </div>
  );
});

// descripción de la metadata (SEO)
...

Cuyo resultado se podrá ver ya con el cambio realizado:

Llegados a este punto, ya tenemos dos rutas y si queremos añadir más, debemos de seguir los pasos dados hasta este momento.

Recordad que esto es super básico, ya que solo serán rutas generales sin parámetros, aspecto que vamos a ver con más detalle en siguientes capítulos con la parte de Routing y Layouts (Plantillas).

Resultado de lo trabajado en este capítulo

A continuación os proporciono el enlace que corresponde al directorio del proyecto que hemos trabajado siguiendo las lecciones del capítulo:

Por el momento, aunque la complejidad es mínima es interesante que vayamos guardando los progresos desde los inicios, para poder ver como evolucionamos en el aprendizaje paso a paso.

El enlace lo tenéis a continuación:
https://shorten-up.vercel.app/YiuJ4YtrPa

¿Qué hemos aprendido en este capítulo?

Al finalizar este capítulo, deberíamos de ser capaces de:

Conclusión

Llegados a este punto, hemos empezado a trabajar con un nuevo framework que es una opción más que interesante para el presente y futuro.

Esperemos que sea una opción importante en el futuro como lo han sido y son actualmente Angular, React, Vue y similares.

Ahora que ya hemos visto lo más básico y esencial para empezar con Qwik, vamos a pasar al siguiente capítulo donde empezamos a profundizar con más detalle el tema del Routing con Qwik City, que es tan importante como interesante.