DEV Community

Cover image for Construí un clon de LWN.net en un solo App.vue de 2292 líneas porque estaba enojado
Andres Avalos Gallegos
Andres Avalos Gallegos

Posted on

Construí un clon de LWN.net en un solo App.vue de 2292 líneas porque estaba enojado

El origen: pura rabia productiva

Línea 8 de mi App.vue:

// y si todo o casi todo en un archivo, y GPLV2 ¿POR QUE?
// por que estaba enojado con paginas con paywalls arcaicos
// (te hablo a ti -> lwn.net <-)
Enter fullscreen mode Exit fullscreen mode

Así nació TuxTimes. Sin reunión de planificación. Sin roadmap. Sin arquitectura de microservicios. Solo un desarrollador, un café, y una rabia muy específica contra LWN.net.

LWN es legendario. Sus artículos sobre el kernel Linux son insustituibles. Pero en 2025:

  • 💸 Paywall de $35/año para leer artículos de la semana
  • 🔒 Solo los editores pueden publicar — no hay comunidad
  • 🗞️ La interfaz parece un periódico de 1994 (sin hipérbole)
  • 📱 Sin dark mode. Sin responsivo decente. Sin filtros modernos.

Así que dije "suficiente" y abrí el editor.


Lo que construí

TuxTimes es una plataforma de noticias sobre Linux y software libre donde cualquiera puede publicar, todo es gratis, y la interfaz no duele usarla.

🔗 tuxtimes.web.app | *

GitHub logo Qmaker-programmer / tuxtimes

🐧 Plataforma de noticias Linux libre, gratis y sin paywalls. Construida con Vue 3 + Firebase. Nació de la rabia contra LWN.net. GPLv2.

████████╗██╗   ██╗██╗  ██╗    ████████╗██╗███╗   ███╗███████╗███████╗
╚══██╔══╝██║   ██║╚██╗██╔╝       ██╔══╝██║████╗ ████║██╔════╝██╔════╝
   ██║   ██║   ██║ ╚███╔╝        ██║   ██║██╔████╔██║█████╗  ███████╗
   ██║   ██║   ██║ ██╔██╗        ██║   ██║██║╚██╔╝██║██╔══╝  ╚════██║
   ██║   ╚██████╔╝██╔╝ ██╗       ██║   ██║██║ ╚═╝ ██║███████╗███████║
   ╚═╝    ╚═════╝ ╚═╝  ╚═╝       ╚═╝   ╚═╝╚═╝     ╚═╝╚══════╝╚══════╝

🐧 TuxTimes

TuxTimes Preview

El lector de noticias Linux que nació de la rabia pura y el odio a los paywalls arcaicos

Vue 3 Firebase GPLv2 LWN Estado Score


"Nació porque estaba enojado con páginas con paywalls arcaicos (te hablo a ti → lwn.net ←)"

— El autor, comentario en el código, línea 8


🐧 Un pingüino rebelde · Una app de Vue · Un grito de independencia informativa 🐧


🏆 TuxTimes vs LWN.net — La Comparativa Final

LWN lleva desde 1998. TuxTimes lleva un fin de semana. El resultado habla solo.

Feature TuxTimes LWN.net
🌑 Dark mode
☀️ Light mode
⚡ High Contrast (modo hacker)
💸 Gratis para leer ❌ ($35/año)
✍️ Cualquiera puede

*

El stack

  • Vue 3 Composition API — porque Options API es 2020
  • Firebase Auth — Google OAuth sin servidores propios
  • Firestore — NoSQL que cobra por query (así aprendes a no hacer queries en bucles)
  • marked — Markdown → HTML, magia negra controlada
  • Vite — porque webpack es un recuerdo doloroso
  • GPLv2 — por coherencia ideológica y enojo

Los features que LWN no tiene

Feature TuxTimes LWN.net
Dark mode
Light mode
⚡ High Contrast (modo hacker)
Gratis para leer ❌ ($35/año y gratis es limitado)
Cualquiera puede publicar
Búsqueda con #tags 😬
Paginación 😬
Responsive móvil 💀
Easter egg de Windows/BSOD
Pingüino bounceando

Score: TuxTimes 19/19 🏆 — LWN 3/19 💀


La parte técnica interesante

El sistema de comentarios recursivo

El feature más dramático del proyecto. Comentarios en árbol con depth hasta 5, y un algoritmo que me tomó más tiempo del que admito:

El Algoritmo de Poda de Fantasmas™:

Cuando borras un comentario que tiene respuestas:

// RECOLECTOR DE BASURA EN CASCADA REVERSA
let currentParentId = currentComment?.parentId;
while (currentParentId) {
  // Si el padre ya era fantasma y no le quedó nada útil... ¡exterminado!
  if (!parentHasLiveChildren) {
    await deleteDoc(parentRef);
    currentParentId = parentNode.parentId;
    continue;
  }
  break;
}
Enter fullscreen mode Exit fullscreen mode
  1. Si tiene hijos vivos → soft delete: [Este comentario ha sido eliminado]
  2. Si no tiene hijos → purga física de Firestore
  3. Cascada reversa: sube por el árbol eliminando padres fantasmas vacíos

El enrutamiento sin router

Sin React Router. Sin Vue Router. Solo window.location.hash y orgullo:

// Porque en el año 2024 seguimos usando el fragmento de la URL
// como sistema de rutas. React Router llorando en un rincón.
// Ventaja: sin SSR, sin 404s, sin drama. Solo un # y listo.
const HASH_VIEWS = {
  '#reciente': 'feed',
  '#configuracion': 'settings',
  '#favoritos': 'favorites',
  '#nuevopost': 'new-post',
  // #post-{ID} → abre ese post directamente (compartible)
  // #cualquier-otra-cosa → filtra por ese tag
};
Enter fullscreen mode Exit fullscreen mode

El Easter Egg

// EASTER EGG: si el usuario busca "windows" → BSoD de Linux.
// (si alguien reporta esto como bug, es que no entiende la cultura)
watch(searchQuery, (v) => {
  showWindowsEgg.value = v.toLowerCase().includes('windows');
});
Enter fullscreen mode Exit fullscreen mode

Sí. Si buscas "windows" aparece una pantalla azul de la muerte de Linux. No me arrepiento.

Los 3 temas

Dark, Light, y High Contrast — inspirado en el tema de VSCodium. Azul neón sobre negro total. El usuario se siente hackeando la NASA.

[data-theme="hc"] {
  --bg: #000000;
  --accent: #1aabff;
  --border: #0078d4;
}
[data-theme="hc"] .post-card {
  border-color: #0078d4;
  box-shadow: 0 0 0 1px #0078d4;
}
[data-theme="hc"] .post-card:hover {
  box-shadow: 0 0 16px rgba(26,171,255,.4);
}
Enter fullscreen mode Exit fullscreen mode

Guardados en cookie, no en Firebase. Es preferencia del navegador, no del servidor.


Lo que aprendí

1. Un monolito no siempre es malo

Todo vive en App.vue. 2292 líneas. CSS incluido. ¿Es buena arquitectura? No. ¿Funciona perfectamente? Sí. A veces la velocidad de iteración vale más que la separación de concerns.

2. Firestore cobra por query — literalmente

Aprendes a optimizar cuando cada .getDocs() de más sale de tu bolsillo. El resultado: código que reutiliza datos locales siempre que puede.

// Filtra los posts del autor desde el array LOCAL (sin query extra 💸)
const authorPostsList = posts.value.filter(p =>
  p.authorUid === post.authorUid || p.author === post.author
);
Enter fullscreen mode Exit fullscreen mode

3. El enojo es un motor válido

Literalmente la mejor motivación que tuve. No había cliente, no había deadline, no había dinero. Solo la rabia de que LWN no tiene dark mode en 2025 y la certeza de que yo podía hacerlo mejor.


El estado actual

  • ✅ Auth completa (Google + Email)
  • ✅ Editor Markdown con preview en tiempo real
  • ✅ Comentarios en árbol con poda de fantasmas
  • ✅ 3 temas (dark/light/high contrast)
  • ✅ Paginación de 20 posts con sort
  • ✅ Perfiles públicos de autor
  • ✅ Sistema de favoritos
  • ✅ Responsive en 3 breakpoints
  • ✅ Easter egg de Windows
  • ⏳ Tests (el futuro nosotros lo resolverá)
  • ⏳ Paginación en Firestore (ahora es client-side — sí, lo sé)

Contribuye

Si eres de la comunidad Linux y quieres una plataforma libre donde publicar lo que aprendes, TuxTimes existe para eso.

git clone https://github.com/Qmaker-programmer/tuxtimes.git
cd tuxtimes
npm install
cp src/firebase.example.js src/firebase.js
npm run dev
Enter fullscreen mode Exit fullscreen mode

GPLv2. Fork it. Mejóralo. Mándale un PR.

O simplemente úsalo: tuxtimes.web.app

1. Un monolito no siempre es malo

Todo vive en App.vue. 2292 líneas. CSS incluido. ¿Es buena arquitectura? No. ¿Funciona perfectamente? Sí. A veces la velocidad de iteración vale más que la separación de concerns.

2. Firestore cobra por query — literalmente

Aprendes a optimizar cuando cada .getDocs() de más sale de tu bolsillo. El resultado: código que reutiliza datos locales siempre que puede.

// Filtra los posts del autor desde el array LOCAL (sin query extra 💸)
const authorPostsList = posts.value.filter(p =>
  p.authorUid === post.authorUid || p.author === post.author
);
Enter fullscreen mode Exit fullscreen mode

3. El enojo es un motor válido

Literalmente la mejor motivación que tuve. No había cliente, no había deadline, no había dinero. Solo la rabia de que LWN no tiene dark mode en 2025 y la certeza de que yo podía hacerlo mejor.


El estado actual

  • ✅ Auth completa (Google + Email)
  • ✅ Editor Markdown con preview en tiempo real
  • ✅ Comentarios en árbol con poda de fantasmas
  • ✅ 3 temas (dark/light/high contrast)
  • ✅ Paginación de 20 posts con sort
  • ✅ Perfiles públicos de autor
  • ✅ Sistema de favoritos
  • ✅ Responsive en 3 breakpoints
  • ✅ Easter egg de Windows
  • ⏳ Tests (el futuro nosotros lo resolverá)
  • ⏳ Paginación en Firestore (ahora es client-side — sí, lo sé)

Contribuye

Si eres de la comunidad Linux y quieres una plataforma libre donde publicar lo que aprendes, TuxTimes existe para eso.

git clone https://github.com/Qmaker-programmer/tuxtimes.git
cd tuxtimes
npm install
cp src/firebase.example.js src/firebase.js
npm run dev
Enter fullscreen mode Exit fullscreen mode

GPLv2. Fork it. Mejóralo. Mándale un PR.

O simplemente úsalo: tuxtimes.web.app


— Qmaker (Andres / Andresuno), el único loco que hizo esto en un solo App.vue de 2292 líneas, en un fin de semana, por puracu rabia productiva 🫡🐧


¡Prueba TuxTimes ahora mismo!

¿Qué opinan de meter 2000 líneas en un solo archivo? ¿Es arte o es un crimen?

Top comments (0)