Descrição do problema
Apenas importar o módulo de cluster está quebrando o aplicativo.
Etapas para reproduzir e uma demonstração mínima do problema
Eu tenho um mapa onde todos os seus marcadores estão sob um cluster. O mapa é agrupado em uma condicional para que seja renderizado apenas no cliente (não no servidor) porque há problemas conhecidos. No entanto, ele ainda interrompe a renderização do lado do servidor porque tenta acessar window
em algum ponto. Isso provavelmente acontece durante a inicialização do módulo, uma vez que o próprio componente nunca foi instanciado.
Comportamento atual
Os aplicativos que usam cluster não podem ser usados em um aplicativo do lado do servidor.
Comportamento esperado / desejado
Os aplicativos não devem quebrar.
versão angular e angular-google-maps
@angular/*
em 5.0.0@agm/core
em 1.0.0-beta.2Outra informação
Estou procurando um caixa eletrônico de solução alternativa, mas, claro, seria bom se os usuários que possuem um aplicativo Universal não precisassem fazer nada. Devemos pelo menos envolver todo o código com isPlatformBrowser
e apenas listar isso como uma advertência por enquanto, até descobrirmos como renderizar mapas no servidor, se for possível.
@lazarljubenovic sim, embrulhar seria uma boa solução por enquanto.
cc @jigfox
Eu vou olhar para isso
@lazarljubenovic Não tenho nenhuma experiência com aplicativos universais e não tenho certeza de como usar isPlatformBrowser
corretamente. Você poderia me dar algumas dicas?
@jigfox Claro! Você pode injetar o token PLATFORM_ID
em um componente, assim:
constructor(@Inject(PLATFORM_ID) private platformId: any) {
}
Em seguida, você pode usar funções angulares como isPlatformBrowser
ou isPlatformServer
para executar condicionalmente certas partes do código apenas em certas plataformas.
constructor(@Inject(PLATFORM_ID) private platformId: any) {
if (isPlatformBrowser(this.platformId)) {
console.log('This code runs only in browser')
}
}
Não tenho certeza de onde colocar isso, a chamada para window
está no código fornecido por js-marker-clusterer:
markerclusterer.js # L698 e markerclusterer.js # L1270 então cluster-manager.ts # L3 deve ser encapsulado ?
Talvez seja necessário desabilitar todo o plugin de cluster em plataformas não do navegador? Mas talvez um markerclusterer.js de reescrita pudesse ajudar, porque ele poderia ser reescrito sem uma referência de window
Ah, é um código de biblioteca de terceiros. Caramba. Eu me pergunto se apenas dizer algo assim ajudaria:
const oldWindow = window || {}
window = {
setTimeout: oldWindow.setTimeout
}
import 'js-marker-clusterer'
window = oldWindow
Mas eu acho que o servidor irá quebrar apenas por encontrar window
enquanto executa o código, uma vez que a variável não foi instanciada, então isso provavelmente irá quebrar também, mesmo que seja uma boa ideia.
Podemos fazer import
não no início do arquivo, mas dentro de um componente? O que isso faria?
A propósito, está escrito no repositório do Google Maps:
Observação: este repositório não é mantido atualmente e é mantido apenas para fins históricos.
Então, que tal apenas fazermos isso por conta própria? Como é um repositório histórico, ele nunca mudará, o que significa que não há problema em usar nossa própria versão ajustada, que não usa window
alguma?
Ah, e com relação a isso:
Mas eu acho que o servidor vai quebrar apenas por encontrar a janela enquanto executa o código, uma vez que a variável não foi instanciada, então isso provavelmente vai quebrar também, mesmo que seja uma boa ideia.
Parece muito básico, mas só aprendi há alguns dias:
Se você tentar fazer if (window == null)
ou similar e window
não existir como uma variável em nenhum escopo visitado, o código será interrompido com ReferenceError
. No entanto, se você fizer if (typeof window == 'undefined'
), funcionará perfeitamente bem e dará os resultados esperados, mesmo que window
nunca tenha sido declarado (que é o nosso problema no servidor).
Acho que poderia tentar brincar e criar nossa própria versão do repositório Cluster e ver o que pode ser feito usando isso.
Tentei consertar isso usando a seguinte abordagem:
http://ideasintosoftware.com/typescript-conditional-imports/
Mas não tive sorte, pois o compilador AOT vai começar a reclamar que a diretiva não pode mais ser encontrada.
Sim, o compilador AOT analisa estaticamente o código e, portanto, as importações dinâmicas
com certeza soa como algo que não é possível fazer no Angular.
Você já teve tempo de tentar bifurcar o repositório e apenas remover o acesso a
window
? Parece que ele é usado apenas em alguns lugares que podem facilmente
ser evitado.
Em 27 de dezembro de 2017 18:06, "cmddavid" [email protected] escreveu:
Tentei consertar isso usando a seguinte abordagem:
http://ideasintosoftware.com/typescript-conditional-imports/
Mas não tive sorte, pois o compilador AOT vai começar a reclamar que a diretiva pode
não pode mais ser encontrado.
-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/SebastianM/angular-google-maps/issues/1241#issuecomment-354144018 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AHTnkXZ85QbMrFT7timh9MPWDeL5piYiks5tEnkmgaJpZM4QmwTi
.
Ainda não, posso tentar ainda esta semana. Não sou fã de alterar o repositório de origem, embora ele não esteja sendo mantido neste momento, pode ser mais tarde. Mas acho que não temos outra opção. Gosto da sugestão de remover completamente as referências da janela, se isso fosse possível, seria ótimo.
Bem, já se passaram dois anos desde a última atualização, então é por isso que eu acho
bifurcação neste caso particular, pelo menos como uma solução temporária,
não seria tão ruim.
Na quinta-feira, 28 de dezembro de 2017 à 1h04, cmddavid [email protected] escreveu:
Ainda não, posso tentar ainda esta semana. Não sou fã de mudar o
no entanto, o repositório de origem, embora não esteja sendo mantido neste momento,
pode ser mais tarde. Mas acho que não temos outra opção. eu gosto de
sugestão de remover completamente as referências da janela, se isso for
possível, isso seria ótimo.-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/SebastianM/angular-google-maps/issues/1241#issuecomment-354198599 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AHTnkfZdUcmrInBzlNL41wJ6znRzWVCoks5tEtsHgaJpZM4QmwTi
.
Eu fiz um fork do projeto js-marker-clusterer
e fiz a correção. Impede a inicialização MarkerClusterer
quando a janela não está definida (na renderização do lado do servidor). Portanto, o clusterer de marcadores funciona corretamente em ambos os casos agora.
Está publicado em npm. https://www.npmjs.com/package/js-marker-clusterer-universal
js-marker-clusterer
dependência js-marker-clusterer-universal
para ter efeito.
@mbrezovsky bom trabalho, está funcionando bem para mim. Eu recebi um erro relacionado a @agm/js-marker-clusterer
usando importações, algo que ainda não é permitido no lado Node.js / Firebase, então eu tive que converter o código para ES2015 usando Anthony Nahas sua solução proposta aqui: https: //github.com/SebastianM/angular-google-maps/issues/1052#issuecomment -331150772
Alguma atualização para esse problema?
@AoschkA Ainda estou usando a solução alternativa mencionada em meu comentário anterior. Você pode encontrar meu exemplo aqui: https://github.com/cmddavid/js-marker-clusterer.git
@cmddavid Seu readme explica apenas como instalar agm / js-marker-clusterer. Como integrar isso em nossos próprios projetos?
@AoschkA , o repo é apenas a saída compilada, eu não fiz nenhuma instrução, você pode adicioná-lo ao seu package.json assim:
"@agm/js-marker-clusterer": "git+https://github.com/cmddavid/js-marker-clusterer.git"
Ao instalá-lo, você terá o js-marker-clusterer sem janela de erros indefinidos e compilado para ES2015 para que seja compatível com serviços como o Firebase.
Thx que funciona. Seria bom se isso pudesse ser implementado no AGM. Mas agradeço a solução @cmddavid !
@cmddavid Fiz como você disse, mas há um erro ERROR em ./node_modules/@agm/js-marker-clusterer/services/managers/cluster-manager.js
Módulo não encontrado: Erro: Não é possível resolver 'js-marker-clusterer-universal' em '. \ Node_modules \ @ agmjs-marker-clusterer \ services \agers'
@maksimbykov você pode confirmar que js-marker-clusterer-universal
está na sua pasta node_modules? talvez não tenha sido totalmente instalado, apenas no caso de você poder executar npm i --save js-marker-clusterer-universal
. Além disso, algo estranho parece estar acontecendo com os caminhos dos arquivos ali. O primeiro tem uma barra dupla //
e o segundo não contém uma barra invertida \
entre node_modules
e @agm
.
Também vale a pena mencionar que não verifiquei se a embalagem ainda funciona com o angular 6.
@cmddavid muito obrigado! provavelmente ontem eu estava cansado e desatento
Este problema foi marcado automaticamente como obsoleto porque não teve atividades recentes. Ele será fechado se nenhuma outra atividade ocorrer. Obrigado por suas contribuições.
"@ agm / js-marker-clusterer": "git + https://github.com/cmddavid/js-marker-clusterer.git " desculpe, mas não funciona (não instale nada)
Eu fiz um fork do projeto
js-marker-clusterer
e fiz a correção. Impede a inicializaçãoMarkerClusterer
quando a janela não está definida (na renderização do lado do servidor). Portanto, o clusterer de marcadores funciona corretamente em ambos os casos agora.Está publicado em npm. https://www.npmjs.com/package/js-marker-clusterer-universal
js-marker-clusterer
dependênciajs-marker-clusterer-universal
para ter efeito.
Muito obrigado cara, você acabou de me salvar ... parabéns :)
Ainda tenho esse problema, por que ele está marcado como fechado ??
Você literalmente rebateu a explicação sobre o motivo do encerramento. Você viu porque foi fechado.
@lazarljubenovic , vamos mudar para https://github.com/googlemaps/v3-utility-library/tree/master/packages/markerclustererplus de qualquer maneira
Você literalmente rebateu a explicação sobre o motivo do encerramento. Você viu porque foi fechado.
então agora podemos reabri-lo: dançarino:
afinal não é mais simples importar js-marker-clusterer dentro da biblioteca e criar um módulo exportável?
eu fiz isso no meu:
https://github.com/alexnoise79/js-marker-clusterer (consulte src / markerclusterer.js)
e então em:
node_modules/@agm/js-marker-clusterer/fesm2015/agm-js-marker-clusterer.js
substituí declare Markerclusterer por:
import * como MarkerClusterer de 'js-marker-clusterer';
funciona e compila ssr 100%
Minha solução se baseia no comentário de @mbrezovsky acima - então
"install:clusterer-universal": "npm i js-marker-clusterer-universal && rm -rf node_modules/js-marker-clusterer && mv node_modules/js-marker-clusterer-universal node_modules/js-marker-clusterer",
"postbuild": "npm run install:clusterer-universal"
e depois de tudo será instalado e substituído.
E o SSR funciona! :)
Comentários muito úteis
Eu fiz um fork do projeto
js-marker-clusterer
e fiz a correção. Impede a inicializaçãoMarkerClusterer
quando a janela não está definida (na renderização do lado do servidor). Portanto, o clusterer de marcadores funciona corretamente em ambos os casos agora.Está publicado em npm. https://www.npmjs.com/package/js-marker-clusterer-universal
js-marker-clusterer
dependênciajs-marker-clusterer-universal
para ter efeito.