Creando un Navegador: Parte III MVP recap
Revisemos lo que hicimos la semana pasada.
Creamos nuestro MVP de navegador.
- Definimos como se escriben nuestras interfaces.
JSON - Interpretamos el contenido
Parser - Guardamos la interpretacion en el
appState - Dibujamos en pantalla con los componentes que implementamos.
Renderer
En otras palabras: Creamos un loader, un parser y un renderer

Versión simplificada portable
Pega el siguiente código en la consola de tu navegador y tendrás lo que hicimos la semana pasada.
(function () { const canvasHelper = { dot: ({ ctx, element }) => { console.log('dot'); console.log({ element }); element.radius = 1; canvasHelper.arc({ ctx, element }); }, line: ({ ctx, element }) => { console.log('line'); }, rect: ({ ctx, element }) => { console.log('rect'); }, arc: ({ ctx, element }) => { const { radius, position } = element; const [x, y] = position;
ctx.fillStyle = 'black'; // ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); ctx.fill(); }, polygon: ({ ctx, element }) => { console.log('polygon'); }, text: ({ ctx, element }) => { console.log('text'); }, }; const navegador = { loader: { getFile: (fileReference) => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => resolve(reader.result); reader.onerror = reject; reader.readAsText(fileReference); }); }, }, parser: { toUI: (file) => { return JSON.parse(file); }, }, renderer: { draw: (elements, engine) => { engine.width = 300; engine.height = 400; engine.style.border = '1px solid #ccc'; const ctx = engine.getContext('2d');
// background ctx.fillStyle = 'white'; ctx.fillRect(0, 0, engine.width, engine.height);
// draw process elements.forEach((element) => { element.type = element.type.toLowerCase().trim();
if (element.position) { element.position = element.position .split(',') .map((coord) => Number(coord)); }
// draw canvasHelper[element.type]({ ctx, element }); }); }, }, }; const appState = { currentUI: undefined, history: [], }; const startNavegador = async (event) => { //loader const fileRef = event.target.files[0]; const file = await navegador.loader.getFile(fileRef); // parser const ui = navegador.parser.toUI(file); //state appState.currentUI = ui; appState.history.push({ ui, ts: Date.now() }); // renderer const { elements } = appState.currentUI.screen; const engine = document.querySelector('#engine'); navegador.renderer.draw(elements, engine); }; // start const template = ` <!-- renderer --> <canvas id="engine" style=" border-radius:4px; padding:1rem 1rem;"></canvas> <!-- trigger process --> <div style="max-width:300px"> <label for="file-input" style="width:100%; display:block; border:1px solid #ccc; border-radius:4px; padding:1rem 1rem;cursor:pointer" >Import file</label> <input style="width: 0; height: 0; position: absolute" type="file" name="file-input" id="file-input" accept=".json" /> <div/> `; document.body.innerHTML = template; // listeners const fileInput = document.querySelector('#file-input'); fileInput.addEventListener('change', startNavegador);})();Que podemos hacer con esto?
mmmm…
Si quisieras hacer aplicaciones como:
FigmaMirodraw.ioCanvaWixWebflow
Flujo base
- defines el modelo de tu interfaz
- expones este modelo para que el usuario lo modifique
- dibujas el modelo segun tus necesidades en un
Renderer
Figma


Miro
tambien usa un <canvas>

draw.io
Maneja su renderer con <svg> y no con <canvas>.

Canva
Crea elementos html directamente en el DOM.

Wix
Crea elementos html y te los muestra en un iframe.
cada vez que haces un cambio en el Editor, manda un mensaje al Backend, e backend actualiza el archivo y se actualiza el iframe

WebFlow
Hace lo mismo que Wix, HTML elements en un iframe

Para este tipo de aplicaciones puede que el Parser no sea tan relevante como el Renderer y la gestión de los elementos del lienzo.
Podemos decir que la complejidad se inclina hacia el Renderer
🤔 que otra cosa podríamos hacer ?
inclinarnos hacia el Parser.
Basados en un texto podemos extraer su significado segun nuestras reglas.
- Podemos simplificar la forma de publicar documentos en la web escribiendo archivos
markdown - Podemos crear nuestro propio lenguaje de
templating, comohandlebar,Razor,etc. - Podemos definir la sintaxis de nuestro propio lenguaje de programación.
- Podemos crear
Lintersy Prettiers
y muchas cosas más!.
Todo va a depender donde y que interpretar. (Puede ser ‘web’ o no).
Estos Legos (loader,parser,renderer), son la puerta de entrada para crear
y comprender sistemas/productos más complejos.
Links para profundizar:
Volviendo con nuestro MVP
Nos faltan un millón de cosas xD!
- Actualmente solo leemos y mostramos la interfaz.
- No soportamos interacciones del usuario
- No se puede definir la apariencia y composición de los elementos de la interfaz
- Solo soportamos formas basicas (puntos, lineas, poligonos) , no soportamos imagenes, audio,…
- No podemos incorporar recursos externos (fuentes, imagenes,…)
- No leemos interfaces de maquinas externas.
- …
Todavia no alcanzamos a ser la Web 1.0.
Somos la Web 0.6, mas-menos xD
📒Backlog
- Permitir al usuario interactuar con la interfaz
Our own Event system. - Permitir definir la apariencia y composición de las elementos de la interfaz
our own CSS implementation. - Permitir la ejecución de código durante el consumo del contenido
our own scripting environment. - Cargar nuestros archivos de interfaces desde un maquina remota/externa.
- LLevar registro del contenido consumido por usuario
- Agregar metricas de los procesos internos de nuestro navegador.
Si les tinca algo en particular, avisen.
🤔 esta semana estaré pensando con que seguir