Next.js: Serverless Next: faça dependência dev-only `next`, introduza` next-server` para compilações menores e inicialização mais rápida

Criado em 29 mai. 2018  ·  52Comentários  ·  Fonte: vercel/next.js

O problema: ao otimizar para uma compilação de produção, invocar next start ou usar require('next') em um server.js envolve trazer todo o conjunto de next dependências, incluindo o aqueles relacionados exclusivamente ao desenvolvimento, como webpack .

Isso não é apenas problemático do ponto de vista da imagem de construção e do desempenho do tempo de download ao gerar compilações de produção, mas também provavelmente prejudica o tempo de inicialização. _Observação: isso é atenuado pelo fato de que carregamos com cuidado e preguiçosamente dependências pesadas, como webpack no modo dev._

Para os que se preocupam com o desempenho e são sensíveis aos _tempos de início frios_ (consulte por exemplo: https://twitter.com/rauchg/status/990667331205447680), podemos introduzir um pacote next-server .

Ele teria os mesmos recursos de require('next') menos todas as configurações de tempo de desenvolvimento , mais uma pequena next-server CLI que pode abrir uma porta e realizar um desligamento normal.

O que queremos otimizar para:

  • O conjunto total de dependências de next-server deve ser o menor possível
  • Devemos otimizar fortemente o tempo de inicialização para começar o mais rápido possível

Além disso, devemos fornecer um exemplo em examples/ de como usar next-server em combinação com pkg para exportar seu aplicativo Next.js como um binário ELF autocontido .

p1 feature request

Comentários muito úteis

Os tempos de inicialização a frio que vemos no Now 2.0 para nosso front-end são 1.5s, para um tamanho de imagem de 80mb IIRC

2018-05-29 16 50 37

Deve ser possível torná-lo muito mais próximo de 1s sem quaisquer alterações no Nó ou V8 ou qualquer uma das dependências cuja avaliação fria leve um bom tempo (como react e react-dom )

Todos 52 comentários

Os tempos de inicialização a frio que vemos no Now 2.0 para nosso front-end são 1.5s, para um tamanho de imagem de 80mb IIRC

2018-05-29 16 50 37

Deve ser possível torná-lo muito mais próximo de 1s sem quaisquer alterações no Nó ou V8 ou qualquer uma das dependências cuja avaliação fria leve um bom tempo (como react e react-dom )

wou, isso é incrível !! : o

Wow isso é ótimo.

algumas perguntas para next-server .

  1. será um servidor expresso leve?
  2. sim, será configurável com rotas expressas e next-routes ?

@ Nishchit14 Você não adicionaria express se estivesse tentando reduzir o tamanho da compilação.

Tenho certeza de que next-routes ainda funcionará bem.

Portanto, estamos falando aqui de extrair o servidor existente em seu próprio pacote. Então, vai funcionar da mesma maneira que antes, mas em vez de importar o próximo, você importa o próximo servidor.

Isso é incrível! Eu e outras pessoas que conheço temos executado Next.js em cima do AWS Lambda usando scandium ( usando este guia ) e alguns dos principais problemas têm sido:

1) Tamanho do pacote. Lambda oferece um limite rígido de 50 MB, que pode ser fácil de se aproximar com todas as ferramentas de desenvolvimento incluídas.

2) Arranque a frio. Ter uma inicialização rápida é muito importante, já que o Lambda pode decidir ligar mais servidores a qualquer momento. Os servidores existentes também duram no máximo cerca de 4 horas, portanto a inicialização a frio será importante durante todo o ciclo de vida do aplicativo.

Muito feliz em ver esta iniciativa e feliz em ajudar!

Esta é uma ótima ideia, temos o mesmo com Nuxt.js, nós o chamamos de nuxt-start porque é o comando que você precisa para executar nuxt start -> nuxt-start

Seguindo isso de perto. Como um ponto de dados para o que é possível, www.bustle.com é um aplicativo SSR pré-ação no AWS Lambda com <1s de inicialização a frio. Todo o arquivo zip de produção implantado tem 166kb. Isso é todo o código do aplicativo e da biblioteca. Webpack é usado para empacotamento.

Obrigado por compartilhar @southpolesteve. Isso é superimpressionante. #metas

O caso do usuário é muito semelhante a micro e micro-dev .

Por que não usar a mesma nomenclatura? next e next-dev

Estou mexendo com next.js e sem servidor usando este exemplo e curioso para saber se há alguma maneira de realizar compilações menores agora. Existe uma lista de node_modules que absolutamente não precisamos na produção e que podem ser excluídos com arquivos de configuração em um empacotador como serverless ou repack-zip ?

@Enalmada Estou executando next.js com vários deps e material-ui sendo um deles, eu tenho um aplicativo muito grande em termos de escala, mas o zip integrado que carrego no Lambda é de ~ 45 MB. Que tamanhos você está procurando?

@albinekb Estou inspirado pela resposta do southpolesteve bustle.com acima de 166kb e me pergunto quanto do meu "45 MB" é inútil e fácil de remover se eu soubesse o que colocar em um arquivo dist exclude como um hack até que este excelente tíquete seja concluído .

@albinekb É altamente recomendável usar webpack, parcel ou rollup para agrupar seu JS para lambda. Você economizará no tamanho, mas também no tempo de inicialização, já que acessar o sistema de arquivos via node normal requer é muito lento.

Se você está implantando no ZEIT Now e deseja manter sua imagem pequena para inicializações a frio rápidas, você pode usar uma ferramenta como o Package Phobia para verificar o tamanho de uma dependência de npm antes de instalá-la (ou apenas verificar o tamanho das dependências atuais para cortar o inchaço).

O leia-me também contém muitas ferramentas semelhantes para ajudá-lo a combater o inchaço. Confira aqui: https://github.com/styfle/packagephobia

Isso não deveria ser abordado na versão Next 7? :(

Se você está implantando no zeit agora e deseja manter sua imagem pequena para inicializações a frio rápidas, você pode usar uma ferramenta como Package Phobia

Maldito seja: https://packagephobia.now.sh/result?p=antd

@Enalmada são provavelmente as dependências do antd que são responsáveis, não a própria biblioteca. Estive investigando isso para https://packagephobia.now.sh/result?p=%40material-ui%2Fcore. A maior parte do peso vem de uma ou duas dependências.

Isso não deveria ser abordado na versão Next 7? :(

Para ser claro sobre isso, Next.js 7 estabelece a base para Serverless Next.js, removemos cerca de 5 rotas, deixando apenas 2 realmente necessárias para a produção.

Alguém já usou next.js para trabalhar com rollup? Eu sinto que cheguei muito perto ... executar o rollup no meu arquivo dist de 60m baixou o tamanho para 6m. Infelizmente, o arquivo dist não inicializou de fato e acho que é devido a uma única dependência circular no código next.js que é um aviso durante o rollup. Se alguém pudesse ponderar sobre a possibilidade de remover uma dependência circular no código next.js, poderíamos estar todos muito próximos de compilações muito menores e inicialização mais rápida:
https://github.com/zeit/next.js/issues/5392

Seguindo isso de perto. Como um ponto de dados para o que é possível, www.bustle.com é um aplicativo SSR pré-ação no AWS Lambda com <1s de inicialização a frio. Todo o arquivo zip de produção implantado tem 166kb. Isso é todo o código do aplicativo e da biblioteca. Webpack é usado para empacotamento.

@southpolesteve , você seria capaz de compartilhar algo sobre a configuração do pacote do webpack?

@shauns Infelizmente, não estou mais no Bustle e não tenho mais o código para examinar: /

@southpolesteve não se preocupe! É bom saber que possui pelo menos um webpack.

Podemos ter algumas notícias sobre o próximo servidor? Eu vi alguns commits neste mês atrás.

Verifique o galho de canário.

Quando você planeja lançá-lo?

Não posso compartilhar uma linha do tempo neste momento.

Acabei de pousar # 5927

@timneutkens Devo mover next para devDependencies e adicionar next-server às minhas dependências ou você está fazendo isso automaticamente via babel?
https://github.com/zeit/next.js/blob/canary/packages/next/build/babel/plugins/next-to-next-server.ts

@Skaronator se você estiver implementando usando # 5927, não é nenhum dos dois, de acordo com a especificação, ele .next/serverless/index.js require it ( require('./.next/serverless/index.js') ) e então chamá-lo de método render :

const page = require('./.next/serverless/index.js')

page.render(req, res)

Isso irá renderizar a página e finalizar a resposta

Fantástico!
Estou tentando fazer isso, mas tenho problemas para fazer funcionar em aws lambda. Alguém tem alguma dica?

Acho que não devemos mais precisar de um servidor expresso personalizado, podemos apenas exigir o arquivo sem servidor com base no caminho 🤔

editar
Isso parece funcionar, mas é preciso ir mais fundo para ver como otimizar a etapa de compilação:

const serverless = require("serverless-http");
const http = require('http');
const app = require('./.next/serverless/index.js');
const server = new http.Server((req, res) => app.render(req, res))
app.prepare().then(() => {
    const handler = serverless(server, {
        binary: binaryMimeTypes
    });
    return handler(event, context, callback);
});

Parece que você está confundindo "servidor personalizado" com "sem servidor", suas APIs são completamente separadas, não há método .prepare em sem servidor, pois não há nada para preparar, nós imediatamente renderizamos a página em html e concluímos o resposta quando render é chamado.

const serverless = require("serverless-http");
const http = require('http');
const page = require('./.next/serverless/index.js');
const server = new http.Server((req, res) => page.render(req, res))
const handler = serverless(server, {
  binary: binaryMimeTypes
});
handler(event, context, callback);

Na verdade, e eu não tenho ideia de por que o código acima funcionou (talvez fosse apenas o cache), mas nem o meu ou seu trecho de código funcionou porque serverless-http não parece suportar http.Server e Não posso simplesmente retornar page.render(req, res) porque o objeto lambda event não pode substituir a renderização necessária req param ..

Além disso, eu não quero usar express / koa / qualquer que seja, pois isso quebrará todo o propósito deste próximo recurso novo .. ( serverless-http não depende de dependências, então pode ser usado)

Estou sem ideias: /

Obrigado @timneutkens , agradeço sua ajuda.
Mas também não está funcionando no momento, ainda tenho este erro: typeError: Parameter "url" must be a string, not undefined

Vou parar de poluir este tópico e continuar pesquisando e vou escrever um exemplo se eu encontrar uma solução 😄

Eu estou um pouco confuso. Este thread parece se aplicar a dois cenários: aplicativos sem servidor e servidores pré-compilados que incluem todos os pacotes npm necessários do lado do servidor webpack'd juntos.

O gif no primeiro comentário neste tópico parece considerar o último cenário, que é aquele em que estou interessado. Parece que ele usa next-server que pode ou não ser este pacote npm - não não tenho um repositório anexado a ele e não consegui encontrar um por meio de pesquisa do Google ou GitHub, embora uma das tags de versão seja 8.0.0-canary.7 - uma tag de versão de next - então eu suspeito que seja o pacote certo.

O que escrevi até agora está correto? Em caso afirmativo, mesmo que esteja em canário, há alguma maneira de obter acesso antecipado a ele?

Minha solução atual (que por razões evidentes, não estou usando no produto ) é remover a função de config.externals em meu next.config.js .

Eu adoraria ser capaz de produzir um servidor pré-construído de forma que não precise instalar 200 MB de node_modules e, em seguida, passar 2 minutos compilando em minha pobre VM de produção pequena toda vez que eu forçar uma atualização.


* "prod" é usado livremente, pois este projeto não é de missão crítica ou tão profissional

Seguindo isso de perto. Como um ponto de dados para o que é possível, www.bustle.com é um aplicativo SSR pré-ação no AWS Lambda com <1s de inicialização a frio. Todo o arquivo zip de produção implantado tem 166kb. Isso é todo o código do aplicativo e da biblioteca. Webpack é usado para empacotamento.

O alvo sem servidor Next.js 8 tem um tamanho de zip de 42Kb por padrão 😌

Fantástico! Ansioso por isso!

Eu tenho exatamente a mesma pergunta que @dfoverdx. Eu quero fazer uma compilação de servidor, que também inclui todos os node_modules necessários para a execução. Estou usando um servidor personalizado com express, então não espero que essas dependências sejam incluídas no pacote, mas agora você deve instalar _todas_ dependências em seu servidor também (react, next, axios, ...).

Eu não entendo como isso não é por padrão?
Empacotar todas as dependências e ser capaz de minimizá-las deve trazer melhorias significativas de desempenho do servidor ou estou completamente errado aqui?

Substituir a seção externals da configuração do webpack como segue inclui a maioria das dependências

module.exports = {
  webpack: (config, { dev }) => {
    config.externals = [];
    return config;
  })
};

Mas react e react-dom ainda são necessários no servidor. Não consigo descobrir como incluí-los também ...

Infelizmente, não é possível criar um servidor personalizado com o modo sem servidor atual. E se você usar o modo normal, você precisa incluir next e todas as suas dependências porque _app.js gerado em .next depende, por exemplo, de next / router

Por que o modo sem servidor também não foi incluído em seguida?

Infelizmente, não é possível criar um servidor personalizado com o modo sem servidor atual. E se você usar o modo normal, você precisa incluir next e todas as suas dependências porque _app.js gerado em .next depende, por exemplo, de next / router

Observe que, desde o próximo 8, você pode exigir 'próximo servidor' em vez de 'próximo' em seu server.js, e você só perderá o recarregamento a quente durante o desenvolvimento local ao fazer isso. Em teoria, oferece a capacidade de criar CI em um servidor intermediário e não copiar dependências relacionadas ao Webpack para instâncias de produção. Mas ainda não experimentamos em nosso projeto.

@ElvenMonky esperando por algo assim há um ano, mas não conseguiu encontrar nada sobre isso nos documentos ou exemplos.

@timneutkens, você poderia verificar isso?

Nesse caso, posso experimentar essa configuração e enviar um PR para os documentos / exemplos.

Observe que, desde os próximos 8, você pode exigir 'próximo servidor' em vez de 'próximo' em seu server.js, e você só perde o recarregamento a quente durante o desenvolvimento local ao fazer isso

Infelizmente, isso não funciona.

Primeiro, a execução da compilação sem servidor com o destino do servidor é ativamente bloqueada com a seguinte mensagem: "Não é possível iniciar o servidor quando o destino não é o servidor. Https://err.sh/zeit/next.js/next-start-serverless "

Então, se você decidir fazer uma construção normal, então os arquivos de construção estão referenciando coisas do pacote next diretamente (como next/router no arquivo _app.js compilado para o lado do servidor). Significa que next e webpack coisas precisam estar em produção de qualquer maneira.

@ElvenMonky

Observe que, desde o próximo 8, você pode exigir 'próximo servidor' em vez de 'próximo' em seu server.js, e você só perderá o recarregamento a quente durante o desenvolvimento local ao fazer isso.

O próximo passo é fazer isso internamente como um plugin do Babel, como você pode ver aqui:
https://github.com/zeit/next.js/blob/709850154754278d2fc86b987eebe1b3f0565255/packages/next/build/babel/plugins/commonjs.ts#L5 -L32

@sheerun, como mencionei também em # 7011, você pode eliminar a dependência next/router não resolvida ao transpilar o módulo next usando o plugin next-transpile-modules .

Criei e ajustei o exemplo do servidor expresso personalizado para ilustrar a solução: https://github.com/ElvenMonky/next.js/tree/custom-next-server-express/examples/custom-server-express

PS: Ainda estou muito animado com o # 5927, não importa, pois meu aplicativo requer tudo listado em TODO, sem mencionar as rotas dinâmicas e veiculação de conteúdo estático.
A boa notícia é que a solução acima parece funcionar bem com https://www.npmjs.com/package/next-serverless configuração de servidor personalizado, tornando possível implantar em seguida, por exemplo, AWS Lambda sem as limitações mencionadas.

Observe que, desde o próximo 8, você pode exigir 'próximo servidor' em vez de 'próximo' em seu server.js, e você só perderá o recarregamento a quente durante o desenvolvimento local ao fazer isso.

Tenho usado este conselho, mas infelizmente não posso usar a configuração de tempo de execução, pois isso requer next/config que requer next .

Não sei por que, mas require('next/config') costumava trabalhar em produção sem next instalado em node_modules com a próxima versão 8.0.3, mas não funciona com a próxima versão 8.1.0

É possível mover next / config para um pacote diferente, como next-runtime-config ?
Ou next-runtime-vars (evitando o termo config para evitar confusão com next.config.js).

Avise-me se for aceitável, vou criar um PR.

Ei pessoal! Esse problema foi implementado desde Next.js 8 e ainda existe no Next.js 9. Vou fechar isso como concluído. 😌

Desculpe, eu me confundi com esse problema: https://github.com/zeit/next.js/issues/7011
Não verifiquei com o destino: "sem servidor"


Ver comentário excluído

Alguns "next/*" podem ser substituídos por "next-server/*" , como:

  • next / config -> next-server / config
  • próximo / amp -> próximo servidor / amp
  • próximo / dinâmico -> próximo servidor / dinâmico
  • next / constantes -> next-server / constantes
  • next / head -> next-server / head

Mas existem alguns para os quais não há suporte para tal otimização mencionada pelo OP nesta edição.

  • próximo / roteador -> próximo-servidor / dist / lib / roteador / roteador (talvez)? (Deve estar vazio ou deve gerar um erro se usado no servidor)
  • próximo / link?

Não são necessários porque estão embutidos mesmo no servidor (AKAIK)

  • próximo / app
  • próximo / documento

Ei pessoal! Esse problema foi implementado desde Next.js 8 e ainda existe no Next.js 9. Vou fechar isso como concluído.

Olá @Timer - Você está se referindo ao destino sem serviço ou à substituição de 'próximo' por 'próximo servidor'?

Se substituirmos next pelo próximo servidor, isso não mudará o tamanho da pasta node_modules, a menos que as dependências de packages.json também sejam atualizadas.

Existe um exemplo de qualquer abordagem disponível? com sem servidor, meu caso de uso é implantar no AWS Lambda.

A abordagem descrita na edição inicial evoluiu para a meta serverless , recomendamos que você a use.

@timneutkens serverless target não resolve e não pode resolver problemas com o servidor personalizado, que usa rotas dinâmicas. # 5927 Não é uma solução para muitos aplicativos de negócios do mundo real como no meu caso, onde temos que usar páginas geradas dinamicamente, prefixo de ativos, _app personalizado, _document e _err: basicamente tudo o que consta na lista TODO.
next-server nos dá uma solução parcial para implantar em produção sem dependências estranhas apenas de desenvolvimento, como webpack e babel. Isso pode ser feito, entretanto, com alguns hacks e woodoo dancing, que estamos discutindo aqui.

Fiquei com a impressão de que você entende essa diferença e esperava ver algum dia uma solução mais robusta para o problema inicial, conforme descrito por @rauchg

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

YarivGilad picture YarivGilad  ·  3Comentários

ghost picture ghost  ·  3Comentários

rauchg picture rauchg  ·  3Comentários

havefive picture havefive  ·  3Comentários

swrdfish picture swrdfish  ·  3Comentários