Fresh es un framework web basado en Deno y estándares web construido para ejecutarse en el edge
This talk has been presented at Node Congress 2023, check out the latest edition of this JavaScript Conference.
Fresh es un framework web basado en Deno y estándares web construido para ejecutarse en el edge
This talk has been presented at Node Congress 2023, check out the latest edition of this JavaScript Conference.
Fresh es un marco de trabajo web de pila completa que se ejecuta en Deno. Es un marco de trabajo renderizado en el lado del servidor y proporciona soporte para TypeScript de forma nativa sin necesidad de configuración inicial.
La instalación de Fresh es rápida. Simplemente ejecuta el comando 'deno run -A -R https://fresh.deno.dev' seguido del nombre de tu proyecto.
Deno es un tiempo de ejecución para JavaScript, TypeScript y WebAssembly que utiliza V8 y se ejecuta en Edge. Permite la creación de interfaces de línea de comandos y tiene varias herramientas integradas como un linter, un formateador de código y un ejecutor de pruebas.
Fresh soporta tres tipos de rutas: rutas de controlador, generalmente utilizadas para APIs, rutas de componente, utilizadas para las páginas, y rutas híbridas, que combinan características de las anteriores.
La arquitectura de Islas en Fresh permite bolsas de interactividad en tu sitio o aplicación, donde el HTML estático se combina con componentes que pueden 'revivirse' con JavaScript en el lado del cliente, pero que son renderizados inicialmente en el servidor.
En Fresh, el middleware es un componente que puede modificar la solicitud o respuesta de una ruta. Puedes tener múltiples middlewares que se ejecutan en un orden específico antes de llegar al controlador final de la ruta.
La obtención de datos en Fresh se puede manejar a través de rutas de controlador o rutas híbridas. Estas permiten exportar funciones que reciben una solicitud y un contexto, y devuelven una respuesta, gestionando así los datos dinámicamente.
Fresh permite el uso de Tailwind CSS mediante TWIN, una implementación renderizada en el lado del servidor, y también admite CSS moderno sin un paso de compilación, favoreciendo la innovación y adaptabilidad en el manejo de estilos.
Fresh permite definir páginas de error personalizadas como una página 404. Estas páginas pueden recibir props específicos sobre la solicitud fallida, permitiendo un manejo más detallado del error.
Hoy vamos a hablar sobre FRESH, un framework web full-stack para Deno. Trabajo en Netlify. Soy de Montreal, Quebec, Canadá. Si me buscas en línea, estoy en NikkieTOnline prácticamente en todas partes. Si quieres saber más sobre mí, visita IAmDeveloper.com. También hago transmisiones en Twitch y tengo un canal de YouTube.
Hola a todos. Hoy vamos a hablar sobre FRESH, un framework web full-stack para Deno. Antes de comenzar, un poco sobre mí. Como mencioné, trabajo en Netlify. Soy de Montreal, Quebec, Canadá. Si me buscas en línea, estoy en NikkieTOnline prácticamente en todas partes. Si quieres saber un poco más sobre mí, puedes visitar mi sitio web en IAmDeveloper.com. También hago transmisiones en Twitch, así que si te interesa, puedes visitar IAmDeveloper.live. También tengo un canal de YouTube que puedes ver en YouTube.IAmDeveloper.com. Tampoco soy muy fan de las arañas.
Hoy vamos a cubrir qué es Fresh, discutir los estándares web y profundizar en las características de Fresh. Deno es un runtime para JavaScript, TypeScript y WebAssembly (Wasm) que utiliza V8. Tiene un linter incorporado, formateador de código, ejecutor de pruebas e interoperabilidad con Node.js y npm. Deno sigue los estándares web y es parte del WinterCG, un grupo comunitario para la interoperabilidad de API. Para instalar Fresh, usa el comando 'deno run-A-R https://fresh.deno.dev project-name' y elige opciones como Tailwind e integración con VS Code. Inicia Fresh con 'deno task start' en la carpeta raíz del proyecto.
Bien, ¿qué vamos a cubrir hoy? Vamos a repasar qué es Fresh. Vamos a discutir los estándares web, y luego profundizaremos en las características de Fresh. Después de eso, habrá una breve demostración, y luego podremos pasar a preguntas y comentarios.
Bien, vamos a ello. Entonces, ¿qué es Fresh? Bueno, espera. Primero, necesitamos hablar sobre Deno. Entonces, ¿qué es Deno? Deno es un runtime para JavaScript, TypeScript y WebAssembly, o Wasm, que utiliza V8. Para la web, se ejecuta en el Edge. También puedes usar Deno para crear interfaces de línea de comandos, es decir, CLI's. Tiene un linter incorporado, hay un formateador de código incorporado, un ejecutor de pruebas incorporado, hay interoperabilidad con Node.js a través de especificadores de nodo, y también hay interoperabilidad con npm a través de especificadores de npm y CDNs. Bien, hablemos de los estándares web. Entonces, Deno utiliza estándares web.
Por ejemplo, import maps, fetch, request y response. Como dice el pequeño dibujo de allí, solo míralo en MDN. Excelentes documentos, pero también eso es prácticamente lo que necesitarás referenciar la mayor parte del tiempo si estás trabajando con Fresh. Como parte de los estándares web, Deno es parte del WinterCG. Web Interoperable Runtimes Community Group. Es un espacio para colaborar en la interoperabilidad de API para runtimes de JavaScript. Siéntete libre de leer más sobre el WinterCG en wintercg.org. Bien, ¿dónde estábamos? Suponiendo que tienes Deno instalado, instalar Fresh es bastante rápido.
Solo necesitas ejecutar el comando que ves en la diapositiva aquí. Así que eso es deno run-A-R y luego https://fresh.deno.dev y el nombre de tu proyecto. Eso fue mucho que decir. Bien. La instalación es bastante rápida y tienes un par de opciones. Puedes elegir Tailwind para estilos, optar por la integración con VS Code a través de la extensión Deno VS Code, y eso es prácticamente todo. Hablaremos más sobre la historia del estilo un poco más adelante en la charla. Para iniciar Fresh, vamos a la carpeta raíz del proyecto en una terminal y ejecutamos Deno task start. No entraremos en eso en esta charla, pero Deno tiene un ejecutor de tareas incorporado que puedes configurar a través de un archivo deno.json.
Fresh es un framework web full-stack que se ejecuta en Deno. Proporciona soporte para TypeScript desde el principio y utiliza la arquitectura Islands para la interactividad del cliente. Preact se utiliza tanto en el lado del servidor como en el del cliente, ofreciendo soporte para JSX. Explicaremos la arquitectura Islands con más detalle más adelante.
Bien. Así que vamos a profundizar en qué es Fresh. Entonces, ¿qué es Fresh? Es un framework web full-stack que se ejecuta en Deno. Es un framework renderizado del lado del servidor. Tiene renderizado justo a tiempo en el edge. Proporciona soporte para TypeScript desde el principio, y no hay nada que configurar para empezar a funcionar. No hay paso de construcción. No se entrega JavaScript por defecto. Utiliza la arquitectura Islands para la interactividad del cliente. Utiliza Preact en el lado del servidor y del cliente. Y hay soporte para JSX gracias a Preact y TypeScript. Si no estás familiarizado con el increíble proyecto Preact, es una alternativa rápida y más pequeña a React con la misma API moderna. Solo se menciona aquí por ahora, pero profundizaremos en qué es la arquitectura Islands un poco más adelante en la charla.
Las características de Fresh incluyen archivos estáticos, rutas y enrutamiento, y obtención de datos. Los activos estáticos en la carpeta Static se pueden almacenar en caché utilizando el asistente de activos incorporado. Fresh admite tres tipos de rutas: handler, component y hybrid. Se admiten patrones de enrutamiento basados en archivos, pero Fresh solo admite renderizado del lado del servidor. Para la obtención de datos, las rutas handler requieren exportar una función que devuelva una respuesta, mientras que las rutas hybrid utilizan el objeto handler para definir funciones para acciones. Los props en Fresh se acceden a través de la propiedad props.data.
Bien, repasemos algunas de las características de Fresh. Tenemos archivos estáticos de los que hablaremos, rutas y enrutamiento, obtención de datos, middleware, páginas de error estilos, y luego llegaremos a Islands.
Así que primero tenemos archivos estáticos. Todos los activos estáticos se pueden encontrar en la carpeta Static. Los activos estáticos, aparte de las etiquetas de imagen y fuente, no tienen encabezados de caché configurados en ellos. Puedes configurar los encabezados de caché manualmente o puedes usar el asistente de activos incorporado para automáticamente almacenar en caché un activo por un año. Aquí hay un ejemplo del asistente de activos en acción. Así que tengo esto en mi hoja de estilo. Estoy usando el asistente de activos y lo que sucede es que genera una URL única que se compone de la ruta del archivo del activo, seguida de una cadena de consulta con una clave, guion bajo FRSH, guion bajo C con un valor que es el ID de compilación del despliegue. Y puedes ver, como mencioné, también se establece esto en los encabezados de control de caché en la respuesta. Así que lo tenemos allí por un año.
Bien, profundicemos en las rutas y el enrutamiento. Hay tres tipos de rutas. Está la ruta handler, que es típicamente para APIs, la ruta component, que es para páginas, y luego la ruta hybrid. Y para las rutas hybrid, es para páginas que requieren rutas handler, por ejemplo, una página de inicio de sesión o una página de búsqueda. Al igual que en otros frameworks, las rutas también pueden ser dinámicas. Puedes ver en la tabla aquí que tomé de la documentación de Fresh, que hay muchos tipos de patrones de enrutamiento basados en archivos que se admiten. Una cosa a tener en cuenta, sin embargo, es que Fresh solo admite renderizado del lado del servidor. Así que no hay concepto de algo como get static paths en Next.js o Astro ya que las páginas nunca se generan estáticamente.
Bien, veamos la historia de la obtención de datos. Así que para la obtención de datos, tenemos rutas handler, que acabo de mencionar, y también podemos usar rutas hybrid para manejar la obtención de datos. Para una ruta handler, todo lo que se requiere es exportar una función que tome dos argumentos, una solicitud y un contexto, y devuelva una respuesta. Así que en este caso aquí, tenemos un handler que está usando el, este es el API de chistes que se incluye con el sitio de demostración de Fresh, y podemos ver aquí que solo está generando una lista de chistes aleatorios de un array, y luego está devolviendo eso como una respuesta. Para rutas hybrid, definimos funciones para acciones en una variable exportada llamada handler. Nombramos las funciones async en el objeto handler después de los verbos HTTP. Por ejemplo, get. Como la ruta handler en el ejemplo anterior devuelve una respuesta, típicamente en una ruta hybrid querrás devolver el resultado del método context render. Piensa en context render como pasar props renderizados del lado del servidor a la página que se está renderizando. Cuando digo props, me refiero a props de Preact o props de React si eres nuevo en Preact. Mirando el ejemplo en la diapositiva, una cosa a tener en cuenta sobre los props y Fresh es que no es props.movies, los props de context.render siempre están en la propiedad props.data.
El array de movie props es en realidad props.data, no props.data.movies. Fresh soporta middleware, y se soportan múltiples middlewares. Se da un ejemplo donde se utilizan dos middlewares para una ruta de película dinámica. El middleware menos específico se ejecuta primero, añadiendo encabezados a la respuesta. El resultado muestra el encabezado de control de caché y los encabezados proporcionados por los middlewares.
Por ejemplo, el array de movie props es en realidad props.data, no es props.data.movies. Eso es un montón de puntos en esa charla.
Bien, vamos a pasar al middleware. Nuevamente, como otros frameworks, Fresh soporta middleware. Todos nuestros archivos se nombran guion bajo middleware punto ts y deben residir en la carpeta routes. Se soportan múltiples middlewares. Aunque Deno te anima a usar TypeScript, podrías escribir el middleware en un archivo JavaScript.
Veamos un ejemplo. Supongamos que navego a slash movie slash Top Gun. Dado que estamos accediendo a una ruta de película dinámica, eso significa que estamos usando dos middlewares. Uno en la raíz de la carpeta routes y otro en la subcarpeta movie. En el caso de múltiples middlewares, el menos específico se ejecuta primero. En nuestro ejemplo, eso significa que el middleware raíz se ejecuta primero. Añade un encabezado X-conference con el valor nodeCongress2023. Luego, el segundo middleware se ejecuta en la subcarpeta movie. Añade un encabezado X-movie-page junto con un encabezado de caché que almacena la página por 60 segundos. Si navegamos a slash-movies, podemos ver los dos middlewares dando un pequeño apretón de manos allí. Podemos ver el resultado en la respuesta es que obtenemos el encabezado de control de caché y obtenemos los otros dos encabezados que proporcionan los dos middlewares.
Vamos a hablar sobre las páginas de error y cómo puedes definir páginas de error personalizadas en Fresh. El ejemplo dado es una página 404 personalizada o página de archivo no encontrado. Estas páginas son rutas de componentes con props especiales pasadas. Los unknown page props te dan acceso a información como la URL de una página que no se encontró. Para rutas dinámicas, puedes usar context.render not found para renderizar la página 404 si la página no existe. Si estás en una página asociada con una ruta dinámica y la página que se está cargando no existe, context.render not found pasará los unknown page props a la página 404.
Así que el X-conference y el X-movie-page. Bien, continuando, vamos a hablar sobre las páginas de error. Al igual que otros frameworks, puedes definir páginas de error personalizadas. Por ejemplo, la diapositiva actual muestra una página 404 personalizada o página de archivo no encontrado. Estas son rutas de componentes pero tienen props especiales pasadas. En el caso de la página 404, tienes acceso a los unknown page props cuando la página se está renderizando. Los unknown page props te dan acceso a cosas como la URL de una página que no se encontró. Para una ruta dinámica, llamamos a context.render not found para renderizar la página 404 si la página no existe. Y solo para volver a la obtención de datos, cuando estábamos discutiendo la obtención de datos, mencioné que normalmente necesitamos devolver el resultado de context.render para rutas híbridas. Eso sigue siendo válido, pero como mencioné, si estás en una página que está asociada con una ruta dinámica y la página que se está cargando no existe, devolvemos context.render not found en su lugar, y context.render not found pasará entonces los unknown page props de los que estábamos hablando hace un momento a la página 404.
Fresh te da la opción de habilitar TWIN, una implementación renderizada del lado del servidor de Tailwind. El CSS moderno es una opción convincente, con selectores anidados, variables CSS y otras ventajas. Agregar un paso de construcción para herramientas de CSS va en contra de la promesa de Fresh de no tener un paso de construcción. Podríamos ver más implementaciones renderizadas del lado del servidor de Sass, Post CSS, etc. Scope CSS, como en Vue y Svelte, sería una gran adición.
Muy bien. Pasemos al estilo. Cuando hablé por primera vez sobre Fresh, mencioné que no había un paso de construcción. Entonces, ¿cómo afecta eso al estilo de nuestras aplicaciones? Fresh te da la opción de habilitar TWIN, una implementación renderizada del lado del servidor de Tailwind. Esto es genial si usas Tailwind, pero si los proyectos en los que estás trabajando no usan Tailwind, ¿cuáles son tus opciones? Primero, diría que el CSS moderno es bastante impresionante hoy en día, por lo que literalmente podrías optar por una buena hoja de estilo antigua. El hecho de que los selectores anidados estén llegando a los navegadores y solo tengamos variables CSS y otras ventajas como has en CSS hace que esta sea una opción convincente. También podrías agregar un paso de construcción que comprometa los artefactos de construcción de tus herramientas de CSS. Podrías lograr esto con una acción de GitHub, o alguna otra forma de automatización. Aunque funcionaría, no se siente bien comprometer los artefactos de construcción en la base de código y también va en contra de una de las promesas de Fresh, sin paso de construcción. Creo que lo que vamos a ver aquí es innovación por parte de los usuarios donde podríamos ver más implementaciones renderizadas del lado del servidor de cosas como Sass, Post CSS, etc., muy parecido a el proyecto TWIN. Otra cosa que me encantaría ver llegar a Fresh es Scope CSS. Lo tenemos en otros frameworks como Vue, Svelte.
Islands permiten bolsillos de interactividad en tu sitio o aplicación. Fresh utiliza la arquitectura de Islands, acuñada por Jason Miller, el creador de Preact. Solo el JavaScript para las islands se carga cuando se carga una página con islands. Fresh tiene dos carpetas de componentes: components e islands. Los componentes en la carpeta components se renderizan solo del lado del servidor, mientras que los componentes en la carpeta islands se renderizan del lado del servidor y reviven la interactividad del lado del cliente.
Bien, hablemos de islands. ¿Qué es una island de todos modos? Lo mencioné brevemente al describir la arquitectura de Fresh, pero profundizaremos un poco más en la arquitectura ahora. En resumen, permite bolsillos de interactividad en tu sitio o aplicación. Dejaré este fragmento de una publicación de blog de Jason Miller por un minuto, pero Jason Miller, una de las personas junto a Katie Seiler-Miller, acuñó el término arquitectura de islands.
De hecho, es apropiado que Jason sea una de las personas que acuñó este término, ya que también es el creador de Preact, que Fresh utiliza. En la arquitectura de islands, el objetivo es enviar principalmente HTML estático y luego marcar ciertas regiones del modelo de objeto del documento, es decir, el DOM, como disponibles para hidratar, o para usar la terminología de Fresh, revivir. Cuando se carga una página con islands, solo se carga el Javascript para esas islands. Mencioné que Fresh no sirve Javascript al cliente por defecto. Entonces, ¿cómo habilitamos la interactividad del lado del cliente de la que estamos hablando en la arquitectura de islands? Fresh tiene dos carpetas de componentes. Hay una carpeta de components y una carpeta de islands.
Los componentes en la carpeta components siempre se renderizarán solo del lado del servidor, incluso si agregas interactividad del lado del cliente a ellos. Y los componentes en la carpeta islands se renderizarán del lado del servidor así como una vez que la página se cargue y la interactividad del lado del cliente será revivida. Así que, veamos un componente interactivo clásico: un contador. Tiene un par de botones, si haces clic en más uno incrementa el contador, y si haces clic en menos uno decrementa el contador. Y en este caso aquí, tenemos un par.
Los componentes que son islands se renderizan del lado del servidor por Fresh. El marcado renderizado para las islands es visible en la vista del código fuente de la página. Fresh agrega un script con el ID __FRSH_state, que contiene un array de props para cada island. La función revive en Fresh toma la lista de componentes y el estado inicial para mapear correctamente el estado inicial. Los componentes de island en Fresh se renderizan con comentarios HTML, denotados por FRSH seguido del nombre del componente y el índice del array del estado del componente de island. Este es un detalle de implementación gestionado por Fresh. El sitio de demostración muestra componentes de contador y una lista de películas con middlewares en ejecución.
Entonces, ¿cómo revivimos una island? Entonces, esencialmente lo que sucede es que los componentes que son islands se renderizan del lado del servidor por Fresh y si hicieras una vista del código fuente de la página que se cargó, en realidad verías el marcado renderizado para esa island o islands en particular. Junto con el marcado que se renderiza para esas islands, Fresh también agrega un script de tipo application JSON con el ID underscore underscore FRSH underscore state como el ID y allí hay un array. En ese array, el primer elemento es otro array que es un array de todos los props para cada island que está en la página. El segundo elemento en el array está actualmente vacío allí, pero eso es para plugins. Eso es algo que realmente no vamos a tocar hoy, pero si estás interesado en los plugins, puedes echar un vistazo a la documentación de Fresh.
Así que como puedes ver aquí, tengo JSX para mi contador y comienza en el lado del servidor donde digo que estoy pasando un prop con el valor tres para el prop de inicio y cuando se renderiza en la página, veremos que los props iniciales para ese componente en particular se cargan en el array que mencioné. Entonces, ¿cómo se revive? Así que tenemos ese estado fresh que acabo de mencionar y luego una de las cosas que hace Fresh es junto con el JavaScript relacionado con esa island en particular, tiene una función de revive y esa función de revive toma la lista de los componentes, por ejemplo aquí el contador y también pasa el primer elemento del estado que son todos los props para todas las islands como mencioné. En el ejemplo anterior solo había una island, pero si hubiera más de una island ¿cómo mapea Fresh el estado inicial correctamente? Así que si tenemos un par aquí, veremos que simplemente se siguen agregando al array pero ¿cómo sabe Fresh que el contador con el prop de inicio de 3 y el contador de inicio con prop 5 se mapean correctamente al array allí?
Hablamos sobre denotar regiones interactivas en el DOM al hablar sobre la arquitectura de islands. Los componentes de island en Fresh se renderizan del lado del servidor como mencioné, pero también se renderizan con comentarios HTML que los rodean. El comentario está prefijado con FRSH seguido del nombre del componente, dos puntos y luego el índice del array de donde vive el estado del componente de island en el estado inicial para todas las islands que se cargó inicialmente. No importa cuántos componentes de island diferentes haya o cuántas instancias de cada uno, el índice del array se incrementará en cada comentario HTML basado en el orden de las islands en el DOM. Una cosa a tener en cuenta es que esto es solo un detalle de implementación, nunca necesitarás gestionar esto tú mismo, solo lo encuentro útil para entender la tecnología subyacente.
Bien, vamos a pasar a una breve demo. Así que voy a movernos aquí. Así que lo que tenemos aquí es... Solo hice un pequeño sitio de demo aquí. Tiene algunas páginas, así que la página de inicio aquí donde tenemos algunas islands, así que tengo tres componentes de contador aquí. Cada uno está gestionando su propio estado. Y también tengo una lista de películas. Eso va a la ruta de películas. Y podemos cargar una película, por ejemplo, como Top Gun. Y si abro el panel de red aquí, vamos a refrescar eso de nuevo, y esto tiene dos middlewares ejecutándose. Y como dije, estaba el primer middleware en la carpeta raíz de rutas y podemos ver que tiene el encabezado x-conference que ese middleware proporciona. Y luego el middleware de subcarpeta agrega el encabezado x-movie dash page, así como el control de caché de 60 segundos. Bien, así que podemos cerrar eso. Y aquí hay un ejemplo de una página híbrida. Así que solo voy a agregar una película. Así que digamos, El Señor de los Anillos. Y le daré una calificación de cinco, y voy a enviarlo.
En esta demo, usamos una ruta híbrida con handlers para publicar nuevas películas en la página. La demo utilizó una base de datos en memoria en lugar de una base de datos real. La vista del código fuente de la página muestra cómo Fresh se inicia, carga el JavaScript del contador y los estilos, y almacena en caché los activos durante un año. El código renderizado incluye los componentes, el estado de Fresh y el método revive. El sitio de demostración está desplegado en imdeveloper.com/fresh-demo, y el código fuente está disponible en GitHub. Recursos adicionales sobre Fresh, Deno, Preact, TypeScript, estándares web y la compatibilidad de nodo de Dino se pueden encontrar en imdeveloper.com/fresh.
Así que estamos en la misma página, y la ruta híbrida tiene handlers en ella, en el objeto handler. Y en este caso particular, estoy pasando un post, y eso es lo que nos permite publicar de nuevo en la página y agregar la nueva película aquí. Para los propósitos de esta demo, no utilicé una base de datos. Solo está usando una variable, así que una base de datos en memoria. Hablar sobre datos está totalmente fuera del alcance de la charla, pero solo sepan que hay un montón de gente trabajando en el problema de los datos en el edge.
Muy bien, así que vamos a terminar la demo aquí con... Esto es lo que parece la vista del código fuente de esa primera página con los tres diferentes cítricos de colores. He quitado muchas cosas solo para poder desplazarme a través de ella. Lo primero es que Fresh está comenzando aquí, eso es lo que es ese script. Puedes ver que la carpeta aquí se basa en el ID de compilación. Y luego podemos ver que solo carga mi JavaScript del contador, que es para la island. Y luego tenemos mi estilo, como mencioné, y está usando el helper de activos, y está dándole un ID único, y tiene el... Está almacenado en caché por un año, como mencioné.
Solo quería mostrar brevemente aquí, así que este es literalmente el código que se renderizó, menos quité algunos SVGs por brevedad, pero podemos ver aquí, por ejemplo, que tengo el primer componente aquí, está denotado con los comentarios HTML, y luego hay un segundo, y un tercero. Luego tenemos el estado fresh aquí, y podemos ver allí, los tres allí. Y luego tenemos ese método revive aquí abajo, y podemos ver que está ejecutándose aquí, y tenemos nuestro componente de contador, y luego el estado que estamos pasando, que son los props para todo eso. Y eso es prácticamente la demo.
Muy bien, volvamos a la presentación de diapositivas. Y sí, si estás interesado en la demo, está desplegada en imdeveloper.com slash fresh dash demo. También puedes ver el código fuente, está en github.com slash nickyt online slash fresh dash talk dash demo. Y terminaremos con solo algunos recursos que creo que todos encontrarán útiles. Así que hay un montón de cosas sobre Fresh, Deno, Preact, algo de TypeScript, estándares web, y también algunas cosas más nuevas con Dino como la compatibilidad con node, y también un enlace a el winter CG. Para los interesados, la presentación de diapositivas está disponible en imdeveloper.com slash fresh. Y eso es prácticamente todo. No pudimos cubrir todo en unos 20 minutos, pero espero que esto les haya dado a todos suficiente introducción para emocionarse con Fresh.
We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career
Comments