Eu conheci o código dividido há muito tempo, no ano de 2008, quando o Yandex foi um pouco suspenso, e os scripts Yandex.Direct conectados de forma síncrona ao site simplesmente mataram esse site. Em geral, era normal naqueles dias se seus “scripts” são 10 arquivos que você conecta na única ordem correta, que ainda (com adiamento) ainda funciona bem.
Então comecei a trabalhar ativamente com cartões, e eles ainda estão conectados como scripts externos, é claro, com carga preguiçosa. Então, como membro da equipe Yandex.Maps, usei ativamente os ymodules para usar a trepidação de árvores no cliente, o que fornecia a divisão perfeita do código.
E então fui para o webpack
e React
, para o país de idiotas assustados que pareciam require.ensure
como um carneiro em um novo portão, e ainda fazê-lo.
A divisão de código não é um recurso uau, é um item obrigatório. Ainda assim, o SSR
não interferiria ...

Pequena introdução
Atualmente, quando os pacotes ficam mais gordos a cada dia, a divisão de código se torna mais importante do que nunca. No começo, as pessoas saíram dessa situação simplesmente criando pontos de entrada separados para cada página do aplicativo, o que geralmente é bom, mas não funciona para o SPA.
Então veio a função require.ensure
, hoje conhecida como dynamic import
(apenas importação), através da qual você pode simplesmente solicitar um módulo, que receberá um pouco mais tarde.
A primeira biblioteca sobre esse caso para o React era carregável por reagentes , o hype em torno do qual ainda não está muito claro para mim e que já morreu (apenas deixou de agradar o autor).
React.lazy
e React.lazy
-components (apenas @loadable
) serão a escolha mais ou menos “oficial”, e a escolha entre eles é óbvia:
- React.lazy é completamente incapaz de SSR (Server Side Rendering), da palavra em geral. Mesmo nos testes, ele cai sem danças especiais com um pandeiro, como "promessas síncronas".
- Um SSR carregável pode e, embora ofereça suporte ao Suspense, não é pior que o React.Lazy.
Em particular, o loadable suporta belos wrappers para carregar bibliotecas (loadable.lib, você pode acessar moment.js no React renderProp) e ajuda o webpack no lado do servidor a coletar uma lista de scripts, estilos e recursos usados para pré-busca (que o próprio webpack realmente não conhece). Em geral, leia a documentação oficial .
SSR
Em geral, todo o problema está no SSR. Para o CSR (Client Side Render), o React.lazy ou um script pequeno com 10 linhas serão adequados - isso definitivamente será suficiente e não faz sentido conectar uma grande biblioteca externa. Mas no servidor isso não será suficiente. E se você realmente não precisa de um SSR, pode pular mais a leitura. Você não tem problemas que precisam ser resolvidos por muito tempo.
SSR é uma dor. Eu (de alguma forma) sou um dos mantenedores de componentes carregáveis e é horrível quantos bugs saem de lugares diferentes. E a cada atualização, o webpack voa ainda mais.
SSR + CSS
Uma fonte ainda maior de problemas com SSRs é o CSS.
Se você tem componentes com estilo - não dói tanto - eles vêm com o transform-stream
que adicionará o que é necessário ao código final. O principal é que deve haver uma versão do SC em todos os lugares, caso contrário, o foco não funcionará - uma versão do SC não será capaz de dizer mais nada sobre si mesma, e o SC adora se multiplicar (verifique seu pacote). Para ser sincero, é justamente por causa dessa limitação que o foco geralmente falha .
A emoção C é mais simples - o adaptador styled
cospe <style>
na frente do próprio componente e o problema é resolvido. Simples, barato e alegre. Em princípio, é muito compatível com dispositivos móveis e otimiza bastante a primeira visualização. Mas um pouco estraga o segundo. E, pessoalmente, minha consciência não me permite embutir estilos como esse.
Com CSS comum (incluindo o obtido em várias bibliotecas CSS-JS com JS diferente), é ainda mais fácil - há informações sobre eles na coluna webpack e é "conhecido" qual CSS precisa ser conectado.
Ordem de conexão
Aqui o cachorro se enterrou. Quando devo me conectar?
O significado da divisão de código amigável ao SSR é que, antes de chamar o ReactDOM.hydrate
é necessário fazer o download de todos os "componentes" que já estão presentes na resposta do servidor, mas os scripts atualmente carregados no cliente não podem pagar.
Portanto, todas as bibliotecas oferecem um determinado retorno de chamada que será chamado quando tudo precisar carregar tudo, e você poderá iniciar o cérebro . Esse é o significado do trabalho das bibliotecas de divisão de códigos SSR.
O JS pode ser carregado a qualquer momento e, geralmente, sua lista é adicionada ao final do HTML, mas o CSS, para que não haja FOUC, deve ser adicionado ao início.
Todas as bibliotecas são capazes de fazer isso para o antigo renderToString
e todas as bibliotecas não podem fazer isso para o renderToNodeStream
.
Não importa se você possui apenas JS (isso não acontece) ou SC / Emotion (que se adicionará). Mas - se você tem "apenas CSS" - é isso. Eles estarão no final ou terão que usar renderToString
ou outro buffer, que fornecerá atraso TTFB (Time To First Byte) e reduzirá ligeiramente a sensação de ter esse SSR em geral.
E é claro - tudo isso está ligado ao webpack e de nenhuma outra maneira. Portanto, com todo o respeito a Greg, autor de componentes carregáveis - proponho considerar outras opções.
A seguir, uma agenda de três partes, cuja principal idéia é fazer algo que não é morto e não depende do empacotador.
1. React-Imported-Component
O React-Imported-Component não é um "carregador" ruim, com uma interface mais ou menos padrão, muito semelhante aos componentes carregáveis, que podem SSR para tudo que se move.
A ideia é muito simples.
Não é necessário stats.json
, adaptar-se à otimização do webpack (concatenação ou código comum) - você só precisa corresponder ao "rótulo" de uma importação na chave da matriz e importar novamente. Como será executado como parte de um empacotador específico, quantos arquivos serão realmente baixados e de onde não é problema dele.
Menos - o início do carregamento de pedaços "usados" ocorre após o carregamento do pacote principal, que armazena o mapeamento, um pouco "mais tarde" do que no caso de componentes carregáveis, que adicionará essas informações diretamente ao HTML.
Sim, com o CCS, ele não funciona na palavra.
2. estilos usados
Mas os estilos usados funcionam apenas com CSS, mas da mesma maneira que os componentes importados por reação.
- varre todos os css (no diretório build)
- lembra onde qual classe é definida
- verifica a saída renderToNodeStream (ou resposta
renderToString
) - localiza class = 'XXX', corresponde ao arquivo e cospe na resposta do servidor.
- (bem, e depois teleporta todos esses estilos para a cabeça, para não quebrar o hidrato). Os componentes de estilo funcionam da mesma maneira.
Não há atraso no TTBT, ele não está vinculado ao empacotador - um conto de fadas. Funciona como um relógio se os estilos forem bem escritos.
Exemplo de trabalho React-import-component + styles-used + parcel .
Não é o bônus mais óbvio: no servidor, as duas bibliotecas farão "tudo o que for necessário" durante a inicialização, até que o servidor expresso possa receber o primeiro cliente e será completamente sincronizado no servidor e durante os testes.
3. componente pré-renderizado de reação
E a biblioteca fecha os três primeiros, que fazem a "reidratação parcial" , e o fazem de uma maneira tão avô que eu me pergunto imediatamente. Ela realmente adiciona "divas".
- no servidor:
- envolve um pedaço de madeira em uma div com um "id famoso"
- no cliente:
- o construtor de componente encontra sua própria div
- copia seu innerHTML antes que o React o pegue.
- usa esse HTML até que o cliente esteja pronto para
hydrate
- tecnicamente, isso permite o uso do SSR híbrido (Rendertron)
const AsyncLoadedComponent = loadable(() => import('./deferredComponent')); const AsyncLoadedComponent = imported(() => import('./deferredComponent')); <PrerenderedComponent live={AsyncLoadedComponent.preload()} // when Promise got resolve - component will go "live" > <AsyncLoadedComponent /> // meanwhile you will see "preexisting" content </PrerenderedComponent>
Esse foco não funciona com componentes carregáveis, pois não retorna de uma promessa de pré-carregamento . Isso é especialmente importante para bibliotecas como reag-snap (e outros "pré-editores") que possuem "conteúdo", mas não passaram por um SSR "real".

Do ponto de vista do código, são 10 linhas, além de um pouco mais para obter UIDs SSR-CSR estáveis, levando em consideração a ordem aleatória de carregamento e execução do código.
Bônus:
- você não precisa esperar pelo "carregamento de todos os scripts" antes de iniciar o cérebro - o cérebro começará quando estiver pronto
- você não precisa carregar cérebros, deixando dados editados por SSR (se não houver uma versão SSR, os cérebros ainda serão carregados). Assim como nos tempos do jQuery.
- Você também pode implementar o cache de fluxo de grandes blocos de renderização (teoricamente compatível com Suspence) - novamente usando o fluxo de transformação.
- e serializando / desserializando o estado para / do HTML, como durante o jQuery
Em princípio, serialização e desserialização foram a principal idéia de criar uma biblioteca para resolver o problema de duplicar o estado (foto do artigo sobre SSR). O cache chegou mais tarde.

Total
No total, existem três abordagens que podem mudar sua visão do SSR e da divisão de código. O primeiro funciona com a divisão de códigos JS e não quebra. O segundo funciona com a divisão de códigos CSS e não quebra. O terceiro funciona no nível HTML, simplificando e agilizando alguns processos e, novamente, não quebra.
Links para bibliotecas:
Artigos (em inglês)