Software y sistemas

He renovado mi página principal y ahora es open source

Justo hoy he publicado mi página principal totalmente renovada y hecha por mí, además de que es totalmente open source (he puesto el repositorio en línea).

Ya era hora, pues no estaba mostrando mi portafolio y la última actualización fue en diciembre del 2017.

Página web de parzibyte.me renovada

Voy a explicar en este post cómo fue la creación y las cosas que usé para crearla; además de exponer cómo hice para que cargara rápido y otras cosas.

Primero lo primero, código fuente y demostración

El código fuente está en mi GitHub, y la demostración la puedes ver en el sitio personal de Luis Cabrera Benito (parzibyte).

Puntuación en PageSpeed Insights

La primera vez (cuando la página no estaba completa) obtuve una puntuación de 100 en móvil y en ordenador, después de agregar los observadores de intersección bajó a 94 en móvil y se mantuvo en 100 desde una computadora.

Puntuación móvil de parzibyte en PageSpeed Insights
Puntuación ordenador de parzibyte en PageSpeed Insights

Puedes ver la puntuación aquí.

¿Por qué es rápida?

Aunque al momento de escribir esto había como 35 imágenes, todas fueron cargadas conforme el usuario las requería, además de que quité saltos de línea y tabulaciones del documento HTML; reduje la calidad de las imágenes, retrasé la carga de iconos y cargué los estilos y fuentes en paralelo.

A pesar de que es un HTML al final, el código es generado con PHP; pero decidí no generarlo en tiempo de ejecución sino generarlo una vez y crear un HTML para acelerar todavía más las cosas.

Tecnologías y cosas utilizadas

Aquí voy a explicar cómo utilicé cada cosa para hacer la página.

Todo el diseño está hecho con Bootstrap

El diseño y la alineación de las cosas es gracias a una variante de Bootstrap llamada Sketchy que puede ser encontrada aquí.

La renderización está hecha con PHP

Sabemos que PHP genera HTML, así que lo usé para ello; pero para ahorrarle carga al servidor (es decir, que no renderizara siempre) decidí poner el contenido generado en un HTML.

De esta manera se servía un HTML, no un PHP, es decir, algo estático pero que fue generado por PHP.

Luego de ello removí los saltos de línea y tabulaciones para que el HTML pesara menos y escribía lo generado en un nuevo documento:

<?php
$salida = "index.html";
ob_start();
include_once "index.php";
# ¿Expresiones regulares? ¿Optimización? aquí no hacemos eso.png
$contenido = ob_get_clean();
$contenido = str_replace("\n", "", $contenido);
$contenido = str_replace("\t", "", $contenido);
$contenido = str_replace("\t\t", "", $contenido);
$contenido = str_replace("  ", "", $contenido);
$escrito = file_put_contents("index.html", $contenido);
if ($escrito !== FALSE) {
    echo "Contenido generado y guardado en $salida";
} else {
    echo "Eror escribiendo en $salida";
}
?>

Acabo de notar que no estoy usando la variable $salida para file_put_contents pero luego lo arreglo. Lo importante es notar el uso de ob_start y ob_get_clean.

Las imágenes son cargadas de manera perezosa

Gracias a la API de IntersectionObserver para el Lazy loading pude cargar las imágenes conforme el usuario hace scroll. Por defecto todas tienen una imagen de placeholder (la cual se define con $imagenGenerica desde PHP) y van cambiando su ruta cada que el usuario las va a ver:

const observadorImagenes = new IntersectionObserver(function (entradas) {
            for (let i = 0; i < entradas.length; entradas++) {
                const entrada = entradas[i];
                if (entrada.intersectionRatio > 0) {
                    const imagenes = entrada.target.querySelectorAll("img");
                    imagenes.forEach(imagen => {
                        imagen.src = imagen.dataset.src;
                    });
                    observadorImagenes.unobserve(entrada.target);
                }
            }
        }, opciones);

La plantilla es modificable

Como programador perezoso que soy, puse todos mis datos en el código y así logré hacer una plantilla personalizable:

<?php
$urlBase = trim(file_get_contents("url_base.txt"));
$persona = [
    "titulo" => "Desarrollador móvil y web full-stack",
    "nombre" => "Luis Cabrera Benito",
    "foto" => "$urlBase/img/perfil.jpg",
    "alias" => "parzibyte",
    "correo" => "contacto@parzibyte.me",
    "descripcion_corta" => "Desarrollador web full-stack y móvil. Interesado en trabajar contigo, unirme a tu equipo de desarrolladores o asesorarte de manera remota para llevar tu idea a la realidad",
    "descripcion" => "Hola, soy Luis Cabrera Benito (a.k.a. parzibyte): un desarrollador móvil y full-stack profesional con más de 5 años de experiencia, especializado en <strong>PHP, JavaScript, Python y Go</strong>",
    "blog" => "https://parzibyte.me/blog"
];
$imagenGenerica = "$urlBase/img/placeholder.jpg";

Cargando los iconos con IntersectionObserver

Para mis habilidades puse algunos iconos CSS de desarrolladores, pero iban a gastar ancho de banda y hacer más lenta la carga aunque el usuario no quisiera ver mis habilidades en ese momento.

Entonces, siguiendo la técnica para las imágenes, cargué los iconos solamente cuando el usuario anda navegando en esa sección.

const cargarIconos = () => {
            const linkIconos = document.createElement("link");
            linkIconos.rel = "stylesheet";
            linkIconos.href = "https://cdn.jsdelivr.net/npm/devicons@1.8.0/css/devicons.min.css";
            document.head.insertBefore(linkIconos, document.head.childNodes[document.head.childNodes.length - 1].nextSibling);
        };

const $seccionHabilidades = document.querySelector("#habilidades");
        const observadorIconos = new IntersectionObserver(elementos => {
            elementos.forEach(elemento => {
                if (elemento.intersectionRatio > 0) {
                    cargarIconos();
                    observadorIconos.unobserve($seccionHabilidades);
                }
            });
        });

observadorIconos.observe($seccionHabilidades);

La carga del tema y las fuentes es en paralelo

Las cosas en paralelo son más rápidas porque se ejecutan al mismo tiempo y no esperan a que una termine para que la otra comience. Con ese principio cargué los estilos CSS y la fuente de manera paralela:

const estilos = ["https://fonts.googleapis.com/css?family=Neucha|Cabin+Sketch", "<?php echo $urlBase ?>/css/bootstrap.min.css"];
        estilos.forEach(enlace => {
            const linkFuente = document.createElement("link");
            linkFuente.rel = "stylesheet";
            linkFuente.href = enlace;
            document.head.insertBefore(linkFuente, document.head.childNodes[document.head.childNodes.length - 1].nextSibling);
        });

Todavía más

Me salté algunas cosas pero de todas ellas ya he hablado en mi blog, a la derecha encontrarás las categorías desde donde puedes explorar cada tema que toco.

Exponiendo cada cosa

Es hora de mostrar lo que compone mi página web, excepto el inicio pues ese ya todos lo vimos. Por cierto, así se ve en móvil:

Página web parzibyte.me renovada para móviles

El portafolio

Con tarjetas muestro las cosas que he creado. Ni siquiera yo sabía que son 30 cosas; claro que no todas son complejas pero puse todo mi esfuerzo en ellas.

Un vistazo a mi portafolio

En los casos en donde el código es mío o el sistema es gratuito agregué algunos enlaces para probar o estudiar el source code.

Las habilidades, lenguajes de programación y esas cosas

Tienen el título, una descripción personal sobre ellas y una barra que indica qué tanto sé sobre ellas.

Habilidades de Luis Cabrera Benito

He sido lo más humilde posible, por cierto.

Más cosas

Hay otras cosas pero dejaré que las veas tú mismo entrando a mi sitio web.

Una curiosidad: por qué elegí el username parzibyte

Bueno nunca había escrito sobre ello, pero si llegaste hasta aquí mereces saberlo. Hace muchos años (como en el 2011) estaba felizmente leyendo en mi teléfono algunos libros que había conseguido por ahí, pero me llamó mucho la atención uno llamado Ready Player One (no supe el nombre hasta después)… leí el inicio y me enganchó, pero el libro estaba incompleto y me quedé con las ganas de leerlo.

Pasó el tiempo, olvidé que existía pero por casualidad lo volví a encontrar; lo leí completo y me gustó mucho así que lo leí otras veces hasta que se convirtió en mi libro favorito. Entonces decidí que mi nombre de usuario iba a ser parzival como el avatar de Wade en la historia (si no has leído el libro, te lo recomiendo) y así fue.

Más tarde me registré en algunos sitios con ese username pero en varios ya estaba ocupado, fue hasta diciembre del 2015 que elegí parzibyte porque mi nombre tenía relación con la informática y aparte de ello no estaba ocupado, así que me quedé con parzibyte y así comenzó todo.

Por cierto, si no era parzibyte podría ser parzival777, ¿no?

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.