
División de código. La división de código está en todas partes. Sin embargo, ¿por qué? Solo porque hay demasiado javascript en la actualidad, y no todos están en uso en el mismo momento.
JS es algo muy pesado . No para su iPhone Xs o su nueva computadora portátil i9, sino para millones (probablemente miles de millones) de propietarios de dispositivos más lentos . O, al menos, para tus relojes.
Entonces, JS es malo, pero lo que sucedería si lo deshabilitáramos , el problema desaparecería ... para algunos sitios y desaparecería "con sitios" para los basados en React. Pero de todos modos, hay sitios que podrían funcionar sin JS ... y hay algo que deberíamos aprender de ellos ...
División de código
Hoy tenemos dos caminos por recorrer, dos maneras de mejorarlo o no empeorarlo:
1. Escribe menos código
Eso es lo mejor que puedes hacer. Si bien React Hooks
le permite enviar un poco menos de código, y las soluciones como Svelte
permiten generar menos código de lo habitual , eso no es tan fácil de hacer.
No se trata solo del código, sino también de la funcionalidad : para mantener el código "compacto", debe mantenerlo "compacto". No hay forma de mantener pequeño el paquete de aplicaciones si está haciendo tantas cosas (y se envió en 20 idiomas).
Hay formas de escribir código corto y sólido , y hay formas de escribir la implementación opuesta: la empresa sangrienta . Y, ya sabes, ambos son legítimos.

Pero el problema principal: el código en sí. Una aplicación de reacción simple podría pasar fácilmente por alto "recomendado" 250kb. Y puede pasar un mes optimizándolo y hacerlo más pequeño. Las optimizaciones "pequeñas" están bien documentadas y son bastante útiles: simplemente obtenga bundle-analyzer
con size-limit
y vuelva a ponerse en forma.
Hay muchas bibliotecas, que luchan por cada byte, tratando de mantenerlo dentro de sus límites: preact y storeon , por nombrar algunas.
Pero nuestra aplicación está un poco más allá de 200kb. Está más cerca de 100Mb . Eliminar kilobytes no tiene sentido. Incluso eliminar megabytes no tiene sentido.
Después de un momento, es imposible mantener su aplicación pequeña. Se hará más grande en el tiempo.
2. Enviar menos código
Alternativamente, code split
. En otras palabras, rendirse . Tome su paquete de 100mb y haga veinte paquetes de 5mb. Honestamente, esa es la única forma posible de manejar su aplicación si es grande: cree un paquete de aplicaciones más pequeñas a partir de ella.
Pero hay una cosa que debe saber ahora: cualquier opción que elija, es un detalle de implementación, mientras buscamos algo más confiable.
La verdad sobre la división de código
La verdad sobre la división de código es que su naturaleza es SEPARACIÓN DE TIEMPO . No solo está dividiendo su código, lo está dividiendo de una manera en la que usará la menor cantidad posible en un solo punto de tiempo.
Simplemente no envíe el código que no necesita en este momento. Deshazte de eso.

Fácil de decir, difícil de hacer. Tengo algunas aplicaciones pesadas, pero no divididas adecuadamente, donde cualquier página se carga como el 50% de todo. A veces code splitting
convierte en code separation
, quiero decir: puede mover el código a los diferentes fragmentos, pero aún así, usarlo todo. Recuerde que "No envíe el código que no necesita en este momento" , necesitaba el 50% del código, y ese era el verdadero problema.
A veces, simplemente agregar import
aquí y allá no es suficiente. Hasta que no sea la separación del tiempo , sino solo la separación del espacio , no importa en absoluto.
Hay 3 formas comunes de división de código:
- Solo
import
dinámica. Apenas usado solo en estos días. Se trata más de problemas con el seguimiento de un estado . - Componente
Lazy
, cuando puede posponer la representación y carga de un componente React. Probablemente el 90% de la "división de código de reacción" en estos días. - Lazy
Library
, que en realidad es .1
, pero se le dará un código de biblioteca mediante React render props. Implementado en componentes reactivos importados y componentes cargables . Muy útil, pero no muy conocido.
División de código de nivel de componente
Este es el más popular. Como división de código por ruta o división de código por componente. No es tan fácil hacerlo y, como resultado, mantener buenos resultados de percepción . Es la muerte de Flash of Loading Content
.
Las buenas técnicas son:
- cargar
js chunk
y data
para una ruta en paralelo. - use un
skeleton
para mostrar algo similar a la página antes de cargar la página (como Facebook). prefetch
fragmentos, incluso puede usar guess-js para una mejor predicción.- use algunos retrasos, indicadores de carga,
animations
y Suspense
(en el futuro) para suavizar las transiciones.
Y, ya sabes, todo se trata de rendimiento perceptivo .

Imagen de UX mejorada con elementos fantasma
Eso no suena bien
Sabes, podría llamarme un experto en división de código, pero tengo mis propios fallos.
A veces podría fallar en reducir el tamaño del paquete. A veces podría no mejorar el rendimiento resultante, siempre y cuando the _more_ code splitting you are introducing - the more you spatially split your page - the more time you need to _reassemble_ your page back
*. Se llama ondas de carga .
- sin SSR o pre-renderizado. SSR adecuado es un cambio de juego en este momento.

La semana pasada tengo dos fallas:
- Perdí en una comparación de biblioteca , siempre que mi biblioteca fuera mejor, pero MUCHO más grande que otra. No he podido "1. Escribir menos código" .
- optimizar un sitio pequeño, hecho en React por mi esposa. Estaba usando la división de componentes basada en la ruta, pero el
header
y el footer
se mantuvieron en el paquete principal para hacer las transiciones más "aceptables". Solo unas pocas cosas, estrechamente unidas entre sí, se dispararon hacia el lado del paquete hasta 320kb (antes de gzip). No había nada importante, y nada que realmente pudiera eliminar. Una muerte por mil cortes . No he podido enviar menos código .
React-Dom fue del 20%, core-js fue del 10%, react-router, jsLingui, react-powerplug ... 20% del código propio ... Ya hemos terminado.

La solucion
Empecé a pensar en cómo resolver mi problema y por qué las soluciones comunes no funcionan correctamente para mi caso de uso.
Que hice He enumerado todas las ubicaciones cruciales, sin las cuales la aplicación no funcionaría en absoluto, e intenté entender por qué tengo el resto.
Fue una sorpresa Pero mi problema estaba en CSS. En transición CSS vainilla.
Aqui esta el codigo
Me gustaría dividir en código esta pieza en su conjunto, pero esto es algo que no pude hacer debido a dos razones:
- la información debe ser visible de inmediato, una vez requerida, sin demora. Un requisito comercial.
- la información "cromo" debería existir antes, para la propiedad manejar la transición.
Este problema podría resolverse parcialmente mediante CSSTransitionGroup o reacondicionamiento . Pero, ya sabes, arreglar un código agregando otro código suena extraño, incluso si en realidad es suficiente . Quiero decir que agregar más código podría ayudar a eliminar aún más código. Pero ... pero ...
¡Debería haber una mejor manera!
TL; DR: hay dos puntos clave aquí:
DisplayData
tiene que ser montado , y existe en el DOM antes.FocusLock
también debería existir antes, para no causar el montaje de DisplayData
, pero sus cerebros no son necesarios al principio.
Así que cambiemos nuestro modelo mental
Batman y Robin
Supongamos que nuestro código es Batman y Robin. Batman puede con la mayoría de los malos, pero cuando no puede, su compañero Robin viene al rescate.
Una vez más, Batman se enfrentará a la batalla, Robin llegará más tarde.
Este es Batman:
+<FocusLock - enabled={componentControl.value} +> - {componentControl.value && <PageTitle title={componentControl.value.title}/>} + <DisplayData + data={componentControl.value} + visible={componentControl.value !== null} + /> +</FocusLock>
Este es su compañero, Robin ::
-<FocusLock + enabled={componentControl.value} -> + {componentControl.value && <PageTitle title={componentControl.value.title}/>} - <DisplayData - data={componentControl.value} - visible={componentControl.value !== null} - /> -</FocusLock>
Batman y Robin podrían formar un EQUIPO , pero en realidad son dos personas diferentes.
Y no lo olvide, todavía estamos hablando de división de código . Y, en términos de división de código, ¿dónde está el compinche? ¿Dónde está Robin?

en un sidecar Robin está esperando en un trozo de sidecar .
Sidecar
Batman
aquí es todo lo visual que su cliente debe ver lo antes posible. Idealmente al instante.Robin
aquí es todo lógico y características interactivas sofisticadas, que pueden estar disponibles un segundo después, pero no desde el principio.
Sería mejor llamar a esto una división de código vertical donde existen ramificaciones de código en paralelo, en oposición a una división de código horizontal común donde se cortan ramas de código.
En algunos países , este trío era conocido como replace reducer
u otras formas de lógica de reducción de carga lenta y efectos secundarios.
En algunas otras tierras , se conoce como "3 Phased" code splitting
.
Es solo otra separación de preocupaciones, aplicable solo a casos, donde puede diferir la carga de una parte de un componente, pero no de otra parte.

imagen de Building the New facebook.com con React, GraphQL y Relay , donde importForInteractions
o importAfter
son el sidecar
.
Y hay una observación interesante : mientras Batman
es más valioso para un cliente, siempre que sea algo que el cliente pueda ver , siempre está en forma ... Mientras que Robin
, ya sabes, podría tener un poco de sobrepeso y requerir muchos más bytes para viviendo
Como resultado, Batman solo es algo mucho más llevadero para un cliente, proporciona más valor a un costo menor. Eres mi héroe Bat!
Lo que se podría mover a un sidecar:
- mayoría de
useEffect
, componentDidMount
y amigos. - como todos los efectos modales . Es decir,
focus
y scroll
cerraduras. Primero puede mostrar un modal, y solo luego hacer modal modal , es decir, "bloquear" la atención del cliente. - Formas Mueva toda la lógica y las validaciones a un sidecar y bloquee el envío de formularios hasta que se cargue esa lógica. El cliente podría comenzar a llenar el formulario, sin saber que es solo
Batman
. - Algunas animaciones Toda una
react-spring
en mi caso. - Algunas cosas visuales. Al igual que las barras de desplazamiento personalizadas , que pueden mostrar barras de desplazamiento elegantes un segundo después.
Además, no olvide: cada pieza de código, descargada en un sidecar, también descarga cosas como core-js poly- y ponyfills, utilizadas por el código eliminado.
La división de código puede ser más inteligente de lo que es hoy en nuestras aplicaciones. Debemos darnos cuenta de que hay 2 tipos de código para dividir: 1) aspectos visuales 2) aspectos interactivos. Este último puede llegar unos momentos más tarde. Sidecar
hace que sea más fácil dividir las dos tareas, dando la percepción de que todo se cargó más rápido . Y lo hará
La forma más antigua de dividir código
Si bien aún puede no estar muy claro cuándo y qué es un sidecar
, daré una explicación simple:
Sidecar
es TODOS TUS SCRIPTS . Sidecar es la forma en que dividimos los códigos antes de todas esas cosas frontend que obtuvimos hoy.
Estoy hablando de la Representación del lado del servidor ( SSR ), o simplemente HTML , todos estábamos acostumbrados ayer. Sidecar
hace las cosas tan fáciles como solía ser cuando las páginas contenían HTML y la lógica vivían por separado en scripts externos incrustables (separación de preocupaciones).
Teníamos HTML, más CSS, más algunos scripts en línea, más el resto de los scripts extraídos en archivos .js
.
HTML
+ CSS
+ inlined-js
eran Batman
, mientras que los scripts externos eran Robin
, y el sitio podía funcionar sin Robin y, honestamente, parcialmente sin Batman (continuará la pelea con ambas piernas (scripts en línea) rotos). Eso fue ayer, y muchos sitios "no modernos y geniales" son los mismos hoy.
Si su aplicación admite SSR, intente deshabilitar js y haga que funcione sin ella. Entonces quedaría claro qué se podía mover a un sidecar.
Si su aplicación es un SPA solo del lado del cliente, intente imaginar cómo funcionaría, si existiera SSR.
Por ejemplo, theurge.com , escrito en React, es completamente funcional sin ningún js habilitado .
Hay muchas cosas que puede descargar a un sidecar. Por ejemplo:
- comentarios Puede enviar código para
display
comentarios, pero no answer
, siempre que requiera más código (incluido el editor WYSIWYG), que no se requiere inicialmente. Es mejor retrasar un cuadro de comentarios , o incluso simplemente ocultar la carga de código detrás de la animación, que retrasar toda una página. - reproductor de video Enviar "video" sin "controles". Cárguelos un segundo después, el cliente podría intentar interactuar con él.
- galería de imágenes, como
slick
. No es un gran problema dibujarlo , pero es mucho más difícil de animar y administrar. Está claro qué se podría mover a un sidecar.
Solo piense en lo que es esencial para su aplicación, y lo que no es del todo ...
Detalles de implementación
(DI) División de código de componente
La forma más simple de sidecar
es fácil de implementar: simplemente mueva todo a un subcomponente, puede dividir el código de una manera "antigua". Es casi una separación entre los componentes Smart y Dumb, pero esta vez Smart no contacta a uno Dumb, es lo contrario.
const SmartComponent = React.lazy( () => import('./SmartComponent')); class DumbComponent extends React.Component { render() { return ( <React.Fragment> <SmartComponent ref={this} /> // <-- move smart one inside <TheActualMarkup /> // <-- the "real" stuff is here </React.Fragment> } }
Eso también requiere mover el código de inicialización a uno tonto, pero aún puede dividir el código en la parte más pesada de un código.
¿Puedes ver un patrón de división de código parallel
o vertical
ahora?
useSidecar
La construcción del nuevo facebook.com con React, GraphQL y Relay , que ya he mencionado aquí, tenía un concepto de loadAfter
o importForInteractivity
, que es un concepto de sidecar bastante similar.
Al mismo tiempo, no recomendaría crear algo como useSidecar
siempre y cuando intentes intencionalmente usar hooks
dentro, pero la división de código en esta forma rompería la regla de los ganchos .
Prefiere una forma de componente más declarativa. Y puede usar hooks
dentro del componente SideCar
.
const Controller = React.lazy( () => import('./Controller')); const DumbComponent = () => { const ref = useRef(); const state = useState(); return ( <> <Controller componentRef={ref} state={state} /> <TheRealStuff ref={ref} state={state[0]} /> </> ) }
Captación previa
No lo olvide: puede usar sugerencias de prioridad de carga para precargar o pretratar el sidecar
y hacer que el envío sea más transparente e invisible.
Cosas importantes: las secuencias de comandos de captación previa lo cargarían a través de la red , pero no se ejecutarían (y gastarían la CPU) a menos que realmente sea necesario.
SSR
A diferencia de la división de código normal , no se requiere ninguna acción especial para SSR. Sidecar
podría no ser parte del proceso de SSR y no ser requerido antes del paso de hydration
. Podría posponerse "por diseño".
Por lo tanto, siéntase libre de usar React.lazy
(idealmente algo sin Suspense
, no necesita ningún indicador de recuperación (carga) aquí), o cualquier otra biblioteca, con, pero mejor sin soporte de SSR para omitir fragmentos de sidecar durante el proceso de SSR.
Las partes malas
Pero hay algunas partes malas de esta idea.
Batman no es un nombre de producción
Si bien Batman
/ Robin
podría ser un buen concepto mental, y el sidecar
es una combinación perfecta para la tecnología en sí misma, no hay un "buen" nombre para el maincar
. No existe un maincar
, y obviamente Batman
, Lonely Wolf
, Solitude
, Driver
y Solo
no se usarán para nombrar una parte que no sea un sidecar.
Facebook ha utilizado la display
y la interactivity
, y esa podría ser la mejor opción para todos nosotros.
Si tienes un buen nombre para mí, déjalo en los comentarios
Sacudida del árbol
Se trata más de la separación de las preocupaciones desde el punto de vista del paquete . Imaginemos que tienes a Batman
y Robin
. Y stuff.js
Entonces puede intentar dividir el código del componente componente para implementar un sidecar
En resumen: el código anterior funcionaría, pero no hará "el trabajo".
- si está utilizando solo
batman
de stuff.js
, la sacudida del árbol solo lo mantendría. - si está usando solo
robin
de stuff.js
, la sacudida del árbol solo lo mantendría. - pero si está utilizando ambos, incluso en diferentes fragmentos, ambos se
stuff.js
en una primera aparición de stuff.js
, es decir, el paquete principal .
La sacudida de árboles no es amigable para la división de código. Tienes que separar las preocupaciones por archivos.
Des-importar
Otra cosa, olvidada por todos, es el costo de javascript. Era bastante común en la era jQuery, la era de la carga útil de jsonp
cargar el script (con json
payload), obtener la carga útil y eliminar el script.
Hoy en día todos import
script, y se importará para siempre, incluso si ya no es necesario.
Como dije antes, hay demasiado JS, y tarde o temprano, con la navegación continua , cargará todo. Deberíamos encontrar una manera de eliminar la importación que ya no necesite trozos, borrando todos los cachés internos y liberando memoria para hacer que la web sea más confiable, y no para aplastar la aplicación con excepciones de falta de memoria.
Probablemente, la capacidad de un-import
(webpack podría hacerlo ) es una de las razones por las que debemos seguir con la API basada en componentes , siempre y cuando nos brinde la capacidad de manejar el unmount
.
Hasta ahora, los estándares de los módulos ESM no tienen nada que ver con cosas como esta, ni con el control de caché ni con la inversión de la acción de importación.
Crear una biblioteca habilitada para sidecar
Hoy en día solo hay una forma de crear una biblioteca habilitada para sidecar
:
- divide tu componente en partes
- exponer una parte
main
y una parte connected
(para no romper la API) a través del index
- exponer un
sidecar
través de un punto de entrada separado. - en el código de destino - importe la parte
main
y el sidecar
- la sacudida del árbol debería cortar una parte connected
.
Esta vez, la sacudida del árbol debería funcionar correctamente, y el único problema es cómo nombrar la parte main
.
export const Main = ({sidecar, ...props}) => ( <div> {sidecar} .... </div> );
import Main from './Component'; import Sidecar from './Sidecar'; export const Connected = props => ( <Main sidecar={<Sidecar />} {...props} /> );
export * from './Main'; export * from './Connected';
import * from './Sidecar';
En resumen, el cambio podría representarse mediante una pequeña comparación
La dynamic import
teóricamente dynamic import
podría usarse dentro de node_modules, haciendo que el proceso de ensamblaje sea más transparente.
De todos modos, no es más que un patrón de children
/ slot
, tan común en React.
El futuro
Facebook
demostró que la idea es correcta. Si no has visto ese video, hazlo ahora mismo. Acabo de explicar la misma idea desde un ángulo un poco diferente (y comencé a escribir este artículo una semana antes de la conferencia F8).
En este momento requiere que se apliquen algunos cambios de código a su base de código. Se requiere una separación más explícita de las preocupaciones para separarlas realmente, y dejar que el código se divida no horizontalmente, sino verticalmente, enviando código menor para una mayor experiencia del usuario.
Sidecar
, probablemente, es la única forma, excepto la SSR de la vieja escuela, de manejar bases de códigos GRANDES. Última oportunidad de enviar una cantidad mínima de código, cuando tienes mucho.
Podría hacer una aplicación GRANDE más pequeña, y una aplicación PEQUEÑA aún más pequeña.
Hace 10 años, el sitio web mediano estaba "listo" en 300 ms, y estaba realmente listo unos pocos milisegundos después. Hoy segundos e incluso más de 10 segundos son los números comunes. Que pena
Hagamos una pausa y pensemos: cómo podríamos resolver el problema y hacer que UX vuelva a ser genial ...

En general
- La división de código de componente es una herramienta muy poderosa, que le brinda la capacidad de dividir algo por completo , pero tiene un costo: es posible que no muestre nada excepto una página en blanco o un esqueleto por un tiempo. Esa es una separación horizontal.
- La división del código de la biblioteca podría ayudar cuando la división de componentes no lo haría. Esa es una separación horizontal.
- El código, descargado en un sidecar, completaría la imagen y puede permitirle proporcionar una experiencia de usuario mucho mejor. Pero también requeriría un esfuerzo de ingeniería. Esa es una separación vertical.
Tengamos una conversación sobre esto .
Para! Entonces, ¿qué pasa con los problemas que trataste de resolver?
Bueno, eso fue solo la primera parte. Estamos en el final del juego ahora , tomaría algunas semanas más escribir la segunda parte de esta propuesta. Mientras tanto ... ¡sube al sidecar!