Three.js: Continuar o suporte para bibliotecas JS juntamente com bibliotecas ES6 JSM

Criado em 5 out. 2020  ·  51Comentários  ·  Fonte: mrdoob/three.js

Sua solicitação de recurso está relacionada a um problema?

Acredito que seja uma boa higiene de biblioteca oferecer suporte a importações de módulos e arquivos estáticos clássicos. Isso mantém a biblioteca acessível a um grupo maior de desenvolvedores e permite que os desenvolvedores usem seu estilo preferido.

Pessoalmente, eu realmente tento evitar o uso de módulos em geral, gosto de projetos que são arquivos estáticos com inclusões clássicas de arquivos JS simples. Talvez eu seja apenas um esquisito, mas eu realmente odeio o quanto os frameworks abstraem você desnecessariamente das coisas e o quanto eles reinventam rodas ou, de outra forma, colocam você na caixa-preta. Eu sei que você pode usar módulos sem nenhuma estrutura, no entanto, as inclusões de módulos são menos intuitivas do que as inclusões JS tradicionais, elas geralmente falharam ao tentar usá-las em uma configuração de arquivo estático.

O uso de módulos ES6 não é ideal para todas as implantações, embora certamente seja uma adição bem-vinda. Eu ensino muitos novos programadores threejs porque eu amo a biblioteca e IMO é uma ótima e satisfatória maneira de entrar na programação. É muito mais fácil ensinar as pessoas CSS/JS/HTML básico sem também enfiar toda a pilha de node/npm + framework goela abaixo ao mesmo tempo. Bibliotecas estáticas são mais simples de usar/entender e mantêm a barreira de entrada baixa aqui.

Estilisticamente, também prefiro sobrecarregar THREE com funcionalidades adicionais em vez de adicionar novas funções nomeadas que flutuam livremente. Embora isso seja obviamente preferência.

Descreva a solução que você deseja

Talvez eu possa responder melhor depois de obter um pouco mais de informações sobre por que foi tomada a decisão de fazer a transição apenas para módulos, mas vou tentar.

A documentação aborda que os módulos ES6 podem não funcionar em todas as situações e, para essas situações, sugere o uso de um empacotador como browserify/rollup/webpack/parcel etc....

Minha solução seria ter um script de empacotador ES6 automático passando pelos módulos em /examples/jsm para gerar /examples/js versões sem módulo. Dessa forma, os desenvolvedores não precisam mais se preocupar em fazer alterações em dois lugares e podem continuar usando as versões sem módulo do JS e o estilo de importação global var, se quiserem.

Essa geração automática de arquivos JS não modulares pode ser feita como parte do processo de compilação ou ser um comando no package.json que alguém pode executar manualmente. Embora eu opte pela geração automática.

Criar essa automação ou manter as versões JS não modulares desta biblioteca é algo para o qual posso doar meu tempo. Se o raciocínio por trás do salto para o ES6 apenas não for apenas remover a necessidade de atualizar duas versões paralelas da mesma coisa manualmente, adoraria discutir outras soluções para resolver essas preocupações também.

Descreva as alternativas que você considerou

A outra consideração óbvia seria deixar as coisas como estão e continuar mantendo as versões JS e JSM de todas as bibliotecas. Embora considerando o anúncio, eles estão sendo obsoletos, acho isso um pouco improvável. Mas eu ficaria feliz em assumir a responsabilidade de garantir que as bibliotecas JS permaneçam atualizadas com suas contrapartes JSM manualmente se decidirmos seguir esse caminho.

Contexto adicional

Muito amor a esta biblioteca e a todos que contribuem com código ou relatando/discutindo problemas.

Suggestion

Comentários muito úteis

Obrigado a todos por compartilhar os prós e contras. É sempre bom compartilhá-los para garantir que estamos tomando decisões informadas.

Isso é algo em que tenho gasto alguns ciclos cerebrais este ano, e até perguntei aos fornecedores de navegadores sobre suas prioridades para poder planejar com antecedência.

Concordo que os módulos ES6 são o futuro, mas desenvolver com eles sem importar mapas pode causar grandes dores de cabeça e quebrar completamente o seu fluxo. Quando decidimos descontinuar examples/js eu esperava que os mapas de importação tivessem mais tração, mas parece que atualmente não é uma prioridade para os navegadores.

Por causa disso, decidi suspender a depreciação da pasta examples/js até que os navegadores implementem mapas de importação. Eu odiaria forçar os novatos a aprender sobre polyfills ou bundlers para renderizar seu primeiro cubo.

Cheguei à mesma conclusão que @Bug-Reaper. Hoje estou dando uma olhada na criação de um script que constrói examples/js a partir de examples/jsm arquivos.

Todos 51 comentários

É muito mais fácil ensinar as pessoas CSS/JS/HTML básico sem também enfiar toda a pilha de node/npm + framework goela abaixo ao mesmo tempo. Bibliotecas estáticas mantêm a barreira de entrada baixa aqui.

Apenas para esclarecer o exemplo, os módulos js mantidos neste projeto não exigem node, npm ou qualquer estrutura de compilação para usar. Eles podem ser usados ​​como arquivos servidos estaticamente assim como as antigas importações globais. Eles apenas exigem a sintaxe de importação es6 para usar, mas isso funcionará em todos os navegadores modernos.

Apenas para esclarecer o exemplo, os módulos js mantidos neste projeto não exigem node, npm ou qualquer estrutura de compilação para usar. Eles podem ser usados ​​como arquivos servidos estaticamente assim como as antigas importações globais. Eles apenas exigem a sintaxe de importação es6 para usar, mas isso funcionará em todos os navegadores modernos.

Obrigado pelo esclarecimento! Isso sim é um bom ponto!
Eu acredito:

<script type="module">

  import { OrbitControls } from 'https://unpkg.com/three@<VERSION>/examples/jsm/controls/OrbitControls.js';

  const controls = new OrbitControls();

</script>
````
is perhaps less intuitive and harder to understand for newcomers than: 

espere um segundo... ainda temos:

<script src="path/to/local/build/three.js"></script>

em oposição a:

<script type=module src="path/to/local/build/three.module.js"></script>

O primeiro é um script estático que pode ser usado de acordo com o antigo global-way dentro do html de alguém... certo? Qual foi a coisa que você não conseguiu mais fazer depois de uma transição para o ES6?

Se bem entendi, o plano ainda é incluir um "/build/three.js" além do "/build/three.module.js".

sim. No entanto, é questionável se essa abordagem faz sentido. Quando examples/js é removido, restam apenas alguns casos de uso em que three.js e three.min.js ainda são úteis.

Seria realmente benéfico remover three.js e three.min.js , pois isso nos permitiria alterar o ponto de entrada main npm do pacote npm, veja #19575.

Se pudermos fazer isso facilmente, acredito que faz sentido continuar suportando /examples/js gerando-os automaticamente por meio de um script de empacotador ES6 como parte do processo de compilação.

A ideia é mover examples/jsm para recursos de linguagem JavaScript mais modernos, como classes. Como examples/js ainda deve funcionar com navegadores mais antigos, seria necessário configurar uma nova compilação (exemplos) com recursos de transpilação de código. Além disso, ainda manteríamos a base de código duplicada ( examples/js vs examples/jsm ) que no meu ponto de vista é uma abordagem ruim. Isso torna a manutenção mais complicada.

Acredito que o usuário tenha que cuidar da conversão de ES6 para ES5, se necessário. O mesmo para minificação de código ou outras tarefas relacionadas à compilação.

Acredito que você esteja correto. Se bem entendi, o plano ainda é incluir um " /build/three.js " além do " /build/three.module.js ".

Verdadeiro

O problema com os preenchimentos da pasta /examples é que você precisa usar arquivos de /examples/js quando usou /build/three.js e arquivos de /examples/jsm quando usou /build/three.module.js , também conhecido como manter a consistência no método de carregamento.

Por quê? Porque ao usar importações de módulo, o objeto principal THREE não é mais um objeto js simples THREE = {} mas sim um objeto de módulo do navegador interno que é selado (não extensível), portanto, arquivos de /examples/js que tenta escrever uma nova propriedade no objeto THREE falha.

Então você não pode misturar import * as THREE from '/build/three.module.js e THREE.WhateverExample = function() ...

Uma maneira possível é alterar o nome da lib importada para algo diferente de THREE e recriar um objeto global js THREE simples para exemplos a serem escritos nele ...

Este é tipicamente o problema de

JS tradicional inclui

que polui a nomenclatura do espaço global e, como você não pode modificar nomes no arquivo carregado, pode receber erros como esse ...
Por outro lado, com módulos, o usuário ganha o poder de nomear durante a importação e não é mais o autor da lib que escolhe o nome resultante...

ex:

<script>
// a script you can't modify already use the name THREE
var THREE = document.getElementById('div-nb-3')
</script>

<script type="module">
import * as foo from '/build/three.module.js'

THREE.appendChild( new foo.WebGLRenderer().domElement )
</script>

@ Mugen87 Você está 100% certo. Se abandonarmos os /examples/js , podemos também descartar os three.js e three.min.js , pois eles são essencialmente incompatíveis com qualquer um dos módulos complementares. Seu caso de uso seria de nicho e isso é quase garantido para criar confusão.

@devingfx Você está certo de que os módulos têm vantagens e eliminam potenciais conflitos de nomes globais. Em anos de uso nunca tive nada de conflito com a variável global THREE e acho que esse é um cenário improvável, mas seu ponto está tecnicamente correto.

o que é, a meu ver, uma má abordagem. Isso torna a manutenção mais complicada.

Acredito que o usuário tenha que cuidar da conversão de ES6 para ES5, se necessário. O mesmo para minificação de código ou outras tarefas relacionadas à compilação.

@ Mugen87 É realmente tão terrível manter uma inclusão js tradicional que usa uma var global além de um módulo? Muitas bibliotecas suportam ambos e, pelo que posso dizer, a versão tradicional do JS geralmente é usada tão popularmente quanto as versões do módulo. Ambos têm vantagens/desvantagens e algumas delas se resumem à preferência. Não é bom dar aos desenvolvedores a opção de usar uma biblioteca em um contexto sem módulo?

Estou disposto a cuidar da criação/teste dos recursos de transpilação de código necessários para gerar automaticamente three.min.js, three.js e /examples/js a partir de three.module.js e /examples/jsm . Após o fluxo de trabalho de transpilação ter sido aperfeiçoado, ele pode exigir um mínimo de manutenção, mas != manter duas versões paralelas. Para a maior parte, o código só seria necessário para ser atualizado nos arquivos do módulo e apenas ocasionalmente você precisaria corrigir algum problema de transpilação.

Eu tenho projetos suficientes que dependem da sintaxe global tradicional e inclui que vou fazer o trabalho para automatizar a transpilação dos módulos de qualquer maneira. Acho que pelo menos poderíamos incluir um comando no package.json e chamá-lo de "legado-build" que transpila os módulos em three.min.js, three.js e /examples/js que se comportam de forma semelhante ao original arquivos agora. Esses arquivos nem precisam ser confirmados no repositório ou criados por padrão. Também podemos avisar que são para suporte legado, não há garantia de que funcionem, sugerimos o uso de módulos etc ...

Realisticamente, embora eu ache que faz mais sentido mantê-los no repositório e simplesmente tê-los gerados automaticamente por meio de transpilação na compilação.

um comando no package.json e chame-o de "legado-build" que transpila os módulos

parece razoável. O babel não foi incorporado recentemente? então eu acho que isso pode ser factível como está

edit: para esclarecer, para que o novo comando não seja executado por ninguém, exceto pelos usuários que desejam a referida compilação

É realmente tão terrível manter uma inclusão js tradicional que usa uma var global além de um módulo?

Acho que a complexidade de manter isso está sendo subestimada. Infelizmente eu não acho que seja tão simples com a forma como os exemplos são configurados no projeto.

Vejamos o GLTFLoader como exemplo. No momento, todo o GLTFLoader está contido em um único arquivo, o que facilita a inclusão no topo de um arquivo HTML. Um dos benefícios dos módulos é que alguns dos arquivos maiores podem ser divididos em arquivos separados que o GLTFLoader pode importar como dependências. Como deve ser a aparência do script global construído, uma vez que o GLTFLoader depende de quatro arquivos externos, alguns dos quais são compartilhados? Os usuários dos scripts globais criados agora terão que incluir todos esses arquivos js de exemplo individualmente? Ou alguns arquivos serão agrupados, o que exigiria a manutenção manual de uma lista de arquivos que podem ser agrupados e que não são?

Acho que o único caso realmente definido e esquecido é agrupar todos os arquivos js de exemplo em um único blob monolítico que não acho razoável. Eu acho que com qualquer uma dessas soluções haveria alguma outra sobrecarga de liberação e documentação também.

Talvez haja uma maneira melhor de fazer isso, mas quando tentei fazer uma compilação de rollup que manteve a compatibilidade com versões anteriores ou pelo menos uma estrutura consistente para os arquivos js existentes, esses são os problemas que encontrei.

Se bem entendi, o plano ainda é incluir um "/build/three.js" além do "/build/three.module.js".

sim. No entanto, é questionável se essa abordagem faz sentido.
Quando o example/js é removido, restam apenas alguns casos de uso em que three.js e three.min.js ainda são úteis.

@Mugen87 @mrdoob

Michael,
Na verdade, manter "three.min.js" por pelo menos mais 2 anos é OBRIGATÓRIO.
Não porque todas as minhas amostras são baseadas nele.
Mas porque muitos milhares de arquivos e os principais cães do Google são baseados nele!
Exemplo: https://www.google.com/search?source=hp&q=webgl+benchmark

Por outro lado, do meu ponto de vista, "three.min.js" significa desenvolvimento e teste mais rápidos.
Sem contar que funciona offline e você não precisa de localhost.
Basta colocar todos os arquivos em uma pasta em algum lugar, usar o Firefox e clicar duas vezes no arquivo HTML.
Eu sempre amei isso para o desenvolvimento!

Ricardo também deveria pensar em tudo isso.
Felicidades

A remoção de three.js e three.min.js é algo que pode ser discutido e planejado quando examples/js se for. Foi importante para mim destacar sua perda de significado quando você não pode mais importar arquivos de examples/js .

Acho que a complexidade de manter isso está sendo subestimada. Infelizmente eu não acho que seja tão simples com a forma como os exemplos são configurados no projeto.

Eu realmente gosto dos pontos que você vai trazer à tona. Há uma complexidade absolutamente imprevista no empacotamento e o exemplo de módulos aninhados é bom. Para o seu ponto, acho que podemos tomar decisões sensatas sobre como lidar com o agrupamento de módulos aninhados quando chegar a hora. Não estou dizendo que um script de pacote será uma situação de configuração e esquecimento, apenas que será de menor manutenção.

Se chegar o momento em que é muito difícil de manter, podemos sempre abandoná-lo, mas acho bobagem descartar a tentativa por causa de problemas que ainda não temos. Será mais fácil de implementar agora enquanto ainda temos 1 para 1 paridade entre /examples/jsm e example /js . Provavelmente não reorganizaremos massivamente a hierarquia do módulo /example/jsm e acho que podemos fazer atualizações incrementais no empacotador quando o fizermos. Vou seguir em frente e começar a trabalhar na prova de trabalho para isso (com babel porque já está adicionado?) colocar meu dinheiro onde está minha boca como dizem.

Para o ponto de Mugen, isso ajudaria a manter alguma relevância para three.js e three.min.js enquanto continuamos a mantê-los. Também pode ajudar as centenas de sites que podem estar procurando por uma atualização compatível com sua implementação TRÊS não baseada em módulo. A refatoração de um projeto TRÊS para usar módulos pode ser bastante extensa, mesmo que você saiba o que está fazendo.

Não posso falar pelos outros colaboradores mas não vou mudar de opinião sobre este tema. Eu voto para excluir examples/js com o lançamento de dezembro de 2020, conforme discutido e comprometido aqui #18749.

Eu voto para excluir exemplos/js com o lançamento de dezembro de 2020, conforme discutido e comprometido aqui #18749.

Eu não tenho nenhum problema com isso.
Enquanto "three.min.js" estiver disponível por mais alguns anos...

Obrigado pela entrada Mugen, eu li esse tópico, mas parece mais um anúncio em oposição a uma explicação para a decisão. Minha suposição é que esse desenvolvimento simplificado é a principal razão para avançar nessa direção, existem outras?

Acho que ter um script de transpilação que podemos executar para gerar inclusões de estilo /examples/js deve ser um bom compromisso aqui. Deve diminuir drasticamente a quantidade de manutenção/complicação necessária aqui. Eu até ficaria bem se fosse apenas um comando no package.json que você tivesse que executar por conta própria e os arquivos não fossem gerados por padrão. Existem benefícios para alguns desenvolvedores e outros que precisarão transpilar de qualquer maneira. Prefiro que todos nós não tenhamos criar um fluxo de trabalho de transpilação/pacote por conta própria separadamente quando algo pode ser mantido no repositório principal para melhor nos permitir colaborar. :)

Eu li esse tópico, mas parece mais um anúncio em oposição a uma explicação para a decisão.

Infelizmente nem sempre podemos fixar todos os argumentos válidos em um único tópico, seja porque a realização de uma mudança de design progride lentamente em várias discussões ao longo dos anos, ou simplesmente porque vários tópicos sobre o mesmo assunto são criados repetidamente (como este ). Os colaboradores tentam minimizar o ruído e a segmentação, mas nem sempre é possível.

Minha suposição é que esse desenvolvimento simplificado é a principal razão para avançar nessa direção, existem outras?

O maior que vejo é a capacidade de usar e importar submódulos que minimizam o código redundante e permitem implementações reutilizáveis.

Por exemplo, a maioria dos carregadores precisa criar algum tipo de estrutura/classe de análise de dados, porque cada carregador precisa ser autossuficiente para que os arquivos example/js sejam reutilizáveis. No entanto, se removermos totalmente a restrição não modular, poderemos criar uma única instância de uma classe DataParser e importar essa implementação padrão em todos os carregadores, facilitando imediatamente o desenvolvimento e também removendo código redundante de todos os carregadores.

Sim, bom ponto. Nós já temos que fazer hacks sujos como incorporar a classe Pass (a classe base de todos os passes FX) em EffectComposer apenas para garantir que o código legado não seja quebrado.

pontos muito bons feitos todo.

obter e manter as pessoas em dia/atualizadas parece (e pela minha própria experiência) uma questão difícil. vou tentar pensar um pouco sobre isso.

Na verdade, manter "three.min.js" por pelo menos mais 2 anos é OBRIGATÓRIO.

Sempre será possível gerar uma compilação ES5 usando Babel. A pergunta que precisaremos responder quando se trata disso é se a responsabilidade por isso é nossa ou do desenvolvedor que usa o three.js.

Já decidimos que caberá ao desenvolvedor criar versões ES5 dos arquivos de exemplo, então provavelmente faz sentido fazer o mesmo para os arquivos de compilação. Na minha opinião, também faz sentido fazer isso em toda a biblioteca em uma versão em vez de espaçá-la, mas manter três.min.js por um pouco mais também é bom.

Mas porque muitos milhares de arquivos e os principais cães do Google são baseados nele!
Exemplo: google.com/search?source=hp&q=webgl+benchmark

Este é o principal site que aparece para mim nessa pesquisa, e eles estão usando R53, então não acho que essa mudança os afetará muito: https://www.wirple.com/bmark/

Como você pode ver, as versões antigas do three.js ainda funcionam bem. Depois de fazermos a transição para os módulos, podemos direcionar qualquer pessoa que queira uma compilação do ES5 sem usar o Babel para usar a última versão antes de removermos os arquivos do ES5. Eles podem conferir todo o repositório dessa versão e usar os documentos dessa versão também.

@looeee Você toca em alguns pontos positivos. Como mencionado acima, concordo que faz sentido descontinuar o ES5 three.min.js e three.js ao mesmo tempo aqui. Talvez isso deva ser sua própria discussão separada?

De qualquer forma, gostaria de chegar a um consenso sobre a inclusão de um script babel no repositório principal que pode ser usado para gerar arquivos /js/example estilo ES5 da velha escola. Não se trata de forma alguma se alguém é responsável por fornecer esse suporte. Existem contribuidores, como eu, que vão precisar desse recurso. Existem benefícios para alguns desenvolvedores e outros que precisarão transpilar de qualquer maneira. Prefiro que todos nós não tenhamos criar um fluxo de trabalho de transpilação/pacote por conta própria separadamente quando algo pode ser mantido no repositório principal para melhor nos permitir colaborar.

Eu acho que é um compromisso justo nos permitir um arquivo no repositório principal para que possamos trabalhar juntos no script do transpiler babel ES6 para ES5. Existe realmente um problema aí? Permitindo que os colaboradores trabalhem juntos em um recurso de que precisam no repositório principal?

Não estou pedindo ajuda ou recursos aos colaboradores para fazer isso, estou simplesmente pedindo que você permita que as pessoas que precisam disso possam trabalhar juntas no repositório principal. Se eu fizer um PR para isso e funcionar, você realmente votaria para rejeitá-lo?

Se eu fizer um PR para isso e funcionar

Quero dizer, estou feliz em ver isso começar

você realmente votaria para rejeitá-lo?

todas as apostas serão canceladas se falhar no passe de linting 😂

Existe realmente um problema aí?

Sim, pois o repositório não deve promover padrões de codificação obsoletos.

Sim, pois o repositório não deve promover padrões de codificação obsoletos.

Ainda não está oficialmente obsoleto se não estivermos demitindo three.js + three.min.js (reconhecido que o consenso ITT é que devemos demiti-los também) e ter um script babel que você precisa executar manualmente por conta própria é dificilmente um endosso brilhante. Concordo que devemos definitivamente encorajar as pessoas a usar módulos e ter um aviso no script babel e nos arquivos gerados sobre isso. Eu discordo que permitir que os contribuidores trabalhem juntos em um script babel para pessoas em situações que não podem usar módulos por qualquer motivo está promovendo um padrão de codificação obsoleto. Principalmente porque ainda existem situações em que o uso de módulos é inviável/impraticável. Os documentos reconhecem essa necessidade. Acho que podemos adicionar com segurança um arquivo para as pessoas que precisam trabalhar juntos.

Concordo que faz sentido descontinuar o ES5 three.min.js e three.js ao mesmo tempo aqui.

Eu quis dizer que devemos descontinuar example/js, three.min.js e three.js ao mesmo tempo, ou seja, remover todo o código ES5 em uma versão em vez de espalhar por várias versões.

@Mugen87

Sim, pois o repositório não deve promover padrões de codificação obsoletos.

Você ainda pode executar jogos do DOS no Windows 10.
E isso não significa que a Microsoft esteja promovendo "padrões de codificação obsoletos".

Apenas para esclarecer o exemplo, os módulos js mantidos neste projeto não exigem node, npm ou qualquer estrutura de compilação para usar.

Bem, não vamos esquecer que construir um aplicativo pronto para produção significa agrupar seu código :)

Eu aprecio ferramentas de agrupamento como o Rollup que estão disponíveis, mas acho que devemos considerar algumas perguntas:

  • É justo supor que se os desenvolvedores quiserem usar o THREE em produção, eles também precisam usar uma dessas ferramentas de agrupamento?
  • É justo descartar o suporte para outras bibliotecas que dependem de atualizações para módulos ES5/UMD na pasta de exemplos?

Meus sentimentos pessoais sobre isso:

Esta biblioteca tem uma década. Existe um enorme ecossistema por aí que depende dos módulos da pasta de exemplos escritos em ES5/UMD. Não acho justo abandonar o suporte para um ecossistema inteiro.

Acho que as pessoas esquecem que você ainda pode usar o ES6 sem um padrão de agrupamento de módulos. Eu uso o ES6 todos os dias, mas não uso padrões de agrupamento de módulos em meus aplicativos front-end. Eu trabalhei em lojas corporativas onde as ferramentas de construção se tornam muito personalizadas por necessidade e seriam incapazes de incorporar um padrão de agrupamento de módulos.

O que deveríamos fazer?

Vamos compilar os módulos ES6 em módulos ES5/UMD para uma determinada distribuição após cada lançamento.

Sim, pois o repositório não deve promover padrões de codificação obsoletos.

Para quase tudo na vida, uma solução ainda pode ser de grande qualidade usando padrões, técnicas e ferramentas mais antigas.

Como analogia - No meu tempo livre gosto de esculpir pedra com cinzéis de ponta. As ferramentas e técnicas são diferentes das ferramentas elétricas, mas no final a escultura ainda será de alta qualidade. Eu exerci uma preferência pessoal para usar cinzéis de ponta porque gosto de usá-los e tenho as habilidades necessárias para produzir algo com o qual eu ou outros estejam felizes.

Eu sinto o mesmo sobre os módulos ES5/UMD. Consegui encontrar padrões, técnicas e ferramentas que sustentam bases de código de alta qualidade e quero continuar exercendo essa preferência pessoal.

Vamos compilar os módulos ES6 em módulos ES5/UMD para uma determinada distribuição após cada lançamento.

Concordo com o que looeee disse.

É justo assumir [...]

que? Estamos falando sobre qual abordagem preferimos, a 'suposição' vem depois. A preferência parece ser no sentido de encorajar outros a usar módulos, mas (assumindo que algumas pessoas ainda vão querer o antigo TRÊS) oferecendo um caminho para aqueles que realmente querem.

Vamos compilar os módulos ES6 em módulos ES5/UMD para uma determinada distribuição após cada lançamento.

Isso pode ser feito por qualquer pessoa; esse custo não precisa ser arcado pelos mantenedores do three.js. Gostaria de reiterar o que @gkjohnson disse acima, o custo de manutenção dos diretórios examples/js e examples/jsm é alto. Não podemos fazer isso indefinidamente, e está claro que os Módulos ES6 são a mais moderna das duas abordagens. Considere os seguintes custos:

  • Criando e mantendo a automação
  • Depuração de falhas de versão quando a automação é interrompida
  • Garantir que todas as solicitações de pull atualizem o arquivo de origem, não o gerado
  • Manter a documentação que explica como ambos os fluxos de trabalho são usados
  • Respondendo a relatórios de bugs e perguntas de suporte de usuários que tentam usar fluxos de trabalho CJS e ES6

Esse último item é possivelmente o maior. Enquanto duas cópias de tudo estiverem disponíveis neste repositório, ambas serão vistas como totalmente suportadas. Passamos tempo regularmente ajudando os usuários que confundem os dois fluxos de trabalho ou tentam usar um carregador de módulo ES6 com a biblioteca principal CJS, que falha de maneiras complicadas.

Podemos reformular o problema simplesmente: todos os nossos exemplos — que são importantes, mas partes opcionais da biblioteca three.js — atualmente não usam nenhuma sintaxe de módulo. Não UMD, não CommonJS, não Módulos ES6. Eles simplesmente corrigem um namespace global THREE . Gostaríamos de atualizar isso, usando a sintaxe de importação/exportação do ES6, e houve muitos avisos antecipados de que essa mudança foi planejada.

Existe um enorme ecossistema por aí que depende dos módulos da pasta de exemplos escritos em ES5/UMD. Não acho justo abandonar o suporte para um ecossistema inteiro.

Não acho justo dizer que qualquer coisa no ecossistema three.js seja tão dependente dos namespaces THREE.* globais que não possa ser atualizado para usar a sintaxe de importação/exportação ou para transpilar para ES5 ou para usar um empacotador. Há várias soluções alternativas aqui, e ficaríamos felizes em trabalhar com os usuários para ajudar a encontrar uma opção adequada para eles.

o custo de manutenção dos diretórios exemplos/js e exemplos/jsm é alto.

Eu gostaria de aprofundar isso um pouco mais. Eu escrevi muitas ferramentas personalizadas e criei scripts de automação para aplicativos front-end e ficaria feliz em ajudar da maneira que puder.

Criando e mantendo a automação
Depuração de falhas de versão quando a automação é interrompida

Ajude-me a entender um pouco mais a taxa de manutenção, isso é algo exclusivo do código TRÊS? Na minha experiência, esse tipo de código geralmente é o mais duradouro, precisando de menos manutenção. Estes são scripts que você escreve uma vez e não vê novamente por longos períodos de tempo.

Garantir que todas as solicitações de pull atualizem o arquivo de origem, não o gerado

Talvez um pequeno script ou teste possa ajudar com isso no fluxo de trabalho de lançamento.

Manter a documentação que explica como ambos os fluxos de trabalho são usados

Eu também votaria para descartar a documentação para namespaces globais. Acho bobagem dar suporte à documentação para dois fluxos de trabalho. Isso não é uma coisa ruim. A maioria das bibliotecas que agrupam seu código para diferentes contextos, módulos UMD/ES6 possuem apenas um conjunto de documentos.

Respondendo a relatórios de bugs e perguntas de suporte de usuários que tentam usar fluxos de trabalho CJS e ES6.

Acho que o volume de questões relacionadas a algo assim vem em relação ao tamanho da popularidade do THREE. Você e eu vemos esses tipos de problemas no Stack Overflow o tempo todo. Um usuário que não consegue distinguir entre os dois fluxos de trabalho provavelmente é um novo programador inspirado na biblioteca e está apenas tentando aprender o básico da programação em geral.

Se o objetivo é reduzir o volume de problemas especificamente relacionados à confusão entre os dois fluxos de trabalho , a remoção do código ES5 provavelmente ajudaria nisso - mas duvido que o volume de problemas em geral mude. Um novo programador sempre ficará preso na próxima pergunta que pode ou não estar relacionada à biblioteca.

Como reduzir o volume de problemas em geral?

Se o objetivo real é reduzir o volume geral de problemas, talvez políticas de problemas mais rígidas possam ajudar com isso. Eu vejo vocês fazendo um ótimo trabalho com isso já usando tags como Help (please use the forum) mas talvez precise haver mais desses tipos de coisas.

De maneira mais geral, pode ser melhor apenas descodificar alguns tipos de questões que os TRÊS contribuidores estão dispostos a discutir e investigar se estiverem se sentindo sobrecarregados com o volume total.

Ideias de casal:

  • No momento em que escrevo suggestions e enhancements têm (271) questões em aberto. Esses rótulos parecem gerar muito ruído. Talvez apenas leve PR pronto / cheques passados ​​como a sugestão real. Feche todo o resto e marque como Discussion (please use the forum) .
  • No momento em que escrevo loaders tem (61) questões em aberto. Este rótulo também parece gerar muito ruído. Eu vejo muitos problemas com esse rótulo relacionados a suggestions e enhancements ou relatórios de bugs mal formados. Talvez apenas leve relatórios de bugs bem formados e PR prontos / verificações aprovadas para sugestões. Insta-feche todo o resto e marque de acordo.

Não acho justo dizer que qualquer coisa no ecossistema three.js seja tão dependente de namespaces THREE.* globais que não possa ser atualizado para usar a sintaxe de importação/exportação, ou para transpilar para ES5, ou para usar um empacotador.

Concordo que qualquer coisa pode ser atualizada, mas se pudermos encontrar uma maneira de trabalhar um pouco para continuar apoiando esses usuários de maneira sustentável, concordo com @Bug-Reaper ao dizer:

Prefiro que todos nós não tenhamos criar um fluxo de trabalho de transpilação/pacote por conta própria separadamente quando algo pode ser mantido no repositório principal para melhor nos permitir colaborar.

Estaríamos economizando coletivamente a esses usuários uma enorme quantidade de tempo de atualização de seus aplicativos/bibliotecas, sistemas de compilação e documentação.

Eu gostaria de aprofundar isso um pouco mais. Eu escrevi muitas ferramentas personalizadas e criei scripts de automação para aplicativos front-end e ficaria feliz em ajudar da maneira que puder.

Boa.

Como reduzir o volume de problemas em geral?

Vamos manter isso na pista, por favor. Feliz em discutir mais em outro tópico. É um pouco relacionado ao meu comentário anterior.

Eu concordo com @Bug-Reaper em dizer:

Prefiro que não tenhamos que criar um fluxo de trabalho de transpilação/pacote [...]

Acho que todos concordamos com isso.

Obrigado a todos por compartilhar os prós e contras. É sempre bom compartilhá-los para garantir que estamos tomando decisões informadas.

Isso é algo em que tenho gasto alguns ciclos cerebrais este ano, e até perguntei aos fornecedores de navegadores sobre suas prioridades para poder planejar com antecedência.

Concordo que os módulos ES6 são o futuro, mas desenvolver com eles sem importar mapas pode causar grandes dores de cabeça e quebrar completamente o seu fluxo. Quando decidimos descontinuar examples/js eu esperava que os mapas de importação tivessem mais tração, mas parece que atualmente não é uma prioridade para os navegadores.

Por causa disso, decidi suspender a depreciação da pasta examples/js até que os navegadores implementem mapas de importação. Eu odiaria forçar os novatos a aprender sobre polyfills ou bundlers para renderizar seu primeiro cubo.

Cheguei à mesma conclusão que @Bug-Reaper. Hoje estou dando uma olhada na criação de um script que constrói examples/js a partir de examples/jsm arquivos.

@mrdoob

Decidi suspender a depreciação da pasta exemplos/js até que os navegadores implementem mapas de importação.
Cheguei à mesma conclusão que @Bug-Reaper. Hoje estou dando uma olhada na criação de um script que constrói exemplos/js a partir de arquivos example/jsm.

Uma decisão sábia.
👍

@mrdoob Claro que aceito sua decisão, mas acho que é uma oportunidade perdida. Mais cedo ou mais tarde, os desenvolvedores terão que se afastar dos scripts globais. E eu não acho que Import Maps fará muita diferença aqui. Em vez de "forçar" os usuários a fluxos de trabalho melhores e preparados para o futuro, permitimos que eles continuem usando scripts globais. Em 2020.

E eu não acho que Import Maps fará muita diferença aqui.

Outro dia eu vi alguém fazendo isso:

<script src="js/three.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/loaders/GLTFLoader.js"></script>
<script type="module" src="js/main.js"></script>

E, dentro de main.js eles estavam fazendo isso:

import {OrbitControls} from "https://threejsfundamentals.org/threejs/resources/threejs/r119/examples/jsm/controls/OrbitControls.js";

E a coisa funcionou mesmo... 😐

Não podemos apenas esperar que os usuários façam a coisa certa, eles estão aprendendo e tentando coisas até que algo funcione. O desafio é encontrar um design que os ajude a fazer a coisa certa sem que percebam.

O problema com Módulos ES6 sem mapas de importação é que o usuário não pode simplesmente copiar OrbitControls.js para uma pasta /js em seu próprio projeto e importá-lo como costumava fazer. Não vai funcionar porque OrbitControls.js procura ../../build/three.module.js .

Com mapas de importação, OrbitControls.js importaria apenas de three . O usuário pode copiar o arquivo para onde quiser e depois ajustar o caminho no mapa de importações.

A importação de mapas nos aproxima da facilidade de importação de arquivos como antigamente. Não será tão fácil quanto antes, mas pelo menos o usuário não terá que se preocupar com o pedido ao importar os arquivos. Ganhar algo perder algo.

Concordamos que os mapas de importação tornarão a importação configurável e, portanto, mais flexível. Embora o usuário ainda precise ajustar o mapa de importação (e assim entender o que realmente é).

Eu só acho que todo o "copiar arquivos JS em uma pasta" é um anti-padrão maligno e eu esperava que pudéssemos evitar isso recomendando que novos usuários/iniciantes trabalhem com importações de CDN (que também é uma opção para desenvolvedores que não não quero usar uma compilação por qualquer motivo). Aplicativos adequados (devem) usar ferramentas de compilação de qualquer maneira.

Eu realmente não vejo como um anti-padrão.

É apenas como eu aprendi a fazer sites. Colocaria os arquivos .css /css , depois as imagens em /img e os arquivos .js em /js .

Nos últimos meses, tenho feito alguns experimentos usando a abordagem de Módulos ES6/CDN e não me sinto bem que as bibliotecas venham de um domínio diferente do local onde meu projeto está.

Uma grande coisa que perdemos quando não copiamos arquivos é poder editá-los. Os arquivos em examples/js sempre deveriam ser exemplos sobre os quais você pode construir. Se eu copiasse OrbitControls.js no meu projeto e não fizesse exatamente o que eu precisava, eu poderia modificá-lo porque era apenas um arquivo local.

É assim que eu costumava configurar meus projetos:

<script src="js/libs/three.js"></script>
<script src="js/libs/three/OBJLoader.js"></script>
<script src="js/libs/three/OrbitControls.js"></script>
<script>
    console.log( THREE, THREE.OBJLoader, THREE.OrbitControls );
</script>

Com mapas de importação ficaria assim:

<script type="importmap">
{
  "imports": {
    "three": "js/libs/three.module.js",
    "OBJLoader": "js/libs/three/OBJLoader.js",
    "OrbitControls": "js/libs/three/OrbitControls.js"
  }
}
</script>
<script type="module">
    import * as THREE from 'three';
    import { OBJLoader } from 'OBJLoader';
    import { OrbitControls } from 'OrbitControls';

    console.log( THREE, OBJLoader, OrbitControls );
</script>

Não é tão bonito quanto antes, mas cuida das dependências/ordens de importação para você e não requer um empacotador.

No entanto, ainda funciona para pessoas que fazem desenvolvimento baseado em pacotes. Na verdade, é melhor para eles porque os complementos agora importam de three em vez de ../../build/three.module.js .

E a coisa funcionou mesmo... 😐

FWIW isso só parece realmente funcionar em uma pequena quantidade de casos. Quando não funciona, falha de maneiras extremamente confusas e tivemos vários problemas arquivados relacionados ao que acontece com os processos de compilação também. Indiscutivelmente, se você está preocupado com o novato, dando-lhes várias maneiras de usar os mesmos arquivos, é mais propenso a erros e confuso.

Talvez tangencial, mas pode valer a pena informar às pessoas que eles têm duas cópias de three.js incluídas na página por meio de um aviso no console (mesmo que sejam da mesma versão), o que pode causar problemas, a menos que se tome cuidado para não misturá-los. ~Acredito que o React faz isso por razões semelhantes~ O React pode apenas apontar para isso como uma possível fonte de um erro. Isso poderia ajudar a afastar as pessoas de misturar essas modalidades ao aprender.

Cheguei à mesma conclusão que @Bug-Reaper. Hoje estou dando uma olhada na criação de um script que constrói exemplos/js a partir de arquivos example/jsm.

Se este for o novo plano, eu ficaria feliz em ajudar a reviver #15526 / #15543 (que agora foram excluídos do projeto) que constrói cada arquivo de módulo para um ES6. Dado que alguns exemplos estão espalhados entre tantos arquivos (Shader Nodes, por exemplo) e podemos estar interessados ​​em dividir alguns dos módulos em vários arquivos, provavelmente vale a pena atualizar o script de rollup para obter uma lista explícita de arquivos que queremos converter e saída. Devemos ser capazes de criar automaticamente dependências entre os arquivos que são gerados também.

Uma grande coisa que perdemos quando não copiamos arquivos é poder editá-los

Eu concordo, embora se pudermos ir às aulas por toda parte, eu esperaria algo como:

import orbitalcontrols from  orbitalcontrolsURL

class mycontrols extends orbitalcontrols {
// do the edits I care about
}

e depois mais tarde

let controls = new myorbitalcontrols

Uma grande coisa que perdemos quando não copiamos arquivos é poder editá-los

Eu concordo, embora se pudermos ir às aulas por toda parte, eu esperaria algo como:

importar orbitalcontrols de orbitalcontrolsURL

class mycontrols extend orbitalcontrols {
// faz as edições que me interessam
}

e depois mais tarde

let controles = novos myorbitalcontrols

Você já pode fazer isso... mesmo que a "classe" pai seja uma função js simples!

Código realmente funcionando (em um teste rápido do depurador):

Promise.all([
    import('https://unpkg.com/three/build/three.module.js')
        .then( mod=> [mod.Camera, mod.WebGLRenderer] ),
    import('https://unpkg.com/three/examples/jsm/controls/OrbitControls.js')
        .then( mod=> mod.OrbitControls )
])
.then( ([
    [ Camera, WebGLRenderer ],
    OrbitControls
])=> new ( class extends OrbitControls {} )( new Camera, (new WebGLRenderer).domElement )
)
.then( console.log )

... ou sintaxe mais simples:

(async function() {

let { Camera, WebGLRenderer } = await import('https://unpkg.com/three/build/three.module.js')
,   { OrbitControls } = await import('https://unpkg.com/three/examples/jsm/controls/OrbitControls.js')

class Con extends OrbitControls { }

let my = new Con( new Camera, (new WebGLRenderer).domElement )
console.log( my )

})()

além dessa função aynom e se preocupar com promessas async/await, legal

class mycontrols extend orbitalcontrols {
 // do the edits I care about
 }

Idealmente, este é o padrão que devemos promover, em vez de dizer aos usuários para editar os arquivos originais ao fazer alterações. No entanto, os exemplos não são escritos com extensibilidade em mente, portanto, há fortes limites para o que você pode alcançar. Na minha experiência, você acaba tendo que copiar todo o exemplo original no construtor da classe estendida para fazê-lo funcionar, então não faz sentido usar extend .

Por exemplo, a alteração solicitada mais comum para OrbitControls é limitar o pan . Isso é facilmente realizado, conforme demonstrado no violino de @Mugen87 desse segmento.

Resumindo, você adiciona os vetores minPan e maxPan e fixa controls.target no método controls.update .

Eu tentei fazer isso estendendo OrbitControls . Você pode criar uma classe estendida e funciona bem. No entanto, os problemas se tornam aparentes quando você começa a fazer alterações. Você não pode simplesmente estender o método update :

class OrbitControlsPanLimit extends OrbitControls {
    constructor(object, domElement) {
        super(object, domElement);
    }

    update() {
        super.update();
        console.log('Custom update function');
    }
}

Esta classe estendida funciona ( glitch ), mas este novo método OrbitControlsPanLimit.update é ignorado. O método OrbitControls.update original ainda é usado.

Você pode sobrescrevê-lo redefinindo-o no construtor:

class OrbitControlsPanLimit extends OrbitControls {
    constructor(object, domElement) {
        super(object, domElement);

        this.update = () => {
            console.log('Custom update function');
        }
    }
}

Você não pode usar super.update() aqui, então a única opção é copiar todo o método de atualização original. No entanto, esse método depende de muitas dessas coisas de OrbitControls , que é compartilhada entre todos os métodos.

    //
    // internals
    //

    var scope = this;

    var changeEvent = { type: 'change' };
    var startEvent = { type: 'start' };
    var endEvent = { type: 'end' };

    var STATE = {
        NONE: - 1,
        ROTATE: 0,
        DOLLY: 1,
        PAN: 2,
        TOUCH_ROTATE: 3,
        TOUCH_PAN: 4,
        TOUCH_DOLLY_PAN: 5,
        TOUCH_DOLLY_ROTATE: 6
    };

    var state = STATE.NONE;

    var EPS = 0.000001;

    // current position in spherical coordinates
    var spherical = new THREE.Spherical();
    var sphericalDelta = new THREE.Spherical();

    var scale = 1;
    var panOffset = new THREE.Vector3();
    var zoomChanged = false;

    var rotateStart = new THREE.Vector2();
    var rotateEnd = new THREE.Vector2();
    var rotateDelta = new THREE.Vector2();

    var panStart = new THREE.Vector2();
    var panEnd = new THREE.Vector2();
    var panDelta = new THREE.Vector2();

    var dollyStart = new THREE.Vector2();
    var dollyEnd = new THREE.Vector2();
    var dollyDelta = new THREE.Vector2();

O resultado final é que você terá que copiar quase todo o OrbitControls original para o construtor OrbitControlsPanLimit que anula o propósito de estender a classe. A menos que escrevamos os controles como uma classe com extensibilidade em mente, não acho que estendê-la seja viável.

obrigado @looeee por entrar na conversa. Eu estava pensando que talvez eu tivesse perdido uma solução fácil dentro de meus próprios esforços, mas agora que você mencionou, foi praticamente onde cheguei a mim mesmo.

Idealmente, este é o padrão que devemos promover, em vez de dizer aos usuários para editar os arquivos originais ao fazer alterações.

Cuidado, isso está se aproximando de um argumento de herança versus composição.

Idealmente, uma biblioteca não deveria estar promovendo nenhum padrão. Deve estar promovendo seus recursos e como ele visa resolver seus problemas.

Também não deve assumir um fluxo de trabalho de desenvolvedores, pilha, sistema de compilação, caso de uso. Uma grande biblioteca é tão flexível quanto possível para as muitas necessidades complexas de sua comunidade.

O que é novo hoje é velho amanhã, padrões vêm e vão. A única constante, então, seria o software que oferece grande suporte para os muitos casos de uso ao longo do caminho para manter o máximo possível de compatibilidade com versões anteriores.

Você ainda pode executar jogos do DOS no Windows 10.

argumento herança vs composição

por favor não. a solução para este 'argumento' é usar a melhor ferramenta para o trabalho. há um lugar para herança, composição, funcional, orientado a testes... você escolhe.

Já que estamos falando sobre como outros desenvolvedores (usam, reutilizam, modificam) three.js, é válido promover um padrão que seja prontamente entendido e utilizável sem sair dos recursos do navegador js.

promover não significa que não se possa usar um estilo diferente.

o máximo de compatibilidade com versões anteriores possível

sim e não.

Deve estar promovendo seus recursos e como ele visa resolver seus problemas

talvez para que fiquemos claros, qual é o problema/recurso definido para você?

Também não deve assumir um fluxo de trabalho de desenvolvedores, pilha, sistema de compilação, caso de uso

Eu concordo principalmente. O caso de uso threejs é atualmente o navegador. a ressalva de que alguns de nossos carregadores são úteis para alguns aplicativos de nó pelo que ouvi.

A única constante então seria o software que oferece grande suporte para os muitos casos de uso ao longo do caminho

Mudança é a única constante. os desenvolvedores usam a ferramenta que gostam e às vezes damos uma chance a outras coisas.

como aparte:

Deve estar promovendo seus recursos e como ele visa resolver seus problemas

qual veio primeiro? o recurso, o padrão ou o problema?
certamente o padrão ajudou a resolver o problema e depois se tornou um recurso
...ou foi o recurso que criou o problema e encontramos um padrão para resolvê-lo?

qual veio primeiro? o recurso, o padrão ou o problema?

Qual veio primeiro? A galinha ou o ovo?
Há quem diga que o Galo...

Ótima discussão, obrigado a todos pela contribuição.

Gostaria de saber o que vocês pensam sobre qual bundler ( rollup, babel, parcel, webpack, etc ) é mais adequado para a tarefa de transpilar nossos módulos de exemplo ES6. Acredito que @gigablox mencionou ter experiência aqui e tenho certeza que outros também.

O repositório atual já contém babel, rollup e alguns plugins relacionados. Eu fui em frente e comecei a hackear isso hoje à noite e tenho um script de configuração de rollup extremamente grosseiro para compartilhar:

// jsm-transpiler.js
export default [
  {
    input: './examples/jsm/controls/OrbitControls.js',
    output: {
      banner:"//warning this file was generated automatically",
      file: './examples/js/controls/OrbitControls.js',
      name:'OC',
      footer:'THREE["OrbitControls"]=OC.OrbitControls',
      format: 'umd'
    }
  }
];

Este script de configuração de rollup realmente converte o módulo OrbitControls em um arquivo .js não módulo que atribui o construtor apropriado a THREE.OribitControls. Funcionou, o que é legal :) ! Ele também juntou as 40k linhas de THREE.js no arquivo de saída, não tão legal haha. Também estou poluindo preguiçosamente o espaço da variável global declarando uma var global intermediária chamada OC para ajudar a transportar o construtor OrbitControls para THREE.

O Rollup parece ter alguns recursos muito legais que acho que podem resolver muitos dos nossos problemas. Notavelmente mapeamento e outros controles para garantir que os módulos aninhados corretos sejam incluídos/excluídos. A capacidade de injetar código antes e depois da carga útil transpilada por meio de propriedades de cabeçalho/rodapé/intro/saída.

Estou cautelosamente otimista de que podemos realizar o que precisamos com um script de configuração de rollup manipulado. Mas seria ótimo se alguém que pesquisou / entenda as diferenças entre os muitos bundlers pudesse pesar aqui. Precisaremos de algo bastante robusto para lidar com módulos à medida que eles se tornam mais impressionantes e eu aposto que alguns códigos de transpilação são melhores do que outros.

Aqui está minha opinião sobre isso:
https://github.com/mrdoob/three.js/pull/20529

Este é um script de construção personalizado poc que converte todos os módulos JSM em módulos JS com namespace global em cerca de 30 segundos. Teve muito bom sucesso com este método. Precisa de mais testes, mas tentei alguns dos módulos mais complexos, como o GLTFLoader em um hello world e estava tudo bem.

Poderia usar a ajuda de qualquer assistente experiente do RegExp :) para resolver alguns casos extremos sobre os quais você pode ler mais no PR.

Intenção de envio de mapas de importação do Chrome:
https://groups.google.com/a/chromium.org/g/blink-dev/c/rVX_dJAJ-eI

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

Questões relacionadas

alexprut picture alexprut  ·  3Comentários

zsitro picture zsitro  ·  3Comentários

fuzihaofzh picture fuzihaofzh  ·  3Comentários

boyravikumar picture boyravikumar  ·  3Comentários

konijn picture konijn  ·  3Comentários