La leyenda del marco del poder

Recientemente, la tendencia de "marcos desaparecidos" está ganando popularidad, cuya locomotora, sin lugar a dudas, puede considerarse SvelteJS , un marco de tiempo de compilación y un compilador de JavaScript de vainilla.

A pesar del hecho de que conceptualmente Svelte es muy simple, y aún más fácil de usar, muchos desarrolladores se preguntan cuál es la característica principal de este marco y todo el enfoque. ¿Por qué no se trata de un "marco javascript más"?

En este artículo, hablaré sobre uno de los muchos superpoderes de Svelte que pueden hacerte la vida más fácil.

Vamos a resolverlo, pero primero te contaré una leyenda ...



La leyenda del marco del poder


Algunos marcos fueron creados por los chicos de Google y Facebook, otros - tipos geniales, pero todos bajo la estrecha "atención" de Rich Harris .

Nueve marcos fueron creados para humanos, siete parecen ser para enanos. Otros tres marcos (reaccionar, vue, angular) fueron para elfos.

Después de crear los marcos e implementarlos en miles de proyectos, Rich Harris creó personalmente y en secreto un marco ...

Un marco para gobernarlos a todos,
Un marco para encontrarlos,
Un marco para traerlos a todos
Y los unimos.

- El señor de los marcos

El problema


Estoy seguro de que muchos de ustedes que han estado comprometidos seriamente y durante mucho tiempo en el desarrollo front-end han enfrentado repetidamente el problema de elegir herramientas para su proyecto actual y / o próximo.
La variedad de todo tipo de paquetes, utilidades, ballenas, marcos, bibliotecas y otras soluciones está fuera de escala como nunca antes. Y lo más importante, todo este movimiento continúa acelerándose.

Todo esto, de una forma u otra, se aplica a la elección del marco. Probablemente no se equivoque si asumo que solo unos pocos equipos modernos y compañías comienzan nuevos proyectos sin usar ningún marco js. Por supuesto, cuando se trata de aplicaciones web modernas, no solo de sitios web. Y todo estaría bien si tanto en su proyecto no dependiera de ello.


Juzguen ustedes mismos, la composición y las características del equipo dependen en gran medida del marco que elijan, y todo el proceso de caza ciertamente depende. A veces, el presupuesto y los plazos incluso dependen de esto. En resumen brrr.

Pero los problemas reales comienzan, si en algún lugar en el medio del proyecto, te das cuenta de que has hecho una elección incorrecta. Algo no creció juntos y giró. El marco requería un poco más de tiempo para dominar, un equipo un poco más grande, resultó ser un poco menos rápido, un poco no adecuado para sus objetivos o estilo de desarrollo, etc. Y lo más importante, ahora su proyecto está 100% vinculado a este marco y no puede simplemente tomarlo y reescribirlo en otra cosa.

Aún más ofensivo, cuando, sin embargo, haya completado el proyecto con éxito, comprende que, en general, no está muy contento. Y probablemente, no nos gustaría escribir el próximo proyecto en el mismo marco. Por lo tanto, todas esas soluciones "reutilizadas" por las que nos esforzamos pueden arrojarse a la tubería.

En realidad, al diablo con eso, con un código comercial que implementa una tarea comercial específica, funciona bien. Pero escribiste un "% inserta tu% con blackjack y chicas con baja responsabilidad social", y querías usarlo en tu próximo proyecto, pero esta infección está estrechamente vinculada al marco actual desde el que ya estás viendo un tipo.

Otra variación del mismo problema: imagine que es una empresa grande, como Yandex. Tiene una gran cantidad de proyectos, incluso algunos de los cuales son conocidos solo por algunos empleados, y cada proyecto ya ha experimentado todo lo que describí anteriormente. El problema es que todos estos proyectos se sientan y odian los diferentes marcos que seleccionaron inicialmente.

Y aquí está su maravilloso liderazgo, decidió competir con Google Material Design y enviarlo en una cruzada a las variadas interfaces de sus proyectos para llevarlos a un denominador común. Diseñadores astutos ya están dibujando nuevos botones y selectores y garabateando miles de páginas de pautas para el nuevo kit de interfaz de usuario único de sus componentes. Hurra camaradas!

No la vida, sino un cuento de hadas, ¿verdad? Solo queda encontrar la forma de extraer todos estos componentes nuevos en todos los proyectos que ya logró escribir en todos los marcos posibles. Si realmente hay mucho tiempo y dinero y hay un deseo estético, y lo más importante, la creencia de que "todo necesita ser unificado", entonces puedes poner un par de docenas de equipos para volver a escribir todo esto, por ejemplo, en React. Esto es correcto, porque la mierda aburrida en la que escribiste los últimos 2-3 años ya es moralmente obsoleta, pero React lo será para siempre. Bien, bien)

Hay otra manera Puede escribir un nuevo kit de interfaz de usuario maravilloso en un marco, crear una biblioteca de componentes reutilizables, por así decirlo, y luego simplemente usar este kit de interfaz de usuario en todos sus proyectos. ¿Suena bien? Por supuesto, pero sigue habiendo un problema: el tiempo de ejecución.

Si su proyecto está escrito en Angular (~ 500Kb), y decidió escribir un kit de interfaz de usuario en React (~ 98Kb), luego arrastre cada proyecto en un marco, otro marco, e incluso con un montón de dependencias, el kit de UI en sí es directo Digamos que no se ve óptimo.

Solución


Para ayudarnos a venir los marcos "desaparecidos", sin tiempo de ejecución. La condición principal aquí es que estén tan aislados como sea posible en términos de su ecosistema y que tengan mecanismos de integración externos y API correspondientes.

Un gran ejemplo de este marco es SvelteJS, sobre el cual ya se han escrito algunos artículos sobre Habré .

Entonces, imagine la situación en la que tenemos una aplicación en React. Quizás estamos cansados ​​de eso y queremos deshacernos de él, pero reescribir todo de una vez es un lujo inadmisible. O tal vez algunas partes de la aplicación requieren mejoras o refactorización. Bueno, o decidimos crear una biblioteca de un solo componente, y ahora escribiremos todos los componentes en Svelte y los usaremos en todos los proyectos. Presentado? Sí, por supuesto que no, nadie tiene tal fantasía. Echemos un vistazo a un ejemplo real.


Descargo de responsabilidad
Inmediatamente quiero llamar su atención sobre el hecho de que no soy un desarrollador de React y la última vez que "sentí" React en 2015. Por lo tanto, supongo que la forma en que escribí parte del ejemplo React puede herir los sentimientos de los reaccionarios creyentes . Lamento no juzgar estrictamente, especialmente porque el significado del artículo no cambia a partir de esto.


Por lo tanto, la tarea es implementar el componente Svelte listo para usar en la aplicación React, sin cambiar el componente en sí y sin incluir tiempo de ejecución adicional en la aplicación. Por ejemplo, tomaré el componente que busca usuarios de GitHub, que escribí para el artículo anterior "Cómo buscar usuarios en GitHub sin React + RxJS 6 + Recompose" .

El código de este componente se puede ver en REPL y el código de muestra de este artículo en el repositorio .

Crear una aplicación de reacción


Primero, cree un nuevo proyecto React utilizando la herramienta estándar de facto: create-react-app :

npx create-react-app my-app cd my-app npm start 

Ok, si vas al puerto 3000, parece que funciona.

Personaliza Svelte


Si no sabe nada sobre Svelte, entonces diré esto, en el contexto de la tarea Svelte, este es solo un paso más de su recopilador (webpack / rollup / gupl / grunt / etc), que le permitirá escribir componentes en formato SFC y compilarlos en vainilla javascript

En la comunidad Svelte, Rollup es más preferido, lo cual no es sorprendente, ya que tienen un autor: Rich Harris. Sin embargo, dado que CRA usa webpack, configuraremos Svelte a través de él. Para hacer esto, primero debe transferir las configuraciones del paquete web de react-scripts al proyecto para que podamos cambiarlas. Esto se hace usando el comando incorporado:

 npm run eject 


Hasta donde yo sé, este no es un enfoque kosher, pero por ejemplo, esta es la opción más conveniente.

Ahora que las configuraciones del paquete web están en la raíz del proyecto, puede instalar Svelte:

 npm i --save-dev svelte svelte-loader 


Presta atención a la bandera --save-dev , recuerda sí, no hay tiempo de ejecución.))))

El toque final, debe conectar el cargador apropiado en las configuraciones:

  { test: /\.svelte$/, use: { loader: 'svelte-loader', } }, 


En general, es habitual en la comunidad Svelte escribir archivos de componentes con la extensión .html , porque el componente Svelte es un archivo HTML válido. Sin embargo, para evitar posibles colisiones, en algunos casos, es mejor usar el formato de archivo .svelte personalizado.

Así lo hicimos, ahora todos los archivos .svelte incluidos en el proyecto serán interceptados por este cargador y compilados por Svelte.

Escribir un componente esbelto


Primero, es mejor configurar el editor de código, por ejemplo, para que aplique el resaltado de sintaxis html a los archivos con la extensión correspondiente. Algo como esto se hace en VS Code:

  "files.associations": { "*.svelte": "html" } 

Ahora cree una carpeta ./src/svelte_components/ y allí la carpeta del componente en sí. Después de eso, simplemente transferimos todos los archivos del ejemplo REPL a esta carpeta, dándoles simultáneamente una nueva extensión .svelte , y llamamos al archivo App.html Widget.svelte.

El resultado debería ser algo como esto:


En el mismo lugar creamos el archivo index.js en el que tendremos el código de integración Svelte y React.

Integrar


¿Quizás ahora quieres saber qué es la magia? La magia es que ya hemos hecho toda la magia. Mágicamente, ¿no es así?

En serio, ahora podemos usar los componentes de Svelte en nuestra aplicación React como constructores JS completamente normales, lo que significa que el código de integración con Svelte no será diferente de la integración con cualquier otro independiente. La documentación de React incluso contiene una sección dedicada a esto: Integración con otras bibliotecas .

El código de integración puede verse así:

 import React, { PureComponent } from 'react'; import Widget from './Widget.svelte'; export default class extends PureComponent { componentDidMount() { const { username } = this.props; this.widget = new Widget({ target: this.el, data: { username } }); } componentWillUnmount() { this.widget.destroy(); } render() { return ( <div ref={el => this.el = el}></div> ); } } 

En total, simplemente envolvimos el código de nuestro complejo componente Svelte en un componente React muy simple, que simplemente crea una nueva instancia del componente Svelte, pasando el elemento de montaje y los datos de los accesorios al crearlo. Además, no nos olvidamos de desinstalar el componente Svelte en el enlace componentWillUnmount.

Lo único que aún no hemos hecho es que no sincronizaron los valores del estado del componente. Es decir, si el componente padre arrojó otros accesorios al componente envoltorio, entonces deberían aplicarse al componente Svelte. Por el contrario, si los datos se han cambiado dentro del componente Svelte, deben revertirse.

Para hacer esto, asumimos que el componente React de nivel superior transmitirá la devolución de llamada onChange, que deberíamos extraer cuando ocurran cambios en el interior, y esperaremos cambios en los accesorios del componente wrapper en el gancho componentWillReceiveProps . Hagámoslo:

  componentDidMount() { ... this.widget.on('state', ({ current: { username }, changed }) => { if (changed.username) { this.props.onChange({ username }); } }); } componentWillReceiveProps({ username }) { this.widget.set({ username }); } 

Aquí usamos el evento de estado incorporado, que se activa cada vez que cambia el estado del componente Svelte. Un objeto que contiene el estado actual del componente ( actual ), el estado anterior ( anterior ) y la lista de propiedades modificadas ( modificadas ) se transfiere a la devolución de llamada. En consecuencia, simplemente verificamos si el nombre de usuario ha cambiado y llamamos a la devolución de llamada onChange, si es así.

En el enlace componentWillReceiveProps , configuramos el nuevo nombre de usuario utilizando el método incorporado set () .

Además de los componentes integrados, Svelte puede implementar eventos y métodos personalizados. Estas características agradables son las que le permiten describir la interfaz del componente y es bastante conveniente organizar la comunicación con el "mundo exterior".

Uso


Ahora intentemos usar nuestro widget directamente en la aplicación React. Para hacer esto, edite el archivo App.js generado por el iniciador:

 import React, { Component } from 'react'; import './App.css'; import GithubWidget from './svelte_components/GithubWidget'; class App extends Component { constructor() { super(); this.state = { username: '' }; } handleChange = (state) => { this.setState({ ...state }); } render() { return ( <div className="App"> <header className="App-header"> <h1>Github Widget for: {this.state.username}</h1> <GithubWidget onChange={this.handleChange} username={this.state.username} /> </header> </div> ); } } export default App; 

En resumen, lo usamos como un componente React regular. Y como resultado obtenemos:


Ya no está mal, ¿verdad?) Tenga en cuenta que el valor de nombre de usuario que ingresamos en el campo de texto del widget se envía inmediatamente a la aplicación React.

Vamos a finalizar


Enseñemos ahora a nuestro widget a buscar y mostrar no solo la tarjeta de usuario de GitHub, sino también la tarjeta del repositorio.

Primero, debe crear un nuevo componente Repo.svelte, que dibujará la tarjeta del repositorio. Para simplificar, acabo de copiar la plantilla y los estilos de User.svelte y los adapté a los datos del repositorio. Sin embargo, teóricamente este es un componente separado.

A continuación, debe enseñar el componente de control Widget.svelte para cambiar estos dos tipos de tarjetas sobre la marcha. Además, debe enseñarle a extraer diferentes solicitudes para el usuario y el repositorio.

Usaremos un campo para la entrada y determinaremos el tipo de datos por la presencia de "/" en el valor. Es decir, si necesita buscar al usuario, ingrese su nombre de usuario, y si es el repositorio, luego ingrese el nombre de usuario del usuario, luego "/" y el nombre del repositorio.

A primera vista, parece bastante confuso, pero en Svelte la solución tomará literalmente 5-6 líneas de código. Primero, conectemos un nuevo componente y método de API, que envolvemos en debounce:

 ... import Repo from './Repo.svelte'; ... import { getUserCard, getRepoCard } from './api.js'; ... const getRepo = debounce(getRepoCard, 1000); 

A continuación, cree una propiedad calculada que determinará qué tipo de tarjeta debemos mostrar:

 computed: { ... repo: ({ username }) => username.includes('/'), ... } 

Ahora agregue el interruptor de solicitudes a la API:

 computed: { ... card: ({ username, repo }) => username && (repo ? getRepo : getUser)(username), ... } 

Y finalmente, cambiando los componentes de la tarjeta según el tipo:

 computed: { ... Card: ({ repo }) => repo ? Repo : User, ... } 

Además, para reemplazar dinámicamente componentes, necesitamos usar una etiqueta especial Svelte, que dibuja el componente cuyo valor se pasa al atributo this :

 <svelte:component this={Card} {...card} /> 


Funciona ¿Te has dado cuenta? ¡Ya estamos escribiendo en Svelte dentro de la aplicación React! )))

Ahora enseñemos a nuestro widget a ocultar el campo de entrada e intente ingresar el nombre de usuario no dentro del widget, sino dentro de la aplicación React. ¿Importa cómo nuestra lógica de negocios obtendrá este valor?

Introducimos una nueva propiedad de búsqueda cuyo valor predeterminado es falso. Dependiendo de esta propiedad, el campo de entrada se mostrará o no se mostrará. Por defecto, en consecuencia, no habrá campo.

 {#if search} <input bind:value=username placeholder="username or username/repo"> {/if} ... <script> export default { ... data() { return { username: '', search: false }; }, ... }; </script> 

Ahora en App.js crearemos un campo de entrada en el lado Reaccionar de la aplicación y escribiremos el procesamiento correspondiente para el evento de entrada:

  ... handleUsername = (e) => { this.setState({ username: e.target.value }); } ... <h1>Github Widget for: {this.state.username}</h1> <input value={this.state.username} onChange={this.handleUsername} className="Username" placeholder="username or username/repo" /> 

Y también cópielo en la carpeta con el widget aquí es un spinner de svg en Svelte:

 <svg height={size} width={size} style="animation-duration:{speed}ms;" class="svelte-spinner" viewbox="0 0 32 32" > <circle role="presentation" cx="16" cy="16" r={radius} stroke={color} fill="none" stroke-width={thickness} stroke-dasharray="{dash},100" stroke-linecap="round" /> </svg> <script> export default { data() { return { size: 25, speed: 750, color: 'rgba(0,0,0,0.4)', thickness: 2, gap: 40, radius: 10 }; }, computed: { dash: ({radius, gap}) => 2 * Math.PI * radius * (100 - gap) / 100 } }; </script> <style> .svelte-spinner { transition-property: transform; animation-name: svelte-spinner_infinite-spin; animation-iteration-count: infinite; animation-timing-function: linear; } @keyframes svelte-spinner_infinite-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } </style> 

Y lo aplicaremos en el widget para que sea muy bonito:

 ... {#await card} <Spinner size="50" speed="750" color="#38b0ee" thickness="2" gap="40" /> {:then card} ... 

En mi opinión, resultó no muy malo:


El sombrero de copa con un fondo negro y un campo de entrada es una aplicación React, el bloque blanco a continuación es un widget Svelte. Estas son las tartas. )))

Repositorio

Conclusiones


Svelte es una gran herramienta para desarrollar aplicaciones web modernas basadas en componentes. Además, puede escribir rápida y convenientemente componentes y widgets de UI independientes reutilizables en él, que se pueden usar en cualquier aplicación web, incluso en combinación con otros marcos. También es ideal para microfrontas .

Svelte es perfecto para ti si:


  1. Desea comenzar un nuevo proyecto y no sabe qué marco elegir para esto.
  2. Tienes un proyecto, funciona y es mejor no tocarlo. Nuevos componentes y módulos, puede escribir en Svelte e integrarse perfectamente en el código existente.
  3. Ya tiene un proyecto, pero está parcial o completamente desactualizado y / o requiere una refactorización seria, hasta una reescritura completa. Puedes comenzar a reescribirlo en partes. En este caso, no necesita crear configuraciones complejas. Simplemente tome algún componente, vuelva a escribirlo en Svelte y ajuste el nuevo componente con el anterior. Sin embargo, el resto de la aplicación ni siquiera está al tanto de los cambios.
  4. Tiene varios proyectos en diferentes bases de código y, al mismo tiempo, le gustaría tener un único kit de interfaz de usuario y usarlo en cualquiera de estos proyectos. Escriba un kit de interfaz de usuario en Svelte y úselo en cualquier lugar. Esto es lindo

¿Quieres descubrir más casos interesantes? ¡Únete a nuestro canal de Telegram !

ACTUALIZACIÓN: gracias justboris por la pregunta correcta. Continuando con el ejemplo:

 import React, { PureComponent } from 'react'; import Widget from './Widget.svelte'; export default class extends PureComponent { componentDidMount() { ... this.widget = new Widget({ target: this.el, data: { username }, slots: { default: this.slot } }); ... } ... render() { return ( <div ref={el => this.el = el}> <div ref={el => this.slot = el}> {this.props.children} </div> </div> ); } } 


 <GithubWidget onChange={this.handleChange} username={this.state.username}> <p>Hello world</p> </GithubWidget> 

Source: https://habr.com/ru/post/es420113/


All Articles