Browserify
Mudar para essa arquitetura tem vantagens e desvantagens. Por favor, adicione seus pensamentos.
Nota: isso não requer que os consumidores three.js usem o browserify.
Uma vantagem é que isso reforçaria uma arquitetura modular para o desenvolvimento contínuo de three.js.
O estilo comum em node / browserify faz com que cada arquivo declare suas dependências no topo e considera as variáveis globais um antipadrão.
Aqui está um exemplo de snippet:
// src/geometry/BoxGeometry.js
var Geometry = require('./Geometry.js');
var Vector3 = require('../core/Vector3.js');
module.exports = BoxGeometry;
function BoxGeometry() {
// ...
}
BoxGeometry.prototype = Geometry.prototype;
Outra vantagem é que os consumidores de three.js
usando o browserify poderiam escolher as peças que desejam. Eles poderiam apenas importar Scene
, BoxGeometry
, PerspectiveCamera
e WebGLRenderer
, obter as dependências para todos eles automaticamente ( Object3D
etc), e tem um pequeno pacote de javascript que suporta apenas o conjunto de recursos que eles desejam.
Isso pode ser feito de uma forma que não imponha alterações significativas. No nível superior, exportaríamos todas as classes que consideramos parte do pacote padrão
// src/three.js
var THREE = { rev: 101 }
module.exports = THREE
THREE.Geometry = require('./geometry/Geometry.js')
THREE.BoxGeometry = require('./geometry/BoxGeometry.js')
// ...
nota: não estou exatamente exigindo as dependências na parte superior neste exemplo, porque esse arquivo seria quase exclusivamente instruções require.
Finalmente, envolveríamos isso em uma Definição de Módulo Universal que detecta se um sistema de módulo (node / browserify, AMD) está em uso e, se estiver, o exporta ou, de outra forma, o anexa ao objeto global ( window
).
Vamos revisar:
three.js
consumidores que usam o browserify escolham e escolham a funcionalidadeIsso exigiria a substituição do sistema de construção, mas o novo seria bastante simples.
Algumas outras vantagens:
@ shi-314 Acho que estou um pouco confuso. Acho que You can structure your code
e You can build for production
são coisas que você pode fazer sem a mudança arquitetônica? Você está falando sobre o código-fonte do three.js ou coisas construídas usando o three.js?
Uma prática que o three.js usa e que o torna difícil de usar em ambientes commonjs é o uso de instanceof
: https://github.com/mrdoob/three.js/blob/master/src/core/Geometry .js # L82
Isso ocorre porque, em um aplicativo, você geralmente acaba com versões diferentes da mesma biblioteca em sua árvore de origem, portanto, verificar instanceof não funciona entre versões diferentes da mesma biblioteca. Seria uma boa preparação para uma mudança para um sistema de módulo commonjs para substituir essas verificações de instância por verificação de recursos por trás de uma interface de estilo Geometry.isGeometry(geom)
.
@kumavis Estou falando sobre coisas construídas em three.js. Digamos que você queira criar seu próprio material com seus shaders etc. No momento, você precisa estender o objeto THREE global para permanecer consistente com o resto do código three.js:
THREE.MeshMyCoolMaterial = function (...) { ... }
Mas se tivéssemos o Browserify, você poderia fazer:
var MeshLambertMaterial = require('./../MeshLambertMaterial');
var MeshMyCoolMaterial = function (...) {...}
Para que seu namespace permaneça consistente e você não precise usar THREE.MeshLambertMaterial
e MeshMyCoolMaterial
em seu código.
E com You can build for production
eu basicamente quis dizer a mesma coisa que você mencionou: allows three.js consumers using browserify to pick and choose functionality
.
@ shi-314 obrigado, isso é mais claro. Isso tem impacto na minha proposta de solução geral para desserialização de classes definidas pelo consumidor:
// given that `data` is a hash of a serialized object
var ObjectClass = THREE[ data.type ]
new ObjectClass.fromJSON( data )
Isto é da minha proposta de refatoração de serialização / desserialização
https://github.com/mrdoob/three.js/pull/4621
O desempenho não deve ser afetado por uma mudança como essa.
Esta é uma grande mudança, mas também sou a favor dela.
Algumas outras vantagens importantes:
standalone
do browserify para gerar uma compilação UMD para você. Não há necessidade de mexer manualmente com invólucros UMD.threejs-vecmath
sem nos preocupar com a quebra de código de todos. E por outro lado, se fizermos um patch ou lançamento menor em um módulo específico, as pessoas que consomem esses módulos serão capazes de obter as alterações automaticamente.npm install threejs-shader-bloom
)require()
os módulos que nosso aplicativo está realmente usando.Para @mrdoob e os demais autores; Se você não tem muita experiência com NPM / Browserify, sugiro fazer alguns pequenos projetos com ele e ter uma ideia de sua "filosofia". É muito diferente da arquitetura ThreeJS; em vez de grandes estruturas, ele incentiva muitas coisas pequenas .
Outra vantagem dessa abordagem é que pode haver um ecossistema de código aberto, módulos Three.JS de terceiros, especialmente sombreadores, geometrias, carregadores de modelo etc. Publicado por meio do NPM ou Github / Component que as pessoas podem facilmente consultar e usar. No momento, as coisas são compartilhadas hospedando-se uma demonstração na qual as pessoas então 'visualizam o código-fonte'. Three.JS merece melhor!
Acho que um dos problemas que tenho com o Three.JS é a rapidez com que o código se torna incompatível com a versão atual do Three.JS. Outra vantagem de mudar para algo assim é ser capaz de especificar versões específicas de _bits_ de Three.JS seria muito poderoso e prático.
+1
+1 para uma arquitetura CommonJS / browserify, tornaria o núcleo mais leve e as extensões caberiam mesmo se fossem de terceiros
Fragmentar three.js em pequenos módulos também acarreta muitos custos. O sistema atual permite addons de terceiros bastante simples (testemunha, por exemplo, os módulos THREEx de jetienne). Há muito a ser dito sobre a simplicidade da configuração atual, contanto que os sistemas de módulo JS sejam apenas invólucros em torno de sistemas de construção.
Outra maneira de minimizar o tamanho da compilação é o que o ClojureScript faz. Eles seguem algumas convenções para permitir que o compilador Closure do Google faça a análise de todo o programa e elimine o código morto.
+1 para o não apreciado, e muitas vezes esquecido, elegância da simplicidade
+1
Fragmentar three.js em pequenos módulos também acarreta muitos custos. O sistema atual permite addons de terceiros bastante simples (testemunha, por exemplo, os módulos THREEx de jetienne).
A ideia aqui é que um build UMD ainda seria fornecido para ambientes não-Node. Plugins como o THREEx funcionariam da mesma maneira para aqueles que dependem do ThreeJS com tags <script>
simples.
O complicado será: como podemos require()
um plugin específico se estivermos em um ambiente CommonJS? Talvez o browserify-shim possa ajudar.
Há muito a ser dito sobre a simplicidade da configuração atual, contanto que os sistemas de módulo JS sejam apenas invólucros em torno de sistemas de construção.
O sistema de plug-in / extensão atual do ThreeJS é horrível de se trabalhar e está longe de ser "simples" ou fácil. A maioria dos projetos ThreeJS tende a usar alguma forma de plugin ou extensão, como EffectComposer, ou FirstPersonControls, ou um carregador de modelo, ou um dos outros muitos arquivos JS flutuando na pasta examples
. No momento, a única maneira de depender desses plug-ins:
vendor
Agora, imagine, com o browserify você poderia fazer algo assim:
var FirstPersonControls = require('threejs-controls').FirstPersonControls;
//more granular, only requiring necessary files
var FirstPersonControls = require('threejs-controls/lib/FirstPersonControls');
Esses plug-ins irão require('threejs')
e qualquer outra coisa que eles possam precisar (como fragmentos GLSL ou triangulação de texto ). O gerenciamento de dependência / versão fica totalmente oculto para o usuário e não há necessidade de tarefas de concat grunt / gulp mantidas manualmente.
O complicado será: como exigimos () um plug-in específico se estivermos em um ambiente CommonJS?
Estou usando CommonJS para projetos THREE.js há um tempo. É um processo meio manual, converter pedaços de código de outras pessoas em módulos e não acho que haverá uma maneira fácil de evitar isso para código legado que não é convertido pelos autores ou contribuidores.
A parte importante é que há um módulo exportando todo o objeto TRÊS 'padrão', que pode então ser exigido por qualquer coisa que deseje estendê-lo.
var THREE = require('three');
THREE.EffectComposer = // ... etc, remembering to include copyright notices :)
Isso tem funcionado muito bem para mim, especialmente conforme o projeto cresce e eu começo a adicionar meus próprios sombreadores e geometrias em seus próprios módulos, etc.
Contanto que haja um pacote npm 'threejs-full' ou 'threejs-classic', então esta se torna uma maneira bastante viável de trabalhar com coisas antigas do Three.js em um ambiente CommonJS, mas eu suspeito que este seja um nicho bastante!
+1
Acredito que, uma vez que os módulos threejs fragmentados estão disponíveis no npm, o plugin
os desenvolvedores adorarão migrar para o ambiente CommonJS.
Em 5 de junho de 2014, 21:19, "Charlotte Gore" [email protected] escreveu:
A coisa complicada será: como exigimos () um plugin específico se nós
estão em um ambiente CommonJS?Estou usando CommonJS para projetos THREE.js há um tempo. É um pouco
de um processo manual, convertendo pedaços do código de outras pessoas em módulos
e não acho que haverá uma maneira fácil de evitar isso para o código legado
que não é convertido pelos autores ou colaboradores.O importante é que há um módulo exportando todo o 'padrão'
TRÊS objeto, que pode então ser exigido por qualquer coisa que deseja estender
isto.var TRÊS = requer ('três');
THREE.EffectComposer = // ... etc, lembrando-se de incluir avisos de direitos autorais :)Isso funcionou muito bem para mim, especialmente à medida que o projeto cresce e eu
comece a adicionar meus próprios sombreadores e geometrias em seus próprios módulos, etc.Contanto que haja um pacote npm 'threejs-full' ou 'threejs-classic', então
isso se torna uma maneira bastante viável de trabalhar com coisas antigas do Three.js em um
Ambiente CommonJS, mas eu suspeito que este seja um nicho bonito!-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -45236911.
Ele também pode tornar os shaders modulares, por exemplo, usando glslify . Até coisas como criar um middleware Express que gere sombreadores sob demanda se tornam mais fáceis.
Alguns meses atrás, mudei o frame.js para o require.js e finalmente entendi como essa coisa da AMD funciona.
Ainda preciso aprender, entretanto, como "compilar" isso. Qual é a ferramenta / fluxo de trabalho para gerar three.min.js
de uma lista de módulos?
Eu prefiro gulp.js como um sistema de construção com o plug - in http://travismaynard.com/writing/no-need-to-grunt-take-a-gulp-of-fresh-air : wink:
algumas idéias: (com base em minha experiência limitada com node, npm, browserify, é claro)
Dito isso, seguindo a discussão neste tópico, não tenho certeza se todos tinham o mesmo entendimento de browserify (browserify, commonjs, requirejs, amd, umd estão de alguma forma relacionados, embora possam não ser necessariamente a mesma coisa).
agora, se você pode seguir minha cadeia de pensamentos um pouco.
É aí que o Browserify entra em cena. Bem, tecnicamente, pode-se usar requireJS no navegador. Mas você deseja agrupar os arquivos js sem fazer muitas chamadas de rede (ao contrário dos require () s do sistema de arquivos, que são rápidos). É aí que o Browserify faz algumas coisas legais como análise estática para ver quais módulos precisam ser importados e cria compilações que são mais otimizadas para o seu aplicativo. (Existem limitações, é claro, ele provavelmente não pode analisar require ('bla' + variável)) ele pode até mesmo trocar partes que requerem uma camada de emulação para coisas dependentes de node.js. sim, ele gera uma compilação js que agora posso incluir no meu navegador.
Aqui estão algumas das coisas que o browserify pode fazer https://github.com/substack/node-browserify#usage
Parece que está tudo ótimo até agora ... mas há alguns pontos que considero que vale a pena considerar que mudamos para uma "arquitetura de navegador"
Portanto, se vemos essa diversidade e carregamento de módulo conveniente (principalmente no ecossistema npm) junto com compilações personalizadas, então pode valer a pena ter uma mudança de paradigma, refatorar o código e mudar nosso sistema de compilação atual.
@mrdoob algumas ferramentas do browserify estão listadas aqui: https://github.com/substack/node-browserify/wiki/browserify-tools.
em relação a three.min.js
, você não usaria o código reduzido em seu projeto. tudo o que você faz é var three = require('three')
em seu project.js
e então executa browserify project.js > bundle.js && uglifyjs bundle.js > bundle.min.js
. observação: você ainda pode enviar o código reduzido por <script src="min.js">
.
estou atualmente envolvendo three.js com
if ('undefined' === typeof(window))
var window = global && global.window ? global.window : this
var self = window
e
module.exports = THREE
então eu envolvo extensões com
module.exports = function(THREE) { /* extension-code here */ }
então eu posso exigir assim:
var three = require('./wrapped-three.js')
require('./three-extension')(three)
então isso não é o ideal, mas eu pessoalmente posso viver com isso e acho que não é tão ruim - embora a proposta da @kumavis seja uma _grande_ vantagem.
mas talvez fizesse sentido dividir três e colocar todas as coisas em módulos separados apenas para ver como funcionaria.
também verifique http://modules.gl/ que é fortemente baseado no browserify (embora você possa usar cada módulo sozinho sem o browserify).
@mrdoob @ shi-314 gulp-browserify foi colocado na lista negra em favor de apenas usar o browserify diretamente (ou seja, via vinyl-source-stream).
Ferramentas como grunt / gulp / etc estão constantemente mudando, e você encontrará muitas opiniões divergentes. No final, não importa qual você escolhe ou se você apenas faz isso com um script personalizado. As questões mais importantes são: como os usuários consumirão o ThreeJS e quanta compatibilidade com versões anteriores você deseja manter?
Depois de pensar um pouco mais, acho que será _realmente_ difícil modularizar tudo sem refatorar completamente o framework e sua arquitetura. Aqui estão alguns problemas:
../../../math/Vector2
feios etc.three-scene
seria desacoplado de three-lights
etc. Então você pode criar uma versão de cada pacote separadamente. Esse tipo de fragmentação parece irreal para uma estrutura tão grande como o ThreeJS e seria um saco de mantê-la.require('three/src/math/Vector2')
Minha sugestão? Consideramos duas coisas no futuro:
Adoraria ver tudo modularizado, mas não tenho certeza de uma abordagem realista para o ThreeJS. Talvez alguém devesse fazer alguns experimentos em uma bifurcação para ver como as coisas são viáveis.
Obrigado pelas explicações galera!
O que temo é complicar as coisas para as pessoas que estão começando. Forçá-los a aprender essas coisas de browserify / modules pode não ser uma boa ideia ...
Teria que concordar com @mrdoob aqui. Eu, e muitos colegas, não somos programadores da web (em vez disso, VFX / TDs de animação). Escolher o WebGL e o Three certamente já deu trabalho suficiente, pois está no topo de nossa carga de trabalho atual (e em alguns casos alguns de nós tiveram que aprender js na hora). Muito do que li neste tópico, às vezes, me faz estremecer pensando em quanto mais trabalho seria adicionado ao meu prato se Três mudasse para esta estrutura. Eu posso estar errado, mas é certamente o que parece para mim.
Com um UMD pré-compilado ( browserify --umd
) compilado no repo, não há nenhuma mudança no fluxo de trabalho para os desenvolvedores existentes.
@mrdoob A ideia de um sistema de gerenciamento de dependências é a simplicidade. Ler dezenas de postagens sobre opções e sistemas de construção pode ser opressor, mas no final das contas o sistema atual não é sustentável. Sempre que um arquivo depende de outro, isso é uma caça -e- pesquisa que qualquer novo desenvolvedor deve realizar para encontrar uma referência. Com o browserify, a dependência é explícita e há um caminho para o arquivo.
@repsac Um sistema de dependência deve tornar o Three mais acessível aos usuários de outras linguagens, pois evita o escopo global, pesadelos na ordem de carregamento e segue um paradigma semelhante a outras linguagens populares. var foo = require('./foo');
é (loosly) semelhante ao do C # using foo;
ou de Java import foo;
Adoraria ver tudo modularizado, mas não tenho certeza de uma abordagem realista para o ThreeJS. Talvez alguém devesse fazer alguns experimentos em uma bifurcação para ver como as coisas são viáveis
Acho que esse é o caminho a percorrer, realmente. Faça o trabalho, mostre como funciona.
E consumir a API seria bastante
ugly: require('three/src/math/Vector2')
Como um experimento, acabei de converter o "início" dos documentos Três para esta nova abordagem modular. Posso imaginar que haja muitas referências, a menos que as pessoas sejam bastante rígidas quanto a dividir seu código em módulos minúsculos.
A principal vantagem de fazer isso seria que o tamanho de compilação resultante seria uma pequena fração do tamanho do Three.js completo, porque você só incluiria as coisas especificamente referenciadas aqui e depois as coisas das quais essas coisas dependem.
Acho que fazer referência a todas as dependências de que você precisa (e instalá-las individualmente) pode ser um pouco terrível na prática.
Se você está segmentando explicitamente dispositivos móveis, essa abordagem altamente granular seria perfeita, mas na realidade, suspeito que precisaremos de pacotes que exportem as TRÊS api inteiras que funcionarão normalmente, e pacotes menores que encapsulem toda a geometria bônus, todos os renderizadores, toda a matemática, todos os materiais, etc., depois até o nível de módulo individual para que os desenvolvedores possam decidir por si próprios.
E sim, programar para a web é uma dor.
De qualquer forma, continue com o experimento ...
Instale nossas dependências ..
npm install three-scene three-perspective-camera three-webgl-renderer three-cube-geometry three-mesh-basic-material three-mesh three-raf
Escreva nosso código ...
// import our dependencies..
var Scene = require('three-scene'),
Camera = require('three-perspective-camera'),
Renderer = require('three-webgl-renderer'),
CubeGeometry = require('three-cube-geometry'),
MeshBasicMaterial = require('three-mesh-basic-material'),
Mesh = require('three-mesh'),
requestAnimationFrame = require('three-raf');
// set up our scene...
var scene = new Scene();
var camera = new Camera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
var renderer = new Renderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// create the cube...
var geometry = new CubeGeometry(1, 1, 1);
var material = new MeshBasicMaterial({color: 0x00ff00});
var cube = new Mesh(geometry, material);
scene.add(cube);
// position the camera...
camera.position.z = 5;
// animate the cube..
var render = function () {
requestAnimationFrame(render);
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
// begin!
render();
então construa nosso arquivo
browserify entry.js -o scripts/hello-world.js
então inclua em nossa página
<script src="/scripts/hello-world.js" type="text/javascript"></script>
Acho que fazer referência a todas as dependências de que você precisa (e instalá-las individualmente) pode ser um pouco terrível na prática.
O usuário final não precisa necessariamente usar o browserify em seu projeto para que o Three use o browserify para gerenciar sua base de código. Três podem ser expostos como o THREE
global como está agora ... inclua o arquivo de construção e execute com ele.
@repsac @mrdoob as mudanças seriam compatíveis com versões anteriores, de forma que os usuários atuais não precisem mudar nada se não quiserem. Essas sugestões são para melhorar a manutenção a longo prazo e longevidade da base de código extensa e monolítica do ThreeJS. Coisas como dependência e gerenciamento de versão podem soar como uma dor de cabeça para os não iniciados, mas são fantásticas para ferramentas de desenvolvimento, frameworks, plug-ins e sites de grande escala além do ThreeJS.
ou seja, o código do usuário final ainda pode ter a mesma aparência, e examples
não precisa ser alterado:
<script src="three.min.js"></script>
<script>
var renderer = new THREE.WebGLRenderer();
</script>
Para desenvolvedores mais ambiciosos que procuram uma construção modular, _ou_ para aqueles que procuram desenvolver soluções de longo prazo com base no ThreeJS (ou seja, e tirar proveito do gerenciamento de versão / dependência), pode ser mais assim:
npm install three-vecmath --save
Então, no código:
var Vector2 = require('three-vecmath').Vector2;
//.. do something with Vector2
E, além disso, isso permite que as pessoas usem coisas como matemática vetorial de ThreeJS, conversões de cores, triangulação, etc. fora do escopo de ThreeJS.
Mesmo que eu ache que a bagunça de require () é uma má ideia e uma péssima troca, seria uma ideia ainda pior expor os usuários a dois tipos diferentes de código three.js, dizendo aos usuários que um é o sabor do sistema de módulo extravagante e o outro é o sabor de sistema de módulo mais simples (mas de segunda classe).
@erno Acho que você perdeu o ponto, three.js
seria organizado por uma estrutura de módulo internamente, mas que é usada para produzir um arquivo de compilação não diferente da configuração atual.
O principal ganho é melhorar a experiência de desenvolvimento e manutenção de three.js
.
@kumavis - no @erno realmente não perdeu isso, mas eu entendi (*) que ele afirma que se three.js
às vezes é usado via require e às vezes não, pode ser confuso. Por exemplo, alguém olha as três fontes e, em seguida, alguns exemplos de terceiros e encontra diferenças em como tudo é e funciona.
(*) falamos sobre isso no irc hoje cedo.
Eu acho que é um tipo de ponto válido, mas não tenho certeza se / como funciona no final - se é um problema com o uso de módulo e construção. Mas certamente parece valer a pena pensar e, no geral, me pareceu bom que o assunto geral tenha sido considerado aqui com cuidado, obrigado pelas informações e pontos de vista de minha parte.
@antont eu vejo. Pessoas sugeriram uma variedade de abordagens diferentes aqui, eu estava assumindo que forneceríamos principalmente documentação para uso de nível superior (retirando tudo de THREE
), mas outros podem criar exemplos que não seguiriam isso e podem levar a alguma confusão. E essa é uma preocupação válida.
Acho que fiquei um pouco confuso com a linguagem.
e outro é o tipo de sistema de módulo mais simples (mas de segunda classe).
Isso se refere apenas ao arquivo de construção, certo?
No meu entendimento, sim. Não consigo imaginar o que mais, mas pode estar faltando alguma coisa.
antont, kumavis: As propostas aqui falam sobre expor o código de estilo require () também para usuários finais, consulte, por exemplo. Comentário mais recente de mattdesl.
"Para desenvolvedores mais ambiciosos que procuram uma construção modular, ou para aqueles que procuram desenvolver soluções de longo prazo em cima do ThreeJS (ou seja, e tirar vantagem do gerenciamento de versão / dependência) [...]"
uma maneira de ter compilações mais otimizadas é ter um script que descubra suas dependências automaticamente e produza os módulos necessários.
agora mesmo o bower & browserify não precisa mais, mas eles não são as únicas soluções. Não sei se existem outros projetos de código aberto prontos para o uso que fazem isso (talvez como dependências de ng), mas já escrevi essas ferramentas antes que acho que haveria outras abordagens para resolver esses problemas.
O compilador de encerramento do Google pode ser essa ferramenta?
Do lado do usuário, isso pode ajudar?
http://marcinwieprzkowicz.github.io/three.js-builder/
isso é muito interessante @erichlof :) Eu me pergunto se @marcinwieprzkowicz gerou isso manualmente ... https://github.com/marcinwieprzkowicz/three.js-builder/blob/gh-pages/threejs-src/r66/modules.json
Uma prática que o three.js usa e que o torna difícil de usar em ambientes commonjs é o uso de instanceof: https://github.com/mrdoob/three.js/blob/master/src/core/Geometry.js#L82
Isso ocorre porque, em um aplicativo, você geralmente acaba com versões diferentes da mesma biblioteca em sua árvore de origem, portanto, verificar instanceof não funciona entre versões diferentes da mesma biblioteca. Seria uma boa preparação para uma mudança para um sistema de módulo commonjs para substituir essas verificações de instância com verificação de recursos por trás de uma interface de estilo Geometry.isGeometry (geom).
em git / three.js / src:
grep -r instanceof . | wc -l
164
em git / three.js / examples:
grep -r instanceof . | wc -l
216
portanto, há um total de 380 usos de instanceof
em three.js. Qual seria a melhor implementação como substituto?
Recentemente, adicionei uma propriedade type
que pode ser usada para substituir a maioria delas.
Recentemente, adicionei uma propriedade de tipo que pode ser usada para substituir a maioria delas.
legais! Preparará um PR.
Para obter um exemplo de como isso é tratado em outra biblioteca JS popular e grande, dê uma olhada em https://github.com/facebook/react . A base de código é estruturada usando o sistema de módulo baseado em estilo de nó (que o browserify implementa), mas é construída para liberação usando grunt. Esta solução é flexível para 3 casos de uso.
require
dependências específicas. Os benefícios do gerenciamento adequado de dependências foram bem documentados.Eu fiz algumas pesquisas ...
Ontem eu hackeei um script (bastante estúpido) que transforma o código fonte Three.js para usar instruções CommonJS require()
para declarar dependências entre arquivos. Só para ver o que acontece ... Este:
var THREE = require('../Three.js');
require('../math/Color.js');
require('../math/Frustum.js');
require('../math/Matrix4.js');
require('../math/Vector3.js');
require('./webgl/WebGLExtensions.js');
require('./webgl/plugins/ShadowMapPlugin.js');
require('./webgl/plugins/SpritePlugin.js');
require('./webgl/plugins/LensFlarePlugin.js');
require('../core/BufferGeometry.js');
require('./WebGLRenderTargetCube.js');
require('../materials/MeshFaceMaterial.js');
require('../objects/Mesh.js');
require('../objects/PointCloud.js');
require('../objects/Line.js');
require('../cameras/Camera.js');
require('../objects/SkinnedMesh.js');
require('../scenes/Scene.js');
require('../objects/Group.js');
require('../lights/Light.js');
require('../objects/Sprite.js');
require('../objects/LensFlare.js');
require('../math/Matrix3.js');
require('../core/Geometry.js');
require('../extras/objects/ImmediateRenderObject.js');
require('../materials/MeshDepthMaterial.js');
require('../materials/MeshNormalMaterial.js');
require('../materials/MeshBasicMaterial.js');
require('../materials/MeshLambertMaterial.js');
require('../materials/MeshPhongMaterial.js');
require('../materials/LineBasicMaterial.js');
require('../materials/LineDashedMaterial.js');
require('../materials/PointCloudMaterial.js');
require('./shaders/ShaderLib.js');
require('./shaders/UniformsUtils.js');
require('../scenes/FogExp2.js');
require('./webgl/WebGLProgram.js');
require('../materials/ShaderMaterial.js');
require('../scenes/Fog.js');
require('../lights/SpotLight.js');
require('../lights/DirectionalLight.js');
require('../textures/CubeTexture.js');
require('../lights/AmbientLight.js');
require('../lights/PointLight.js');
require('../lights/HemisphereLight.js');
require('../math/Math.js');
require('../textures/DataTexture.js');
require('../textures/CompressedTexture.js');
Precisaríamos de uma grande refatoração, talvez dividindo o WebGLRenderer (e outros) em vários módulos (atm, o arquivo tem mais de 6.000 linhas).
THREE.ShaderChunk
em tempo de compilação e depois em THREE.ShaderLib
em tempo de execução (juntando arrays de THREE.ShaderChunk
s), o que é bastante complicado de fazer apenas com o browserify. Presumo que isso exigiria uma transformação browserify que fizesse o mesmo.React.js usa commoner para pesquisar seus módulos sem ter que se referir a eles por caminho de arquivo. Talvez pudéssemos fazer o mesmo e também definir regras personalizadas que nos permitem require
arquivos GLSL transformando-os na sintaxe JS.
@rasteiner, você pode ficar muito feliz em saber mais sobre https://github.com/stackgl/glslify , ele vem da crescente família http://stack.gl
Eu tive um pouco de experiência com módulos e a abordagem "unixy" nos últimos dois meses e meu pensamento agora é que é um pouco tarde demais, e refatorar threejs para modularidade ou módulos npm seria uma meta irreal.
Aqui está o que estou fazendo atualmente para resolver o problema de modularidade / reutilização:
Meus novos projetos tendem a usar "três" no npm apenas para começar a funcionar. Seria muito bom se ThreeJS publicasse oficialmente a construção para o npm usando tags de versão que se alinham com os números de lançamento.
PS: para aqueles interessados em trazer shaders reutilizáveis / modulares para seu fluxo de trabalho:
https://gist.github.com/mattdesl/b04c90306ee0d2a412ab
Enviado do meu iPhone
Em 20 de novembro de 2014, às 7h42, aaron [email protected] escreveu:
@rasteiner, você pode ficar muito feliz em saber mais sobre https://github.com/stackgl/glslify , ele vem da crescente família http://stack.gl
-
Responda a este e-mail diretamente ou visualize-o no GitHub.
No caso de ajudar outras pessoas que possam estar procurando como usar o Three.js com o browserify, e tropeçar neste tópico, a maneira que eu mesmo configurei é usando o browserify-shim .
Seguindo a seção README em _ "Você às vezes a) Exporá variáveis globais via global" _, incluí uma tag de script separada para Three.js e a configurei para expor a variável global THREE.
E então apenas uma parte que eu tive que descobrir sozinho foi como incluir extras como ColladaLoader, OrbitControls etc. Eu fiz assim:
De package.json:
"browser": {
"three": "bower_components/threejs/build/three.js"
},
"browserify-shim": "browserify-shim-config.js",
"browserify": {
"transform": [ "browserify-shim" ]
}
browserify-shim-config.js:
module.exports = {
"three": { exports: "global:THREE" },
"./vendor/threejs-extras/ColladaLoader.js": { depends: {"three": null}, exports: "global:THREE.ColladaLoader" },
"./vendor/threejs-extras/OrbitControls.js": { depends: {"three": null}, exports: "global:THREE.OrbitControls" }
};
Então, em meu próprio script, main.js:
require('../vendor/threejs-extras/ColladaLoader.js');
require('../vendor/threejs-extras/OrbitControls.js');
var loader = new THREE.ColladaLoader(),
controls = new THREE.OrbitControls(camera);
...
O Browserify requer a reconstrução de todo o script quando você modifica até mesmo em bytes. Certa vez, usei o browserify para empacotar um projeto que requer THREE.js, então levo mais de dois segundos para construir um boundle e bloqueia o livereload toda vez que faço uma alteração. Isso é muito frustrante.
Você normalmente usa watchify durante o desenvolvimento com livereload. Esse constrói o pacote incrementalmente.
watchify não funciona para mim. Quando eu mudo um arquivo e o salvo, watchify e beefy livereload fornecem a versão mais antiga / em cache. Não tenho ideia de por que isso acontece. Felizmente, o browserify já funciona muito bem.
@ChiChou Passe em --noparse=three
para o navegador. Isso leva o pacote do browserify de 1000 ms para 500 ms na minha máquina, o que é decente o suficiente para uma sensação de feedback instantâneo.
@rasteiner Quero agradecer novamente por sua pesquisa informal sobre as interdependências do three.js. Embora essa lista massiva de dependências seja um código de aparência feia, na verdade essa feiura está presente como está, apenas invisível. O ponto forte do Browserify é exigir que arejemos nossas roupas sujas e busquemos sistemas menos emaranhados.
Há muitos lugares em Three.js onde pegamos algum objeto, percebemos seu tipo e executamos diferentes tarefas com base nesse tipo. Na maioria desses casos, esse código dependente do tipo poderia ser movido para o próprio tipo, e não precisaríamos ter uma compreensão de todos os tipos possíveis em que estamos operando.
O seguinte é um exemplo resumido do WebGLRenderer :
if ( texture instanceof THREE.DataTexture ) {
// ...
} else if ( texture instanceof THREE.CompressedTexture ) {
// ...
} else { // regular Texture (image, video, canvas)
// ...
}
deveria ser mais da forma
texture.processTexImage( _gl, mipmaps, otherData )
Deixe o tipo determinar como se comportar. Isso também permite que o consumidor da biblioteca use novos tipos de textura nos quais não havíamos pensado. Essa estrutura deve reduzir a interdependência.
Acho que mudar para uma arquitetura de browserify é definitivamente o caminho a percorrer. A construção UMD tornará o consumo de THREE.js mais fácil. Também nos permitirá dividir o WebGLRenderer em vários arquivos, porque agora ele parece um tanto monolítico e assustador.
Eu comecei um branch onde estou trabalhando atualmente para movê-lo aqui: https://github.com/coballast/three.js/tree/browserify-build-system
Por favor, deixe-me saber o que você pensa.
Aqui estão as alterações de @coballast .
Parece que você está adotando a abordagem de conversão automatizada com seu arquivo browserifyify.js
, que eu acho que é o caminho certo a seguir.
Uma coisa que todos nós não discutimos muito ainda é a melhor forma de fazer a transição desta biblioteca grande e em constante mudança para o navegador. Você pode fazer as alterações e abrir um PR, mas ele ficará imediatamente desatualizado. Isso é o que é atraente sobre a abordagem automatizada.
Se pudermos:
browserifyify.js
)... então podemos transformar isso em uma conversão de botão que ainda funcionará no futuro previsível. essa simplicidade permite que essa noção onírica de uma mudança fundamental da arquitetura para um projeto tão grande seja realizada quando os argumentos ideológicos vencem.
@coballast para esse fim, eu removeria as alterações em src / Three.js se ele funcionar da mesma forma.
Nota: não apenas reverter, mas remover essas mudanças do histórico do branch por meio de um novo branch ou um push forçado
@coballast Eu me pergunto se faria mais sentido para o utilitário de conversão não ser um fork de three.js
, mas um utilitário externo que você aponta para o diretório de desenvolvimento three.js
e converte o código-fonte arquivos, adiciona um script de construção e executa os testes.
@kumavis Eu concordo em deixar o diretório src sozinho. Acho que a coisa a fazer é fazer com que o utilitário escreva um diretório duplicado com o código commonjs, e podemos testar e executar a compilação do browserify a partir daí para garantir que todos os exemplos funcionem antes de tentar fazer algo importante.
Também há uma oportunidade interessante aqui de escrever algumas coisas de análise estática que irão verificar e aplicar automaticamente um estilo consistente em toda a base de código.
@coballast parece ótimo.
Existe uma grande variedade de ferramentas para reescrever código automatizado, por exemplo, escodegen . Precisamos ter certeza de que estamos mantendo comentários, etc.
Deseja iniciar um repositório de utilitário de conversão threejs?
@coballast que disse, manter um foco nítido para este utilitário é importante
@kumavis Considere feito. Eu realmente quero que isso aconteça Este é apenas um dos dois projetos em que estou trabalhando no momento.
@kumavis @mrdoob Parte da discussão aqui parece girar em torno da ideia de dividir TRÊS em vários módulos separados que poderiam ser instalados via npm e depois compilados com o browserify. Não sou totalmente contra a ideia, mas acho que deveria ser uma questão separada. A única coisa que estou defendendo neste momento é usar o browserify para gerenciar a base de código do THREE internamente. Faça com que ele seja transferido e funcione da mesma forma que sempre funcionou para os usuários e, em seguida, avalie o que faz sentido.
Estou curioso para ver qual é o resultado desse utilitário ^^
@coballast vincula um
https://github.com/coballast/threejs-browserify-conversion-utility
O código está uma bagunça, vai limpar em breve.
aqui vamos nós! :foguete:
Agora tenho o utilitário em um estado em que ele gera browserify src e o criarei sem problemas. Atualizarei o repo com instruções sobre como fazer isso sozinho. Neste ponto, os exemplos não funcionam. Existem vários problemas que precisam ser resolvidos para corrigir isso. Vou adicioná-los ao repo se alguém quiser arregaçar as mangas e ajudar.
@coballast sim, por favor, registre os problemas como TODOs, e eu ou outras pessoas entraremos em ação como pudermos.
Sérios problemas surgiram. Veja # 6241
Aqui está minha análise do que precisa acontecer para que isso funcione: https://github.com/coballast/threejs-browserify-conversion-utility/issues/9#issuecomment -83147463
browserify é no mínimo redundante de transporte (conjestivo) devido ao seu design. Isso torna seu custo de uso inflativo (plano de dados, alguém?) E lento.
Uma solução simples para isso é separar o documento do código da biblioteca, o que implicaria em dois arquivos de cliente e não um. Esta é uma prática comum para js do lado do cliente.
Se no início o browserify está com defeito e precisa ser consertado, dificilmente posso ver por que ele deve ser considerado para melhorar alguma coisa, muito menos algo como threejs.
@spaesani Porque os dados para threejs devem ser baixados de qualquer maneira. Se dividirmos o threejs em módulos menores e deixarmos um sistema de compilação automatizado escolher o que precisa para um único aplicativo, na verdade a maioria dos aplicativos do threejs que existem seriam mais leves.
Se por algum motivo você ainda deseja separar "documento do código de biblioteca", você ainda pode fazer isso e usar uma versão pré-construída como fazemos agora. Você pode até mesmo dividir seu aplicativo integrado no browserify em módulos separados usando os sinalizadores --standalone e --exclude .
Browserify é apenas uma maneira de usar uma API de definição de módulo comprovada em batalha (CommonJS) no navegador. Isso simplificaria muito o desenvolvimento de plug-ins threejs e aumentaria a clareza do código e, portanto, a produtividade, permitiria a integração em um ecossistema maior (npm), onde o código é inerentemente mantido por mais pessoas, mantendo a integridade por meio do sistema de controle de versão (pense sobre família stackgl ), e nem mesmo forçaria as pessoas a entrar no CommonJS se elas não quisessem.
Claro que existem desvantagens, mas não são as que você mencionou.
three.js e three.min.js podem ser armazenados em cache para economizar no transporte (dados) por um proxy, a solução móvel comum ou um navegador de armazenamento em cache.
No momento em que você seleciona e agrega o código threejs com o código específico do documento, o armazenamento em cache não é viável.
Se o browserify permitir
sp
On Mar 28, 2015 1:06 PM, Roman Steiner notifications@github.com wrote:@spaesani Because the data for threejs has to be downloaded anyway. If we split threejs into smaller modules and let an automated build system cherry pick what it needs for a single app, actually most threejs apps out there would be lighter.
If for some reason you still want to separate "document from library code", you could still do this and use a pre-built version like we do now. You could even split your browserify-built app into separate modules by using the --standalone flag.
Browserify is just a way to use a battle proven module definition API (CommonJS) on the browser. It would greatly simplify the development of threejs plugins and enhance code clarity and therefore productivity, it would allow us to integrate into a bigger ecosystem (npm) where the code is inherently maintained by more people while still maintaining integrity through the versioning system, and it wouldn't even force people into CommonJS if they don't want it.
Of course there are downsides, but they're not the ones you've mentioned.
—Reply to this email directly or view it on GitHub.
@spaesani It (browserify) melhora as coisas para os humanos. Minha própria felicidade psicológica e bem-estar são mais importantes do que a facilidade com que uma máquina pode carregar e executar coisas.
Muitos problemas de carga de rede móvel serão amenizados um pouco por coisas como http / 2. Problemas como esse são resolvidos melhor modificando as camadas que estão mais abaixo na pilha de abstração. Problemas de desempenho não devem nos impedir de seguir as melhores práticas de engenharia de software, como modularidade / separação de interesses, etc.
Encontrei este problema porque minha equipe começou recentemente a usar jspm. Podemos importar threejs (acredito que seja porque o arquivo principal foi pesquisado). Eu estava procurando ver se alguém tinha transformado threejs em módulos es6, principalmente por causa do recurso de compilação do jspm (agrupando todas as dependências em um único arquivo, mas apenas capturando as dependências que são usadas).
Embora seja ótimo que mrdoob mantenha o tamanho de três js abaixo de 100 kb, descobri que a maioria dos meus projetos não usa muito o código-base (sinto que é a maioria, mas não tentei descobrir isso). CubeCamera, OrthographicCamera, CanvasRenderer, várias Luzes, Carregadores, Curvas, Geometrias, Auxiliares, etc. Além disso, acho que a maioria dos meus projetos inclui alguns dos scripts de exemplo.
Minha esperança era que seria possível ter um único local de todos esses módulos (aqueles normalmente agrupados com threejs, bem como aqueles em exemplos) e simplesmente importar os que eu preciso, então quando eu agrupar o projeto, o resultado será em um arquivo muito menor do que o threejs original, embora contenha muitas partes que não foram originalmente incluídas.
Eu também queria adicionar que se threejs fosse construído usando módulos browserify, ele adicionaria uma pequena sobrecarga de tamanho de arquivo (mas incomparável aos atuais 403kb em r70), mas também removeria o uso da variável global THREE do código, assim permitindo que variáveis como THREE.Geometry sejam minimizadas pelo fechamento.
Fiz um teste rápido, localizando e substituindo, para me livrar do objeto THREE (de modo que todos os seus filhos poluíram o namespace) e agrupando todo o arquivo em um IIFE, em seguida, executei tudo por meio do encerramento do google. O arquivo resultante (sem gzip) tinha 238 kb, abaixo de 777 kb.
Embora os resultados variem, acho que definitivamente vale a pena garantir que isso possa acontecer.
obrigado por contar - muitos pontos bons lá, e familiares para nós também. também nunca usamos muitos renderizadores em um projeto, mas fazemos coisas do tipo lib a partir de exemplos.
não percebi isso sobre como minimizar - essa é uma grande diferença.
e os módulos es6 certamente pareceram promissores - também foi bom saber que há um caminho lá do padrão AMD / CommonJS / tal padrão de módulo e uso de lib.
@colin Não tenho certeza se sigo você sobre como o browserify
ajuda a sua felicidade psicológica.
Está na documentação?
browserify é uma vaca leiteira transportadora ...
Terça-feira, 31 de março de 2015, 10:11 PM -4: 00 de Colin Ballast notifications@github.com :
@spaesani It (browserify) melhora as coisas para os humanos. Minha própria felicidade psicológica e bem-estar são mais importantes do que a facilidade com que uma máquina pode carregar e executar coisas.
Muitos problemas de carga de rede móvel serão amenizados um pouco por coisas como http / 2. Problemas como esse são resolvidos melhor modificando as camadas que estão mais abaixo na pilha de abstração. Problemas de desempenho não devem nos impedir de seguir as melhores práticas de engenharia de software, como modularidade / separação de interesses, etc.
-
Responda a este e-mail diretamente ou visualize-o no GitHub.
Agora, se o browserify determinasse automaticamente as dependências sem uma instrução require ... ei, espere ...
@spaesani Na verdade, prefiro as dependências explícitas - ajuda a entender como o código se encaixa.
browserify é uma vaca leiteira transportadora ...
A sobrecarga do
Atualização de status:
Eu tenho uma filial com algum código de navegador:
https://github.com/coballast/three.js/tree/browserify
Lembre-se de que este é um trabalho em andamento. Esse código foi gerado automaticamente e, como resultado, terá uma aparência horrível por um tempo. Ainda estou tentando consertar alguns problemas de compilação. Consulte coballast / threejs-browserify-conversion-utility # 10 se você acha que pode consertá-lo. Estava crescendo por um tempo, mas não está agora.
@kumavis e eu temos trabalhado para resolver alguns problemas de tempo de execução (e melhorar a arquitetura do software também). Eu acredito que mencionei isso acima em algum lugar.
Desculpe pela longa resposta. TLDR: jspm / es6 roda, mas tem algumas estranhezas: 1) Exportar objetos antes de defini-los; 2) Exportar objetos contendo uma única classe, ao invés de apenas exportar uma única classe; 3) IIFE usando dependências circulares; 4) Estrutura do arquivo.
Eu brinquei com seu branch com navegador em jspm ( @spinchristopher acima sou eu) e tenho algumas notas, embora primeiro: Não seria bom abrir questões sobre esse fork, então este tópico não está cheio deles e eles não estão misturados?
Embora seja executado, na verdade não produz o resultado correto. (usando a demonstração simples no início). Cria a tela e a preenche de preto (a menos que eu defina a cor clara como transparente), mas não está realmente renderizando o cubo. No entanto, não espero que funcione neste momento, visto que ainda está muito no início do processo.
Encontrei 3 problemas principais:
1. Esse foi o mais irritante e, honestamente, não tenho certeza de como você consegue compilar algo com esse erro em particular, já que ele não deveria funcionar de jeito nenhum. Muitos dos arquivos começam assim (isso é bom porque as definições de função são recentes e são essencialmente executadas antes da linha module.exports, mesmo que apareça primeiro):
module.exports.Foo = Foo;
function Foo() {}
O problema está nos muitos arquivos que são assim (o primeiro que vi foi math / Math.js). A inicialização do objeto é içada (é por isso que não há erro indefinido), mas a definição permanece em vigor (portanto, a exportação é indefinida).
module.exports.Foo = Foo;
var Foo = {};
A única correção que encontrei aqui é mover a linha de exportação para o final ou reescrevê-la assim (preferencial):
var Foo = module.exports.Foo = {};
Dois. Os dados exportados. Ao lidar com arquivos modularizados, o padrão é que cada arquivo exporte um único objeto. Embora a maioria dos arquivos seja assim (embora alguns exportem mais), eles não exportam o construtor único, eles exportam um objeto que contém esse construtor (ou seja: module.exports.Foo = Foo;
vez de module.exports = Foo;
. O último é a forma como todos os exemplos do browserify funcionam). Portanto, ao usar o requer, você deve avançar um nível mais profundo ( var Vector3 = require('../math/Vector3').Vector3;
). Além de ser desnecessário, não há como fazer isso ao importar para o es6. ( import Vector3 from '../math/Vector3'; var vector = new Vector3.Vector3();
). Embora seja necessário obter uma exportação específica no es6, ela se aplica ao usar módulos navegados e ainda teria a mesma redundância ( import { Vector3 } from '../math/Vector3';
). Existem alguns arquivos que simplesmente coletam outros objetos (o óbvio é Three.js), mas eles devem ser reduzidos ao mínimo e realmente devem ser usados apenas para o processo de construção, não como uma forma de pegar muitas coisas em produção .
Três. Isso tem a ver com as dependências circulares. System.js (o carregador de módulo usado por jspm) pode lidar com dependências circulares muito bem, mas há um problema. Em muitos lugares, o código é semelhante ao seguinte. O problema é que, embora Vector3 tenha sido passado como uma dependência, neste momento ele não foi totalmente carregado (como Vector3 também inclui esse arquivo, cada um não pode ser resolvido até que o outro seja resolvido) e não pode ser criado. Eu adicionei uma correção muito ruim (mostrada abaixo), embora não tenha certeza de como isso seria melhor corrigido. Parece que este é um problema arquitetônico que pode não ter uma solução simples. Acontece muitas e muitas vezes. Parece ser uma otimização para evitar a criação de um novo Vector3 cada vez que a função é chamada. Se realmente houver um impacto significativo no desempenho que não pode ser corrigido pela otimização do Vector3, talvez adicione uma função ao Vector3 para retornar um vetor3 não utilizado que será lançado posteriormente?
Foo.prototype.bar = function() {
var vector = new Vector3();
return function() {
// some data which reuses vector repeatedly.
};
}();
O conserto:
Foo.prototype.bar = function() {
var vector;
return function() {
if(!vector) vector = new Vector3();
// some data which reuses vector repeatedly.
};
}();
Por fim, gostaria de acrescentar um pouco sobre a organização de arquivos. Obviamente, isso é algo a ser abordado depois que o conjunto atual for compilado corretamente, mas eu queria trazê-lo à tona agora. Embora a estrutura de arquivos atual funcione, algumas partes dela são um tanto estranhas ou mesmo desajeitadas. Os principais agrupamentos (câmeras, materiais, geometrias, etc.) parecem estar bem, embora eu deva fazer algumas alterações, como visto a seguir. Eu também moveria os globais em ThreeGlobals para o que eles são globais. IE: FrontSide, BackSide, DoubleSide pertencem ao Material (junto com NoShading, FlatShading e SmoothShading. Na verdade, parece que a maioria deles pertence ...).
Minhas confusões primárias vieram com o núcleo e os extras. core / Geometry.js deve estar na pasta geometries, assim como Material está na pasta de materiais. Mas não existe uma pasta de geometrias, está em extras. A propósito, extras também tem um núcleo e uma geometria, mas a geometria base não está nesta pasta. Há uma grande coleção de ajudantes, mas cada ajudante não deveria estar com o que está ajudando? Os processos de construção podem ser facilmente configurados para pegar apenas os arquivos que você deseja, portanto, não há desculpa para colocar os arquivos não importantes em outro lugar.
Atualmente, tenho uma linha em meu código que diz import BoxGeometry from 'threejs/extras/geometries/BoxGeometry';
e var geometry = new BoxGeometry.BoxGeometry( 1, 1, 1 );
Por estar acostumado a usar `new THREE.BoxGeometry ()` `` demorou um pouco para encontrar o arquivo. Ao usá-lo de maneira modular, a localização do arquivo é tão importante quanto algo como assinaturas de função.
Mudanças gerais que eu faria na estrutura do arquivo. Isso se aplica a muitos lugares, mas estou apenas mostrando um exemplo. (Como observação, sempre preferi um modelo de nomear o arquivo após a única classe que ele exporta e colocar o arquivo em uma pasta com o mesmo nome. Quaisquer descendentes diretos geralmente vão para essa pasta, mas, novamente, para uma pasta com o mesmo nome que eles próprios. No entanto, se não gostar deste padrão, aplica-se a mesma estrutura abaixo, apenas retirando aquele nível extra. Além disso, qualquer carregador de ficheiros pode ser facilmente modificado [os ganchos são normalmente fornecidos directamente, de facto] para automatizar a disposição em camadas e simplificar as instruções de requerimento].) (Eu também prefiro todos os arquivos em minúsculas, com sublinhados quando necessário.)
Three.js - This is _only_ used in the build process, so it should actually be with the build files, but run as if it is in this location.
geometry/geometry.js - Currently at core/Geometry.js
geometry/face3/face3.js - from core/Face3.js
geometry/box_geometry/box_geometry.js - Currently at extras/geometries/BoxGeometry.js
geometry/circle_geometry/circle_geometry.js - Similar to above.
geometry/utils/utils.js - from extras/GeometryUtils.js
camera/camera.js
camera/cube_camera/cube_camera.js
camera/perspective_camera/perspective_camera.js
camera/helper/helper.js - or camera/camera_helper/camera_helper.js
scene/scene.js
scene/fog/fog.js
scene/fog_exp2/fog_exp2.js
Eu provavelmente também renomearia matemática para utils (cada categoria também pode ter utils, como geometria acima) para que possa conter mais do que apenas matemática (muitas das coisas do núcleo).
@HMUDesign @spinchristopher obrigado pela ótima análise! É melhor colocar esses tipos de problemas no repositório do utilitário coballast / threejs-browserify-conversion-conversion no futuro.
ok, deixe-me ler corretamente seu comentário agora.
De alguma forma, perdi o link para esse repositório acima. Terei todo o gosto em resolver os meus problemas
para aquele repo amanhã, dividindo-o conforme necessário (percebi que pelo menos
parte dele já está lá)
Em 9 de abril de 2015, às 12h09, "kumavis" notifications@github.com escreveu:
@HMUDesign https://github.com/HMUDesign @spinchristopher
https://github.com/spinchristopher obrigado pela excelente análise! Melhor
para colocar esse tipo de problema no
coballast / threejs-browserify-conversion-utility repo no futuro.ok, deixe-me ler corretamente seu comentário agora.
-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -91132413.
Sim, e eu faço isso para minhas próprias bibliotecas de tipos de utilitários (* arquivos de utilitários são os
única vez que não tenho uma exportação padrão, embora às vezes eu adicione um
especialista além do padrão), no entanto, essa sintaxe só funciona quando você
exportar várias variáveis nomeadas. O carregador para módulos js comuns trata
modules.exports como uma exportação padrão, que não pode ser desestruturada no
import = (
Em 9 de abril de 2015, às 12h12, "kumavis" notifications@github.com escreveu:
no es6, você pode importar propriedades dos objetos de exportação via
desestruturação.importar {Vector3} de '../math/Vector3';
Dito isso, concordo que é preferível uma exportação por módulo.
-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -91132982.
@HMUDesign obrigado novamente por sua energia e análise - aqui estamos construindo uma lista de tarefas, sinta-se à vontade para começar e outras coisas. https://github.com/coballast/threejs-browserify-conversion-utility/issues/17
+1 para browserify.
Também +1 para mover shaders em arquivos separados usando glslify.
Também +1 para adotar alguns recursos do ES6 - como classes e módulos. A nova pilha de construção nos permitirá compilar de volta para ES5, se necessário. Consultar exemplo:
import Object3D from '../core/Object3D';
import Geometry from '../core/Geometry';
import MeshBasicMaterial from '../materials/MeshBasicMaterial';
class Mesh extends Object3D {
constructor(
geometry = new Geometry(),
material = new MeshBasicMaterial({color: Math.random() * 0xffffff}
) {
super();
this.geometry = geometry;
this.material = material;
this.updateMorphTargets();
}
}
export default Mesh;
@lmcd Enquanto estamos nisso, podemos usar módulos es6 e usar o babeljs para compilar tudo.
@coballast, estou interessado em ramificar seu branch browserify
e fazer algumas dessas coisas acontecerem
@lmcd Eu não me incomodaria. Vou desenvolver ferramentas automatizadas para mover coisas do es5 para o es6 automaticamente. Faz sentido, uma vez que existe uma grande quantidade de código es5 por aí, e a necessidade de trabalho para movê-lo manualmente é astronômico.
@coballast Eu estava pensando mais em fazer um passe 5to6
: https://github.com/thomasloh/5to6
@lmcd oo nice find
mas tbh, parece que seria mais fácil reescrever three.js do zero: P
@lmcd Estou tão feliz por você ter encontrado isso. Era uma daquelas coisas que eu faria por necessidade, mas parecia claramente não divertido.
@mrdoob qual é sua opinião atual sobre esse assunto?
@anvaka No momento, estou focado na refatoração de WebGLRenderer
. Eu não tenho mais largura de banda mental 😅
Recentemente encontrei um projeto que estava usando módulos es6 felizmente com o babel polyfill que já foi mencionado aqui também. Não consegui lembrar nem descobrir agora o que era, parecia bom para mim de qualquer maneira.
O es6 também parece estar concluído agora na frente dos padrões: "Finalmente, ECMA-262 Edição 6 foi oficialmente aprovado e publicado como um padrão em 17 de junho de 2015", diz https://developer.mozilla.org/en-US/docs / Web / JavaScript / New_in_JavaScript / ECMAScript_6_support_in_Mozilla
Apenas uma nota que em relação às ferramentas e estabilidade das especificações do módulo, a situação parece boa nessa frente.
Recentemente encontrei um projeto que estava usando módulos es6 felizmente com o babel polyfill que já foi mencionado aqui também. Não consegui lembrar nem descobrir agora o que era, parecia bom para mim de qualquer maneira.
É também 47kb de js extra e lê e transpila o javascript incluído para es5 no navegador, portanto, não é ótimo para o tempo de inicialização.
Não há nada que impeça alguém que usa three.js de usar es6 em seu próprio código; no entanto, usá-lo na biblioteca introduziria problemas de compatibilidade e desempenho do navegador em toda a linha.
Ah - de pé corrigido aqui, obrigado pela informação. Eu acho que o browserify e outros que funcionam no processo de compilação são melhores agora do que então.
Ah - de pé corrigido aqui, obrigado pela informação. Eu acho que o browserify e outros que funcionam no processo de compilação são melhores agora do que então.
Um dos principais problemas do es6 é que ele tem alterações de sintaxe importantes com o es5; por exemplo, a seta grande => é es5 inválido e fará com que o analisador javascript falhe e saia da tentativa de compilar o código. Esperançosamente, alguém vai descobrir uma maneira de contornar isso, mas ainda não o fez.
Na verdade, estava pensando apenas no sistema de módulos, na instrução de importação etc.
É também 47kb de js extra e lê e transpila o javascript incluído para es5 no navegador, portanto, não é ótimo para o tempo de inicialização.
por exemplo, a seta grande => é es5 inválida e fará com que o analisador javascript falhe e saia da tentativa de compilar o código
O código es6 pode ser transpilado para es5 durante _build_ sem penalidade de tempo de execução. É apenas uma questão de adicionar uma etapa de babel ao pipeline de construção.
Por exemplo, a função de seta pode ser transpilada para es5 durante a construção sem polyfill ou penalidade de tempo de execução. Babel irá transpilar este trecho es6
function MyObj() {
this.step = 1;
this.increment = function ( arr ) {
return arr.map( v => v + this.step );
}
}
nesta versão portátil:
function MyObj() {
this.step = 1;
this.increment = function (arr) {
var _this = this;
return arr.map(function (v) {
return v + _this.step;
});
};
}
Outro recurso, como classes es6, irá gerar um pequeno polyfill (você pode ver no babel repl http://babeljs.io/repl/).
@mrdoob entendido. Você apoiaria a ideia de dividir o three.js em módulos menores hospedados no npm?
O repositório principal three.js permanecerá inalterado: os consumidores não terão que construir nada. Usuários mais experientes seriam capazes de escolher as partes necessárias do three.js.
Isso soa bem. Mas não sei os detalhes.
O código es6 pode ser transpilado para es5 durante a compilação sem penalidade de tempo de execução. É apenas uma questão de adicionar uma etapa de babel ao pipeline de construção.
Por exemplo, a função de seta pode ser transpilada para es5 durante a construção sem polyfill ou penalidade de tempo de execução. Babel irá transpilar este trecho es6
A transpilação ES6 ainda vem com uma penalidade de tempo de execução significativa: http://www.incaseofstairs.com/2015/06/es6-feature-performance/ especialmente para uma biblioteca de alto desempenho.
modules / npm / browserfy etc, no entanto, é provavelmente uma boa ideia
+1 na modularização adequada usando módulos ES6
+1 na modularização adequada usando qualquer sistema de módulo lógico (commonjs, amd, es6)
Eu acho que commonjs e amd são as escolhas preferidas b / c eles não precisam de transpilação
Eles precisam de uma etapa de construção, no entanto, que é equivalente ao
etapa de transpilar.
O uso do ES6, além de ser a próxima versão da linguagem, permitiria a
uso dos próximos recursos conforme desejado, mas sem quebrar o código nativo existente.
É realmente sensato reativar a base de código em um sistema que já está
não é o mais recente?
Em 20 de julho de 2015, às 12h05, "kumavis" notifications@github.com escreveu:
+1 na modularização adequada usando qualquer sistema de módulo lógico (commonjs, amd,
es6)
Acho que commonjs e amd são as escolhas preferidas b / c eles não
necessita de transpilar-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -122990605.
Eles precisam de uma etapa de construção, no entanto, que é equivalente ao
etapa de transpilar.
construir e transpilar não são equivalentes em termos da complexidade que introduzem.
É realmente sensato reativar a base de código em um sistema que já está
não é o mais recente?
commonjs é simples e funciona muito bem. não estou convencido de que 'mais recente' === 'melhor'.
O uso do ES6 [...] permitiria o uso dos próximos recursos conforme desejado
então vale a pena considerar isso. queremos recursos do es6? se começarmos a transpilar ES6, as pessoas começarão a fazer RP ES6. como @benaadams sugeriu, há impactos de desempenho não intuitivos no uso de recursos do es6.
além disso, não precisamos confundir as questões de 'sistema de módulo' e 'recursos es6'. você pode transpilar ES6 e usar commonjs. e você pode apresentá-los separadamente.
+1 para browserify / commonjs - é simples de compilar com browserify de forma que as pessoas ainda possam usar a biblioteca da maneira tradicional se quiserem - é para isso que serve o UMD, permitir que a AMD requeira (como require.js), O CommonJS requer (como node + browserify) e uma janela global (para tags de script) dependendo do ambiente em que estamos executando.
PIXI.js acabou de mudar para uma arquitetura modular usando browserify e a biblioteca foi configurada de uma forma muito semelhante - tudo anexado a um objeto PIXI global. A configuração deles é muito parecida com a que @kumavis descreveu no segundo post.
Nem o browserify nem o commonjs atendem às necessidades específicas de um mecanismo 3D, o que não significa que não possam ser usados, mas devem ser vistos como uma peça de um quebra-cabeça maior:
Os componentes precisam exportar metainformações sobre as propriedades de suas instâncias, para que possa haver um carregador para objetos arbitrários e conexões de dados de memória compartilhada. Com essa arquitetura, seria apenas uma questão de bom senso também carregar o código do componente fora do núcleo na primeira utilização. Estive fazendo um brainstorming sobre esses tópicos em # 6464 e # 6557.
+1
+1
Como uma solução híbrida, também é possível adicionar os requisitos como comentários. Eu sei que o browserfy já está em muitos ecossistemas, mas eu só queria deixar isso aqui como uma variante de implementação rápida :) porque você não teria que mudar nada. Você só precisa adicionar um comentário no topo de cada arquivo.
Como desenvolvedor, você pode criar facilmente seus próprios arquivos min.js com o plugin @requires
information e gulp.
Olá a todos, Recentemente, tive uma necessidade semelhante de carregar recursos arbitrários com suas próprias dependências de uma maneira limpa e estruturada e eu vim com a solução de escrever plug-ins require.js para cada tipo de recurso. Dessa forma, deixo a resolução de dependência de require.js cuidar do download e armazenamento em cache adequados dos recursos ... Ao mesmo tempo, essa abordagem cria 'pacotes' de recursos reutilizáveis que posso usar em vários de meus projetos.
Se você estiver interessado, pode encontrar o projeto aqui: https://github.com/wavesoft/three-bundles
(Um exemplo usando esta biblioteca estará disponível em breve)
No futuro, estou planejando incluir uma fase de otimização nesses plug-ins para permitir que o otimizador require.js compile os recursos em um formato ainda mais compacto.
Olhando para esta conversa https://twitter.com/defunctzombie/status/682279526454329344 , não parece que os módulos es6 serão implementados em um futuro próximo. Algo para manter em mente.
Fiz alguns protótipos com módulos commonjs e browserify.
Meu pacote final com navegador inclui todos os arquivos da pasta src
e resulta em 962K
tamanho de arquivo (em comparação com a versão original não navegador 885K
).
A construção direcionada de cloth
exemplo é:
580K
(~ 44% menor)431K
(~ 8% menor)Aqui está a divisão do tamanho do pacote: http://output.jsbin.com/yogoxawozu. Os renderizadores pegam 40% do pacote e 10% disso é levado pela biblioteca de shaders.
Acho que poderíamos reduzir o tamanho do pacote:
instance of
cheques - eles requerem módulos de referência explícita, mesmo quando não são usados. Vejo que algumas das classes já têm type
- poderíamos usar isso em toda a biblioteca.glslify
foi trazido algumas vezes e pode definitivamente ajudar. Idealmente, cada componente que requer sombreadores precisa depender explicitamente de um sombreador.Você pode verificar os resultados e verificar o código:
git clone --depth 1 --branch commonjs https://github.com/anvaka/three.js.git
cd three.js
npm i
# build backward compatible three.js library from commonjs modules.
# The output will be save into `build/three.min.js`. I'm using `.min.js` just
# to quickly verify examples. The actual file is not minified.
npm run build
# build cloth example
# the output is saved into ./examples/cjs/webgl_animation_cloth.bundle.js
npm run demo
não parece que os módulos es6 serão implementados em um futuro próximo. Algo para manter em mente.
Isso é verdade, mas também é importante perceber que o suporte ao módulo CommonJS _nunca_ será implementado em navegadores, então a escolha é entre
Bibliotecas como a D3 estão adotando módulos ES6 porque elas já podem fazer tudo que os módulos CommonJS podem fazer (exceto rodar nativamente em Node.js, o que não é realmente uma preocupação para uma biblioteca como Three.js) e resultar em compilações menores.
Fiz alguns experimentos em https://github.com/rollup/three-jsnext e, embora não esteja pronto para produção (preciso gastar um pouco mais de tempo transferindo exemplos etc!), A compilação UMD que ele gera é na verdade _smaller_ do que a compilação atual.
Eu concordaria com a nota sobre módulos es6 vs outros sistemas. Ou
não são um padrão es, são um padrão comunitário. E embora eles
não pode ser executado "nativamente" no nó, pode parecer nativo com ganchos Babel.
Entrarei em contato com seu repositório em breve.
Além disso, o fato de ser menor foi algo que mencionei anteriormente em
esta conversa. "TRÊS. Geometria" torna-se "geometria" que pode ser
reduzido para "a", por exemplo.
Além disso, a solução para a instância de verificações é removê-los todos
juntos. Um módulo não deve ser diferente, dependendo de qual
foi dado, mas em vez disso adiando a coisa fornecida para fazer o que é necessário
pendência. Então, não há verificações de instância ou tipo.
Em 1º de janeiro de 2016, às 20h23, "Rich Harris" notifications@github.com escreveu:
não parece que os módulos es6 serão implementados perto
futuro. Algo para manter em mente.Isso é verdade, mas também é importante perceber que o módulo CommonJS
o suporte _nunca_ será implementado em navegadores, então a escolha é entre
- continuando com uma arquitetura não modular e uma construção ad hoc
sistema, que tem servido bem a Three.js até agora, mas atua como um freio ao crescimento
a longo prazo- usando módulos CommonJS, o que envolve alguns truques em torno dos
dependências e resultados em uma construção maior, ou- usando módulos ES6, que são adequados para uma base de código como Three.js
que tem dependências cíclicas, e que resultam na menor e na maioria
Possibilidade de construção minimizável. Eventualmente, os navegadores irão suportá-los nativamente,
e as mudanças necessárias para acomodar quaisquer peculiaridades imprevistas no carregador
a especificação provavelmente será trivial em comparação com o esforço envolvido em
atualizar a partir de uma base de código CommonJS.Bibliotecas como a D3 estão adotando módulos ES6 porque já podem fazer
tudo que os módulos CommonJS podem fazer (exceto executar nativamente em Node.js, que
não é realmente uma preocupação para uma biblioteca como Three.js) e resulta em menores
constrói.Eu fiz algumas experiências em
https://github.com/rollup/three-jsnext , e embora não seja produção
pronto (preciso gastar um pouco mais de tempo transferindo exemplos etc!) o build UMD
ele gera é na verdade _ menor_ do que a compilação atual.-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -168363092.
O CommonJS ainda resultaria em uma compilação maior com uma base de código que não tem dependências cíclicas?
@cecilemuller Sim - consulte https://github.com/nolanlawson/rollup-comparison. Com os módulos CommonJS, você paga um custo por módulo (cada módulo precisa ser envolvido em uma função e precisa redeclarar as importações que são compartilhadas em todo o pacote, então você é penalizado por uma base de código mais modular), um custo por pacote (ele precisa simular um ambiente Node.js) e outros custos, como nomes de propriedade de objeto não minimizáveis que seriam nomes de variáveis minimizáveis em módulos ES6. Os módulos ES6 permitem que você se agrupe com literalmente zero overhead.
Embora houvesse alguma sobrecarga na transpilação para es5. Atualmente,
Eu uso o webpack com o babel que adiciona muito pouco. Existe um custo por módulo
pois também está envolvido na função s. Dependências são declaradas no final
código chamando uma função tipo require com um índice inteiro, de modo que obtém
reduzido para algo como "var a = f (5)" do que era originalmente 'importação
Geometria de "./geometria"; '
Usar geradores também adiciona um pouco mais, mas não imagino a estrutura de
o código mudaria tanto em breve.
Em 2 de janeiro de 2016, 5:53 AM, "Rich Harris" notifications@github.com escreveu:
@cecilemuller https://github.com/cecilemuller Sim - veja
https://github.com/nolanlawson/rollup-comparison. Com módulos CommonJS
você paga um custo por módulo (cada módulo precisa ser empacotado em uma função,
e precisa declarar novamente as importações que são compartilhadas por todo o pacote, para
você é penalizado por uma base de código mais modular), um custo por pacote (ele precisa
para simular um ambiente Node.js), e outros custos, como não minimizável
nomes de propriedades de objetos que seriam nomes de variáveis minimizáveis em ES6
módulos. Os módulos ES6 permitem que você se agrupe com literalmente zero overhead.-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -168394376.
Embora haja alguma sobrecarga na transpilação para es5
Se você estiver usando apenas a sintaxe import
e export
para descrever a relação entre os módulos, não há necessidade de transpilar o próprio código com Babel ou qualquer coisa semelhante. É apenas quando você começa a adicionar outros recursos ES6 (como classes e escopo de bloco e funções de seta etc.) que a transpilação se torna necessária, então não há sobrecarga para usar import
e export
. D3 e PouchDB são dois exemplos de bibliotecas que usam import
e export
mas são ES5 sem Babel, e three-jsnext é feito da mesma maneira.
Ok, todos nós tivemos a mesma ideia. Seria ótimo ter uma história como a lodash.
Proponho criar um pacote _três-foo_ para cada componente _foo_ (por exemplo, três-vetor2) que pode ser modularizado, quase sem alteração no código, para que possa ser importado neste repo sem impacto.
Pessoas que publicam no npm devem jogar bem e colaborar com @mrdoob, já que ele é o criador deste ótimo software, então se ele quiser centralizar novamente todos os pacotes como o autor _babel_ (quero dizer, todos os pacotes principais na mesma pasta), o editor deve dar a ele o controle sobre o namespace npm obtido.
Vou tentar fazer isso, para os pacotes de que preciso. Vamos ver o que acontece.
Existe apenas uma grande comunidade :)
Não notei ninguém sugerindo separar totalmente a biblioteca como
Lodash. Lodash é uma coleção de utilitários com um nome comum; seu táxi
pegue um único pedaço dele e use-o. Threejs não é; é um abrangente
biblioteca, a maioria das quais é inútil sem o resto. Existem algumas peças
que podem ser separados, como os tipos de materiais específicos ou
geradores de geometria, mas eles necessariamente serão muito próximos
amarrado ao núcleo, provavelmente precisando de correspondências exatas de versão. Considerando seu
tamanho, criaria uma dor de cabeça de manutenção sem ganho mensurável.
Se o Sr. Doob aprovasse uma divisão dessa natureza, no entanto, eu não acho
apropriado para qualquer um, exceto um mantenedor oficial, reivindicar três js- *
pacotes.
Independentemente do acima, acho prudente fazê-lo funcionar de forma modular
ambiente antes de mais nada. Houve vários projetos com este
objetivo, mas todos parecem ter fracassado.
Em 6 de março de 2016, 11h39, "Gianluca Casati" notifications@github.com escreveu:
Ok, todos nós tivemos a mesma ideia. Seria ótimo ter uma história como
Lodash.Proponho criar um pacote _três-foo_ para cada componente _foo_ (para
instância de três vetores2) que pode ser modularizada, com quase nenhuma mudança em
o código, para que possa ser importado neste repositório sem impacto.Pessoas que publicam no npm devem jogar bem e colaborar com @mrdoob
https://github.com/mrdoob já que ele é o criador desta grande peça
de software, então se ele quiser centralizar novamente todos os pacotes como em
_babel_, o editor deve fornecer a ele o controle sobre o namespace npm obtido.Vou tentar fazer isso, para os pacotes de que preciso. Vamos ver o que acontece.
Existe apenas uma grande comunidade :)
-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -192970867.
@mattdesl : por exemplo, seu three-shader-fxaa usa THREE.Vector2 e THREE.Texture, além do composer de três efeitos que não verifiquei, resultaria em uma construção bem leve usando a abordagem de modularidade proposta acima.
@HMUDesign : Eu entendo suas dúvidas, mas ainda me parece uma boa abordagem. Eu quero tentar, mas vou ouvir seus conselhos, usando pacotes npm de URLs do GitHub, não publicando-os no registro sagrado.
Eu tentei, iniciando o formulário TrackballControls que depende do Vector2, Vector3, Quaternion e assim por diante.
Existem dependências circulares (por exemplo, Matrix4 depende de Vector3 e vice-versa). Isso não pode ser feito se o lib (ou seja, threejs) foi iniciado monolítico.
É uma pena que o padrão de módulo com todos os seus benefícios não possa ser aplicado facilmente em projetos importantes como este.
Tento também com outros projetos como svg.js, vvvvjs, até mesmo x3dom, mas se os autores não estão totalmente convencidos dessa escolha radical, isso não pode ser feito.
Desculpe pelo spam, mas eu queria tentar proativamente: a propósito, comecei com o repo de três trackballcontrols .
O padrão do módulo
Tenho certeza de que você viu isso: https://github.com/kamicane/three-commonjsify Ele resolveu em commonJS.
@drcmda realmente interessante, vou tentar
1 para mudar para uma arquitetura modular.
+1
+1
@drcmda está certo. Os módulos ES6 têm uma etapa de inicialização e uma etapa de execução que permite referências circulares. No entanto, assim que você tiver dependências circulares diretamente do contexto de execução do módulo (na área global de um módulo), o primeiro carregado durante o tempo de execução terá valores indefinidos para suas dependências. Contanto que as referências sejam usadas em contextos diferentes em que a ordem de execução do tempo de execução é importante, as dependências circulares não são problema.
Eu sugiro considerar também webpack em vez de browserify.
@gionkunz nós temos referências circulares na etapa de inicialização bc do padrão onde há um fechamento para gerar variáveis de rascunho
A versão beta do Webpack 2 acaba de ser lançada (https://twitter.com/TheLarkInn/status/747955723003322368/photo/1), então os módulos es6 também podem se beneficiar do tremor da árvore quando agrupados.
@mrdoob
Houve uma declaração oficial mais recentemente? Como muitos, abandonamos o ES5 e os concats de cola há muito tempo e é muito ruim o quanto o THREE sai da linha em um sistema de compilação moderno. Usamos talvez 10% do que ele pode fazer, mas é a maior dependência que enviamos.
Este é talvez _o_ projeto mais favorito no Github para mim pessoalmente - espero sinceramente que as prioridades sejam reconsideradas.
Hmm, gostaria de saber mais detalhes sobre o suporte do navegador. Quais navegadores fazem e quais não. Para os navegadores que não o fazem, quais são as soluções alternativas e quais são as penalidades de desempenho.
Na verdade, o suporte ao navegador não é mais um problema (talvez até menos do que agora). Os sistemas de construção pegam esse código ES6 e o transpilam para o es5 (às vezes ocupando menos espaço do que o ES5 original teria). Certos tipos de coisas transpiladas acabam sendo grandes (principalmente: geradores e funções assíncronas), mas se você os evitar, não terá essa penalidade.
Como @drcmda mencionou, o sistema de construção ainda produziria uma saída monolítica (e seria muito fácil personalizar exatamente o que está incluído nessa saída), mas os módulos individuais também podem ser incluídos em nossos próprios projetos, usando apenas as partes que nós precisamos. Para tirar o máximo proveito de
que, as interdependências precisam ser ajustadas, mas isso pode acontecer com o tempo. Acho que a principal característica que queremos é que ele seja modularizado com importação / exportação. Do seu ponto de vista, isso permitiria o uso de classes em vez de protótipos (eles ainda usam protótipos nos bastidores, então você ainda pode
mexa com ele conforme necessário).
Existem alguns sistemas de construção. Meu voto seria webpack (que usa babel para transpilar). Com o babel, você pode definir carregadores personalizados, de forma que o sistema de chunking desenvolvido para shaders pudesse ser reduzido ao código glsl real com uma extensão #include (na verdade eu faço meus shaders dessa forma e ficaria feliz em contribuir com o projeto). Isso obtém os mesmos benefícios do seu sistema (sem duplicação de código), mas é muito simples de usar.
Eu adoraria fazer parte do projeto de modularização, mas sei que isso não terá sucesso de forma alguma sem o seu apoio (e provavelmente assistência). Muitos de nós sabemos como usar a biblioteca, mas nenhum de nós sabe como ela funciona internamente como você.
Certos tipos de coisas transpiladas acabam sendo grandes (principalmente: geradores e funções assíncronas), mas se você os evitar, não terá essa penalidade.
Quão largo?
Além disso, você não falou sobre penalidade de desempenho. Isso não é um problema, então?
Pelo que eu posso ver, as importações ES6 ainda não são suportadas por nenhum navegador , então este módulo de refatoração seria principalmente para sistemas de construção, certo?
Não se esqueça dos benefícios que você obtém ao usar ferramentas como rollupjs, isso excluiria automaticamente todas as exportações que um usuário não usa. (Que é o padrão com JSPM)
O pacote babel-polyfil, que só é necessário se você estiver usando
geradores (que provavelmente nem fazem sentido neste projeto) ou assíncronos
funções (que eu realmente não acho que mudaria muito no projeto
ou), adiciona cerca de 50k à construção final. Mas, novamente, isso é opcional.
No que diz respeito ao desempenho, realmente depende exatamente de quais recursos você é
usando. Por exemplo, as funções das setas são um pouco mais lentas, devido ao
vinculação subjacente, as classes são um pouco mais lentas para criar, embora o
o tempo de instanciação é o mesmo. https://kpdecker.github.io/six-speed/
Importações / exportações ES6 não são suportadas por navegadores, mas desde que vai
por meio de um sistema de construção, isso não é um problema. A saída do produto seria
utilizável exatamente como é atualmente (mesmo sendo compatível com versões anteriores), mas
permitiria que ele fosse integrado em nossos sistemas de construção, e tornaria o
componentes internos reutilizáveis para nós.
Outra coisa a ser observada é o tamanho final da construção. Atualmente, coisas como geometria,
Material, Malha, etc, fazem parte do namespace TRÊS. Quando minimizado,
referências a TRÊS. Geometria, TRÊS. Material, TRÊS. Malha etc. permanecem no
código. Com um sistema modular, cada um desses arquivos teria algo como
var Geometry = require('./geometry');
então tenha referências ao
variável Geometry
mais tarde. Então, na minifaciton, Geometry
e require
são ambos trocados para caracteres únicos, o './geometria' é substituído por um
número, resultando em uma boa economia. Matemática do guardanapo: o reduzido
build tem 511,794 bytes e contém 2942 referências a
THREE\.[A-Z][a-zA-Z]+
. Substituindo tudo isso por um único caractere
resulta em uma redução de tamanho de arquivo de quase 10% (até 464.782). (O gziped
os tamanhos são 117.278 e 110.460 respectivamente, uma redução de 6%). A construção
provavelmente poderia ser ajustado para reduzir isso ainda mais.
Rollup (que eliminou o código não utilizado de uma compilação final) é o padrão
com jspm, será o padrão com webpack2 (e eu acredito que pode ser usado
com webpack). Se as coisas forem escritas de maneira modular, não acho que isso será
útil, no entanto. Em qualquer caso, desde que o código possa ser transpilado com
babel, pode ser usado em qualquer sistema de compilação (o carregador glsl que mencionei
antes também pode ser feito para funcionar com webpack).
Na quinta-feira, 7 de julho de 2016 às 13h28, Mr.doob notifications@github.com escreveu:
Certos tipos de coisas transpiladas acabam sendo grandes (principalmente:
geradores e funções assíncronas), mas se você os evitar, não terá
essa penalidade.Quão largo?
-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -231197171,
ou silenciar o tópico
https://github.com/notifications/unsubscribe/AA71cqAqmgxsUjpvamnI_xyL2wpzeWrdks5qTWGBgaJpZM4B4aA7
.
Não tenho certeza se isso é terrivelmente útil, mas este é o tópico de discussão para D3 sobre o mesmo problema: https://github.com/d3/d3/issues/2220. O D3 4.0 adotou a importação / exportação ES6 para gerenciar módulos, mas ainda é escrito em ES5 (https://github.com/d3/d3/issues/2220#issuecomment-111655235).
Muito interessante @jpweeks!
Então ... com esta abordagem de importação / exportação ... Como seriam coisas como object instanceof THREE.Mesh
?
@mrdoob
import/export
é apenas a forma como os módulos são declarados e obrigatórios. Isso não afetará / alterará o código definido nos módulos:
src / Objects / Mesh.js
// Mesh class, stays the same as today (except the export part)
var Mesh = function ( geometry, material ) {
// ...
}
export default Mesh
src / Three.js
// Library entry point, exports all files using som bundling tech
// In a "THREE" namespace for browsers
// As import three from 'three' in node
import Mesh from './objects/Mesh'
export {Mesh} // All three objects, such as Geometry, Material etc..
Application.js
// In node
import {Mesh} from 'three'
var mesh = new Mesh(geo, mat)
console.log(mesh instanceof Mesh) // true
Client.js
// In a browser
var mesh = new THREE.Mesh(geo, mat)
console.log(mesh instanceof THREE.Mesh) // true
Isso é muito útil @GGAlanSmithee! Obrigado!
Sou uma pessoa visual, então exemplos de pseudocódigos me convencem mais do que grandes pedaços de texto 😅
Certo, então vai exigir um pouco de refatoração ...
Alguém sabe se o compilador de encerramento está planejando oferecer suporte a isso?
Certo, então vai exigir um pouco de refatoração ...
Te peguei! Desde que este tópico ficou animado nos últimos dias, tenho trabalhado um pouco mais no three-jsnext . É um projeto que pega a base de código Three.js existente e a transforma em módulos ES automaticamente. Apenas brigando com algumas dependências cíclicas complicadas (particularmente em torno de KeyframeTrack
), mas deve haver algo para compartilhar em breve. Até onde eu posso dizer, todos os exemplos continuam funcionando, e a compilação minimizada é menor que a atual (usando Rollup para gerar um arquivo UMD), então é uma boa notícia.
Ok, abri uma solicitação pull para isso: # 9310
@mrdoob
Temos uma biblioteca em produção que está mais ou menos estruturada como TRÊS. Funciona em navegadores e ambientes modulares. A base de código é ES6, mas os navegadores não são sua preocupação.
Você enviaria isso em npm _as is_, todos os módulos incluídos + um monólito de navegador de namespace global compilado (three.js). Quem precisa usar partes únicas usa ferramentas para criar bundles.
Considere uma estrutura como esta:
/src
classA.js
classB.js
classC.js
/index.js
/browser.js
index.js simplesmente reexporta todos os módulos e funções em um arquivo:
export ClassA from './src/classA';
export ClassB from './src/classB';
export ClassC from './src/classC';
Assim, o usuário final pode instalar o lib por npm e apenas usá-lo sem mais delongas:
// all exports from index.js will be under: mylib.ClassA, etc.
import * as mylib from 'libname':
// selected exports from index.js
import { ClassA, ClassC } from 'libname';
// or, specific modules
import ClassB from 'libname/src/classB'
browser.js seria a única parte compilada do pacote. Normalmente transpilado para ES5 via Babel e exportado para um namespace global para que possa ser usado como um script include. Rollup, Webpack, etc. podem criar isso com facilidade.
@mrdoob, foi um passeio maravilhoso 🚀
Comentários muito úteis
Te peguei! Desde que este tópico ficou animado nos últimos dias, tenho trabalhado um pouco mais no three-jsnext . É um projeto que pega a base de código Three.js existente e a transforma em módulos ES automaticamente. Apenas brigando com algumas dependências cíclicas complicadas (particularmente em torno de
KeyframeTrack
), mas deve haver algo para compartilhar em breve. Até onde eu posso dizer, todos os exemplos continuam funcionando, e a compilação minimizada é menor que a atual (usando Rollup para gerar um arquivo UMD), então é uma boa notícia.