Browserify
Pasar a esta arquitectura tiene ventajas y desventajas. Por favor agregue sus pensamientos.
Nota: esto no requiere que los consumidores de three.js usen browserify.
Una ventaja es que esto impondría una arquitectura modular para el desarrollo continuo de three.js.
El estilo común en node / browserify hace que cada archivo declare sus dependencias en la parte superior y considere las variables globales como un anti-patrón.
Aquí hay un fragmento de ejemplo:
// src/geometry/BoxGeometry.js
var Geometry = require('./Geometry.js');
var Vector3 = require('../core/Vector3.js');
module.exports = BoxGeometry;
function BoxGeometry() {
// ...
}
BoxGeometry.prototype = Geometry.prototype;
Otra ventaja es que los consumidores de three.js
usen browserify podrían elegir las partes que deseen. Podrían simplemente importar Scene
, BoxGeometry
, PerspectiveCamera
y WebGLRenderer
, obtener las dependencias para todos esos automáticamente ( Object3D
etc.), y tener un pequeño paquete de javascript que admita solo el conjunto de funciones que desean.
Esto podría hacerse de una manera que no imponga cambios importantes. En el nivel superior, exportaríamos todas las clases que consideramos parte del paquete estándar
// src/three.js
var THREE = { rev: 101 }
module.exports = THREE
THREE.Geometry = require('./geometry/Geometry.js')
THREE.BoxGeometry = require('./geometry/BoxGeometry.js')
// ...
nota: No estoy requiriendo exactamente las dependencias en la parte superior en este ejemplo, porque este archivo sería casi exclusivamente declaraciones de requerimiento.
Finalmente, envolveríamos eso en una Definición de módulo universal que detecta si un sistema de módulo (nodo / browserify, AMD) está en uso y, si es así, lo exporta o lo agrega al objeto global ( window
).
Revisemos:
three.js
utilizan browserify elegir la funcionalidadEsto requeriría reemplazar el sistema de compilación, pero el nuevo sería bastante sencillo.
Algunas otras ventajas:
@ shi-314 Supongo que estoy un poco confundido, siento que You can structure your code
y You can build for production
son cosas que puedes hacer sin el cambio arquitectónico. ¿Estás hablando de la fuente de three.js o de cosas creadas con three.js?
Una práctica que usa three.js y que dificulta su uso en entornos commonjs es el uso de instanceof
: https://github.com/mrdoob/three.js/blob/master/src/core/Geometry .js # L82
Esto se debe a que en una aplicación a menudo termina con diferentes versiones de la misma biblioteca en su árbol de fuentes, por lo que la verificación de instanceof no funciona entre diferentes versiones de la misma biblioteca. Sería bueno en preparación para un cambio a un sistema de módulos commonjs para reemplazar esas instancias de comprobaciones con verificación de características detrás de una interfaz de estilo Geometry.isGeometry(geom)
.
@kumavis Estoy hablando de cosas integradas en three.js. Digamos que quieres crear tu propio material con tus shaders, etc. En este momento necesitas extender el objeto THREE global para mantener la coherencia con el resto del código three.js:
THREE.MeshMyCoolMaterial = function (...) { ... }
Pero si tuviéramos Browserify de lo que podría hacer:
var MeshLambertMaterial = require('./../MeshLambertMaterial');
var MeshMyCoolMaterial = function (...) {...}
Por lo tanto, su espacio de nombres se mantiene constante y no necesita usar THREE.MeshLambertMaterial
y MeshMyCoolMaterial
en su código.
Y con You can build for production
básicamente quise decir lo mismo que mencionaste: allows three.js consumers using browserify to pick and choose functionality
.
@ shi-314 gracias, eso está más claro. Eso afecta mi solución general propuesta para la deserialización de clases definidas por el consumidor:
// given that `data` is a hash of a serialized object
var ObjectClass = THREE[ data.type ]
new ObjectClass.fromJSON( data )
Esto es de mi refactor de serialización / deserialización propuesto
https://github.com/mrdoob/three.js/pull/4621
El rendimiento no debería verse afectado por un cambio como este.
Este es un cambio bastante grande, pero también estoy a favor de él.
Algunas otras ventajas importantes:
standalone
browserify para generar una compilación UMD para usted. No es necesario manipular manualmente las envolturas UMD.threejs-vecmath
sin preocuparnos por la rotura del código de todos. Y por otro lado, si hacemos un parche o una versión menor en un módulo en particular, las personas que consuman esos módulos podrán obtener los cambios automáticamente.npm install threejs-shader-bloom
)require()
los módulos que nuestra aplicación está usando realmente.Para @mrdoob y los demás autores; Si no tiene mucha experiencia con NPM / Browserify, sugeriría hacer un par de pequeños proyectos con él y familiarizarse con su "filosofía". Es muy diferente a la arquitectura ThreeJS; en lugar de grandes marcos, fomenta muchas cosas pequeñas .
Otra ventaja de este enfoque es que puede haber un ecosistema de código abierto, módulos Three.JS de terceros, especialmente sombreadores, geometrías, cargadores de modelos, etc. Publicado a través de NPM o Github / Component que la gente puede fácilmente referenciar y usar. Por el momento, las cosas se comparten al albergar una demostración en la que las personas luego 'ven la fuente'. Three.JS se merece algo mejor!
Creo que uno de los problemas que tengo con Three.JS es la rapidez con la que el código se vuelve incompatible con la versión actual de Three.JS. Otra ventaja de cambiar a algo como esto es poder especificar versiones específicas de _bits_ de Three.JS sería muy poderoso y práctico.
+1
+1 para una arquitectura CommonJS / browserify, haría que el núcleo sea más liviano y las extensiones encajarían incluso si provienen de terceros
Fragmentar three.js en pequeños módulos también tiene muchos costos. El sistema actual permite complementos de terceros bastante simples (por ejemplo, los módulos THREEx de jetienne). Hay mucho que decir sobre la simplicidad de la configuración actual, siempre que los sistemas del módulo JS sean simplemente envoltorios de los sistemas de compilación.
Otra forma de minimizar el tamaño de compilación es lo que hace ClojureScript. Siguen algunas convenciones para permitir que el compilador Closure de Google realice análisis de todo el programa y elimine el código muerto.
+1 para la elegancia de la simplicidad poco apreciada y a menudo pasada por alto
+1
Fragmentar three.js en pequeños módulos también tiene muchos costos. El sistema actual permite complementos de terceros bastante simples (por ejemplo, los módulos THREEx de jetienne).
La idea aquí es que se seguiría proporcionando una compilación UMD para entornos que no sean de nodo. Los complementos como THREEx funcionarían de la misma manera para aquellos que dependen de ThreeJS con etiquetas simples <script>
.
Lo complicado será: ¿cómo require()
un complemento en particular si estamos en un entorno CommonJS? Quizás browserify-shim podría ayudar.
Hay mucho que decir sobre la simplicidad de la configuración actual, siempre que los sistemas del módulo JS sean simplemente envoltorios de los sistemas de compilación.
El actual sistema de extensiones / complementos de ThreeJS es bastante horrible para trabajar, y está lejos de ser "simple" o fácil. La mayoría de los proyectos de ThreeJS tienden a usar algún tipo de complemento o extensión, como EffectComposer o FirstPersonControls, o un cargador de modelos, o uno de los otros muchos archivos JS que flotan en la carpeta examples
. Ahora mismo, la única forma de depender de estos complementos:
vendor
Ahora, imagina, con browserify podrías hacer algo como esto:
var FirstPersonControls = require('threejs-controls').FirstPersonControls;
//more granular, only requiring necessary files
var FirstPersonControls = require('threejs-controls/lib/FirstPersonControls');
Esos complementos serán require('threejs')
y cualquier otra cosa que puedan necesitar (como fragmentos de GLSL o triangulación de texto ). La administración de dependencias / versiones está oculta para el usuario, y no hay necesidad de tareas de concat de gruñido / trago mantenidas manualmente.
Lo complicado será: ¿cómo necesitamos () un complemento en particular si estamos en un entorno CommonJS?
He estado usando CommonJS para proyectos THREE.js por un tiempo. Es un proceso un poco manual, convertir fragmentos de código de otras personas en módulos y no creo que haya una manera fácil de evitarlo para el código heredado que no es convertido por los autores o contribuyentes.
Lo importante es que hay un módulo que exporta todo el objeto TRES 'estándar', que luego puede ser requerido por cualquier persona que desee extenderlo.
var THREE = require('three');
THREE.EffectComposer = // ... etc, remembering to include copyright notices :)
Esto me ha funcionado bastante bien, especialmente a medida que el proyecto crece y comienzo a agregar mis propios sombreadores y geometrías en sus propios módulos, etc.
Siempre que haya un paquete npm 'threejs-full' o 'threejs-classic', esta se convierte en una forma bastante viable de trabajar con cosas antiguas de Three.js en un entorno CommonJS, ¡pero sospecho que es un nicho bastante!
+1
Creo que una vez que los módulos threejs fragmentados están disponibles en npm, plugin
A los desarrolladores les encantará migrar a CommonJS env.
El 5 de junio de 2014 a las 21:19, "Charlotte Gore" [email protected] escribió:
Lo complicado será: ¿cómo necesitamos () un complemento en particular si
están en un entorno CommonJS?He estado usando CommonJS para proyectos THREE.js por un tiempo. Es un poco
de un proceso manual, convirtiendo fragmentos del código de otras personas en módulos
y no creo que haya una manera fácil de evitarlo para el código heredado
que no ha sido convertido por los autores o colaboradores.Lo importante es que hay un módulo que exporta todo el 'estándar'
TRES objeto, que luego puede ser requerido por cualquier cosa que desee extender
eso.var TRES = require ('tres');
THREE.EffectComposer = // ... etc, recordando incluir avisos de derechos de autor :)Esto me ha funcionado bastante bien, especialmente a medida que el proyecto crece y yo
comenzar a agregar mis propios sombreadores y geometrías en sus propios módulos, etc.Siempre que haya un paquete npm 'threejs-full' o 'threejs-classic', entonces
esto se convierte en una forma bastante viable de trabajar con cosas antiguas de Three.js en una
Entorno CommonJS, ¡pero sospecho que este es un nicho bastante!-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -45236911.
También podría hacer que los sombreadores se hicieran modulares, por ejemplo, usando glslify . Incluso cosas como crear un middleware Express que genere sombreadores a pedido se vuelven más fáciles en ese momento.
Hace algunos meses moví frame.js a
Sin embargo, todavía necesito aprender a "compilar" esto. ¿Cuál es la herramienta / flujo de trabajo para generar three.min.js
partir de una lista de módulos?
Prefiero gulp.js como sistema de compilación con el complemento gulp-browserify . Es realmente fácil de entender y el código se ve más limpio que gruñido en mi opinión. Mira esto: http://travismaynard.com/writing/no-need-to-grunt-take-a-gulp-of-fresh-air : wink:
algunos pensamientos: (basado en mi experiencia limitada con node, npm, browserify, por supuesto)
Dicho esto, después de la discusión en este hilo, no estoy seguro de si todos tenían el mismo conocimiento de browserify (browserify, commonjs, requirejs, amd, umd están algo relacionados, aunque es posible que no necesariamente sean lo mismo).
ahora si puedes seguir un poco mi cadena de pensamientos.
Ahí es donde entra en escena Browserify. Bueno, técnicamente se puede usar requireJS en el navegador. Pero desea agrupar archivos js sin realizar demasiadas llamadas de red (a diferencia de los requisitos del sistema de archivos que son rápidos). Ahí es donde Browserify hace algunas cosas interesantes como análisis estático para ver qué módulos deben importarse y crea compilaciones que están más optimizadas para su aplicación. (Hay limitaciones, por supuesto, probablemente no puede analizar el requerimiento ('bla' + variable)) incluso puede intercambiar partes que requieren una capa de emulación para cosas dependientes de node.js. sí, genera una compilación js que ahora puedo incluir en mi navegador.
Estas son algunas de las cosas que puede hacer browserify https://github.com/substack/node-browserify#usage
Parece que todo va muy bien hasta ahora ... pero hay algunos puntos que pensé que valía la pena considerar. Pasamos a una "arquitectura de navegación".
Entonces, si vemos esta diversidad y la conveniente carga de módulos (principalmente en el ecosistema npm) junto con compilaciones personalizadas, algo bueno, entonces podría valer la pena hacer un cambio de paradigma, refactorizar el código y cambiar nuestro sistema de compilación actual.
@mrdoob, algunas herramientas relacionadas con browserify se enumeran aquí: https://github.com/substack/node-browserify/wiki/browserify-tools.
con respecto a three.min.js
, no usaría el código minificado en su proyecto. todo lo que haces es var three = require('three')
en tu project.js
y luego ejecutar browserify project.js > bundle.js && uglifyjs bundle.js > bundle.min.js
. nota: aún puede enviar código minificado por <script src="min.js">
.
Actualmente estoy envolviendo three.js con
if ('undefined' === typeof(window))
var window = global && global.window ? global.window : this
var self = window
y
module.exports = THREE
luego envuelvo extensiones con
module.exports = function(THREE) { /* extension-code here */ }
entonces puedo requerirlo así:
var three = require('./wrapped-three.js')
require('./three-extension')(three)
así que esto no es óptimo, pero personalmente puedo vivir con eso y pensar que no es tan malo, aunque la propuesta de @kumavis sería una gran ventaja.
pero tal vez tenga sentido bifurcar tres y poner todas las cosas en módulos separados solo para ver cómo funciona.
también consulte http://modules.gl/, que se basa en gran medida en browserify (aunque puede usar cada módulo por sí solo sin browserify).
@mrdoob @ shi-314 gulp-browserify ha sido incluido en la lista negra a favor de usar browserify directamente (es decir, a través de vinyl-source-stream).
Herramientas como grunt / gulp / etc.están en constante cambio, y encontrará muchas opiniones diferentes. Al final, no importa cuál elijas o si lo haces con un script personalizado. Las preguntas más importantes son: ¿cómo consumirán los usuarios ThreeJS y cuánta compatibilidad con versiones anteriores desea mantener?
Después de pensarlo un poco más, creo que será _realmente_ difícil modularizar todo sin refactorizar por completo el marco y su arquitectura. A continuación se presentan algunos problemas:
../../../math/Vector2
etc.three-scene
se desacoplaría de three-lights
etc. Luego, puede versionar cada paquete por separado. Este tipo de fragmentación parece poco realista para un marco tan grande como ThreeJS, y sería un dolor de cabeza mantenerlo.require('three/src/math/Vector2')
¿Mi sugerencia? Consideramos dos cosas en el futuro:
Me encantaría ver todo modularizado, pero no estoy seguro de un enfoque realista para ThreeJS. Tal vez alguien debería hacer algunos experimentos en una bifurcación para ver qué tan factibles son las cosas.
¡Gracias por las explicaciones chicos!
Lo que temo es complicar las cosas a las personas que recién comienzan. Obligarlos a aprender estas cosas de browserify / modules puede no ser una buena idea ...
Tendría que estar de acuerdo con @mrdoob aquí. Yo, y muchos de mis colegas, no somos programadores web (más bien, TD de VFX / animación). Obtener WebGL y Three ciertamente ha sido suficiente trabajo, ya que además de nuestra carga de trabajo actual (y en algunos casos, algunos de nosotros tuvimos que aprender js en el acto). Mucho de lo que he leído en este hilo, a veces, me hace estremecer al pensar en cuánto trabajo más se agregaría a mi plato si Tres se mudara a esta estructura. Podría estar equivocado, pero eso es ciertamente lo que me dice.
Con una compilación de UMD precompilada ( browserify --umd
) en el repositorio, no hay cambios en el flujo de trabajo para los desarrolladores existentes.
@mrdoob La idea de un sistema de gestión de dependencias es la simplicidad. Leer docenas de publicaciones sobre opciones y sistemas de construcción puede ser abrumador, pero en última instancia, el sistema actual no es sostenible. Cada vez que un archivo depende de otro, es una búsqueda y una búsqueda que cualquier desarrollador nuevo debe realizar para encontrar una referencia. Con browserify, la dependencia es explícita y hay una ruta al archivo.
@repsac Un sistema de dependencia debería hacer que Three sea más accesible para los usuarios de otros lenguajes, ya que evita el alcance global, carga pesadillas en el orden y sigue un paradigma similar a otros lenguajes populares. var foo = require('./foo');
es (loosly) similar a C # 's using foo;
o de Java import foo;
Me encantaría ver todo modularizado, pero no estoy seguro de un enfoque realista para ThreeJS. Tal vez alguien debería hacer algunos experimentos en una bifurcación para ver qué tan factibles son las cosas.
Creo que este es el camino a seguir, de verdad. Haga el trabajo, muestre cómo funciona.
Y consumir la API sería bastante
ugly: require('three/src/math/Vector2')
Como experimento, acabo de convertir el "inicio" de los Tres documentos a este nuevo enfoque modular. Me imagino que habrá muchas referencias a menos que la gente sea bastante estricta a la hora de dividir su código en pequeños módulos.
La principal ventaja de hacer esto sería que el tamaño de compilación resultante sería una pequeña fracción del tamaño de Three.js completo porque solo incluiría las cosas a las que se hace referencia específicamente aquí y luego las cosas de las que esas cosas dependen.
Supongo que hacer referencia a todas las dependencias que necesita (e instalarlas todas individualmente) podría resultar un poco terrible en la práctica.
Si está apuntando explícitamente a dispositivos móviles, entonces este enfoque altamente granular sería perfecto, pero en realidad sospecho que necesitaremos paquetes que exporten las TRES api completas que funcionarán normalmente, luego paquetes más pequeños que encapsulen toda la geometría adicional, todos los renderizadores, todas las matemáticas, todos los materiales, etc., luego hasta el nivel de módulo individual para que los desarrolladores puedan decidir por sí mismos.
Y sí, codificar para la web es un fastidio.
De todos modos, adelante con el experimento ...
Instala nuestras dependencias ...
npm install three-scene three-perspective-camera three-webgl-renderer three-cube-geometry three-mesh-basic-material three-mesh three-raf
Escribe nuestro 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();
luego construye nuestro archivo
browserify entry.js -o scripts/hello-world.js
luego inclúyelo en nuestra página
<script src="/scripts/hello-world.js" type="text/javascript"></script>
Supongo que hacer referencia a todas las dependencias que necesita (e instalarlas todas individualmente) podría resultar un poco terrible en la práctica.
El usuario final no necesita necesariamente usar browserify en su proyecto para que Three use browserify para administrar su base de código. Se pueden exponer tres como el THREE
global tal como está ahora ... incluir el archivo de compilación y ejecutarlo.
@repsac @mrdoob los cambios serían compatibles con versiones anteriores, por lo que los usuarios actuales no necesitan cambiar nada si no quieren. Estas sugerencias son para mejorar la capacidad de mantenimiento a largo plazo y la longevidad del extenso y monolítico código base de ThreeJS. Cosas como la dependencia y la administración de versiones pueden parecer un dolor de cabeza para los no iniciados, pero son increíbles para quienes desarrollan herramientas, marcos, complementos y sitios web a gran escala sobre ThreeJS.
es decir, el código de usuario final aún puede verse igual, y el examples
no necesita cambiar en absoluto:
<script src="three.min.js"></script>
<script>
var renderer = new THREE.WebGLRenderer();
</script>
Para los desarrolladores más ambiciosos que buscan una compilación modular, _o_ para aquellos que buscan desarrollar soluciones a largo plazo además de ThreeJS (es decir, y aprovechar la gestión de versiones / dependencias), podría parecerse más a esto:
npm install three-vecmath --save
Luego, en código:
var Vector2 = require('three-vecmath').Vector2;
//.. do something with Vector2
Y, además, esto permite a las personas usar cosas como las matemáticas vectoriales de ThreeJS, las conversiones de color, la triangulación, etc. fuera del alcance de ThreeJS.
Aunque creo que el desastre require () es una mala idea y una mala compensación, sería una idea aún peor exponer a los usuarios a dos tipos diferentes de código three.js, diciéndoles a los usuarios que uno es el tipo de sistema de módulo elegante y otro es el Tipo de sistema de módulo más simple (pero de segunda clase).
@erno Creo que te has perdido el punto, three.js
estaría organizado por una estructura de módulo internamente, pero eso se usa para producir un archivo de compilación no diferente de la configuración actual.
La principal ventaja es mejorar la experiencia de desarrollar y mantener three.js
.
@kumavis - no @erno en realidad no se perdió eso, pero entendí (*) que él señala que si three.js
veces se usa a través de require y otras no, puede ser confuso. Por ejemplo, alguien mira las tres fuentes y luego algunos ejemplos de terceros y encuentra diferencias en cómo es y funciona todo.
(*) hablamos de esto en el irc hoy.
Creo que ese es un tipo de punto válido, pero no estoy seguro de si o cómo funciona al final, si realmente es un problema con los usos del módulo y la construcción. Pero ciertamente parece que vale la pena pensarlo y, en general, me ha parecido bien que el asunto general se haya considerado aquí cuidadosamente, gracias por la información y las opiniones hasta ahora de mi parte.
@antont ya veo. La gente ha sugerido una variedad de enfoques diferentes aquí, asumí que proporcionaríamos principalmente documentación para el uso de nivel superior (sacando todo de THREE
), pero otros pueden crear ejemplos que no seguirían esto y es posible que dar lugar a cierta confusión. Y esa es una preocupación válida.
Creo que estaba un poco confundido por el idioma.
y otro es el tipo de sistema de módulos más simple (pero de segunda clase).
Esto solo se refiere al archivo de compilación, ¿no?
A mi entender, sí. No puedo imaginar qué más, pero puede faltar algo.
antont, kumavis: Las propuestas aquí han hablado de exponer el código de estilo require () a los usuarios finales también, ver eg. comentario más reciente de mattdesl.
"Para desarrolladores más ambiciosos que buscan una compilación modular, o para aquellos que buscan desarrollar soluciones a largo plazo sobre ThreeJS (es decir, y aprovechar la gestión de versiones / dependencias) [...]"
una forma de tener compilaciones más optimizadas es en realidad tener un script que descubra sus dependencias automáticamente y produzca los módulos requeridos.
en este momento, Bower & Browserify cumple con los requisitos, pero no son las únicas soluciones. No sé si hay otros proyectos de código abierto listos para usar que hagan eso (tal vez como dependencias ng) pero he escrito tales herramientas antes y creo que habría otros enfoques para resolver estos problemas.
¿El compilador de cierre de Google podría ser una herramienta de este tipo?
Por parte del usuario, ¿esto podría ser de alguna ayuda?
http://marcinwieprzkowicz.github.io/three.js-builder/
eso es bastante interesante @erichlof :) @marcinwieprzkowicz generó esto a mano ... https://github.com/marcinwieprzkowicz/three.js-builder/blob/gh-pages/threejs-src/r66/modules.json
Una práctica que usa three.js y que dificulta su uso en entornos commonjs es el uso de instanceof: https://github.com/mrdoob/three.js/blob/master/src/core/Geometry.js#L82
Esto se debe a que en una aplicación a menudo termina con diferentes versiones de la misma biblioteca en su árbol de fuentes, por lo que la verificación de instanceof no funciona entre diferentes versiones de la misma biblioteca. Sería bueno en preparación para un cambio a un sistema de módulos commonjs para reemplazar esas instancias de comprobaciones con verificación de características detrás de una interfaz de estilo Geometry.isGeometry (geom).
en git / three.js / src:
grep -r instanceof . | wc -l
164
en git / three.js / examples:
grep -r instanceof . | wc -l
216
por lo que hay un total de 380 usos de instanceof
en three.js. ¿Cuál sería la mejor implementación como reemplazo?
Recientemente agregué una propiedad type
que se puede usar para reemplazar la mayoría de ellas.
Recientemente agregué una propiedad de tipo que se puede usar para reemplazar la mayoría de ellos.
¡bonito! Preparará un PR.
Para ver un ejemplo de cómo se maneja esto en otra biblioteca JS grande y popular, eche un vistazo a https://github.com/facebook/react . El código base está estructurado usando el sistema de módulos basado en estilo de nodo (que explora los implementos) pero está construido para su lanzamiento usando grunt. Esta solución es flexible para 3 casos de uso.
require
dependencias específicas. Los beneficios de una gestión adecuada de la dependencia están bien documentados.Investigué un poco ...
Ayer pirateé un script (bastante estúpido) que transforma el código fuente Three.js para usar declaraciones CommonJS require()
para declarar dependencias entre archivos. Solo para ver qué pasa ... Esto:
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');
Necesitaríamos una refactorización importante, tal vez dividiendo WebGLRenderer (y demás) en varios módulos (atm, el archivo tiene más de 6000 líneas).
THREE.ShaderChunk
en tiempo de compilación y luego en THREE.ShaderLib
en tiempo de ejecución (uniéndose a matrices de THREE.ShaderChunk
s), lo cual es bastante complicado de hacer solo con browserify. Supongo que requeriría una transformación de browserify que haga lo mismo.React.js usa commoner para buscar sus módulos sin tener que referirse a ellos por la ruta del archivo. Quizás podríamos hacer lo mismo y también definir reglas personalizadas que nos permitan require
GLSL transformándolos a la sintaxis JS.
@rasteiner, es posible que esté muy feliz de conocer https://github.com/stackgl/glslify , proviene de la creciente familia http://stack.gl
He tenido un poco de experiencia con módulos y el enfoque "unixy" en los últimos meses y mi pensamiento ahora es que es muy poco y demasiado tarde, y refactorizar threejs para modularidad o módulos npm sería un objetivo poco realista.
Esto es lo que estoy haciendo actualmente para abordar el problema de la modularidad / reutilización:
Mis nuevos proyectos tienden a usar "tres" en npm solo para comenzar a funcionar. Sería bastante impresionante si ThreeJS publicara oficialmente la compilación en npm usando etiquetas de versión que se alinean con los números de lanzamiento.
PD: para aquellos interesados en incorporar sombreadores modulares / reutilizables a su flujo de trabajo:
https://gist.github.com/mattdesl/b04c90306ee0d2a412ab
Enviado desde mi iPhone
El 20 de noviembre de 2014, a las 7:42 a.m., aaron [email protected] escribió:
@rasteiner, es posible que esté muy feliz de conocer https://github.com/stackgl/glslify , proviene de la creciente familia http://stack.gl
-
Responda a este correo electrónico directamente o véalo en GitHub.
En caso de que ayude a otros que podrían estar buscando cómo usar Three.js con browserify y tropiecen con este hilo, la forma en que lo acabo de configurar es usar browserify-shim .
Siguiendo la sección README sobre _ "A veces a) Expondrás variables globales a través de global" _, incluí una etiqueta de script separada para Three.js y la configuré para exponer la variable THREE global.
Y luego lo único que tuve que resolver fue cómo incluir extras como ColladaLoader, OrbitControls, etc. Hice esto así:
Desde 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" }
};
Luego, en mi propio 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);
...
Browserify requiere reconstruir todo el script cuando modifica incluso en bytes. Una vez utilizo browserify para empaquetar un proyecto que requiere THREE.js, luego toma más de dos segundos construir un límite y bloquea la recarga en vivo cada vez que hago un cambio. Eso es muy frustrante.
Normalmente usas watchify durante el desarrollo con livereload. Ese construye el paquete de forma incremental.
watchify no funciona para mí. Cuando cambio un archivo y lo guardo, watchify y la recarga en vivo de beefy muestran la versión anterior / en caché. No tengo idea de por qué sucede esto. Afortunadamente, browserify ya funciona bastante bien.
@ChiChou Pass en --noparse=three
para navegar. Esto lleva el paso del paquete browserify de 1000ms a 500ms en mi máquina, lo cual es lo suficientemente decente para una sensación de retroalimentación instantánea.
@rasteiner Quiero agradecerle nuevamente por su investigación informal sobre las interdependencias de three.js. Si bien esa lista masiva de departamentos es un código de aspecto feo, en realidad esa fealdad está presente tal como está, simplemente invisible. La fortaleza de Browserify es que nos obliga a ventilar nuestra ropa sucia y buscar sistemas menos enredados.
Hay muchos lugares en Three.js donde tomamos algún objeto, percibimos su tipo y realizamos diferentes tareas basadas en ese tipo. En la mayoría de esos casos, ese código dependiente del tipo podría trasladarse al tipo en sí, y no tendríamos que comprender todos los tipos posibles con los que estamos operando.
El siguiente es un ejemplo abreviado de WebGLRenderer :
if ( texture instanceof THREE.DataTexture ) {
// ...
} else if ( texture instanceof THREE.CompressedTexture ) {
// ...
} else { // regular Texture (image, video, canvas)
// ...
}
debería ser más de la forma
texture.processTexImage( _gl, mipmaps, otherData )
Deje que el tipo determine cómo manejarse. Esto también permite al consumidor de bibliotecas utilizar nuevos tipos de texturas en los que no habíamos pensado. Esta estructura debería reducir la interdependencia.
Creo que pasar a una arquitectura Browify es definitivamente el camino a seguir. La compilación de UMD facilitará el consumo de THREE.js. También nos permitirá dividir WebGLRenderer en varios archivos, porque en este momento parece bastante monolítico y aterrador.
Comencé una rama en la que actualmente estoy trabajando para moverla aquí: https://github.com/coballast/three.js/tree/browserify-build-system
Por favor dejame saber lo que tu piensas.
Aquí están los cambios de @coballast .
Parece que está adoptando el enfoque de conversión automática con su archivo browserifyify.js
, que creo que es el camino correcto.
Una cosa que todavía no hemos discutido mucho es cuál es la mejor manera de hacer la transición de esta biblioteca grande y en constante cambio a la navegación. Puede realizar los cambios y luego abrir un PR, pero quedará obsoleto de inmediato. Eso es lo convincente del enfoque automatizado.
Si podemos:
browserifyify.js
)... entonces podemos convertir esto en una conversión de botón que aún funcionará en el futuro previsible. esa simplicidad permite que esta noción de ensueño de un cambio arquitectónico fundamental a un proyecto tan grande se lleve a cabo cuando los argumentos ideológicos triunfan.
@coballast con ese fin, eliminaría los cambios en src / Three.js si funciona de la misma manera.
Nota: no solo revertir, sino eliminar esos cambios del historial de la rama a través de una nueva rama o un empuje forzado
@coballast Me pregunto si tendría más sentido que la utilidad de conversión no sea una bifurcación de three.js
, sino una utilidad externa que apunta al directorio de desarrollo three.js
, y convierte la fuente archivos, agrega un script de compilación y ejecuta las pruebas.
@kumavis Estoy de acuerdo con dejar solo el directorio src. Creo que lo que hay que hacer es hacer que la utilidad escriba un directorio duplicado con el código commonjs, y podemos probar y ejecutar la compilación de browserify desde allí para asegurarnos de que todos los ejemplos funcionen antes de intentar hacer algo importante.
También hay una oportunidad interesante aquí para escribir algunas cosas de análisis estático que verifiquen y apliquen automáticamente un estilo consistente en todo el código base.
@coballast suena genial.
Existe una gran cantidad de herramientas para la reescritura automática de código, por ejemplo, escodegen . Necesitamos asegurarnos de que mantenemos comentarios, etc.
¿Quiere iniciar un repositorio de utilidad de conversión de threejs?
@coballast dicho esto, mantener un enfoque nítido para esta utilidad es importante
@kumavis Considérelo hecho. Realmente quiero que esto suceda. Este es solo uno de los dos proyectos en los que estoy trabajando en este momento.
@kumavis @mrdoob Parte de la discusión aquí parece girar en torno a la idea de dividir TRES en múltiples módulos separados que presumiblemente podrían instalarse a través de npm y luego compilarse con browserify. No estoy totalmente en contra de la idea, pero creo que debería ser un tema aparte. Lo único que estoy defendiendo en este momento es usar browserify para administrar la base de código de THREE internamente. Haga que se mueva y que funcione de la misma manera que siempre lo ha hecho para los usuarios, y luego evalúe lo que tiene sentido.
Tendré curiosidad por ver cuál es la salida de esa utilidad ^^
@coballast enlaza un repositorio para que podamos rastrearlo, incluso si está vacío en este momento. Podemos construir a partir de ahí.
https://github.com/coballast/threejs-browserify-conversion-utility
El código es un desastre, se limpiará pronto.
¡Aquí vamos! :cohete:
Ahora tengo la utilidad en un estado en el que genera browserify src y la construiré sin problemas. Actualizaré el repositorio con instrucciones sobre cómo hacerlo usted mismo. En este punto, los ejemplos no funcionan. Hay varios problemas que deben resolverse para solucionarlo. Los agregaré al repositorio si alguien quiere arremangarse y ayudar.
@coballast sí, por favor presente los problemas como TODOs, y yo u otros participaremos como podamos.
Han surgido problemas graves. Ver # 6241
Aquí está mi análisis de lo que debería suceder para que esto funcione: https://github.com/coballast/threejs-browserify-conversion-utility/issues/9#issuecomment -83147463
browserify es, como mínimo, un transporte redundante (conjuntivo) debido a su diseño. Esto hace que su costo de uso sea inflable (¿plan de datos alguien?) Y lento.
Un remedio simple para esto es separar el documento del código de la biblioteca, lo que implicaría dos archivos de cliente y no uno. Esta es una práctica común para los js del lado del cliente.
Si al principio browserify es defectuoso y necesita ser reparado, difícilmente puedo ver por qué debería considerarse para mejorar algo y mucho menos algo como threejs.
@spaesani Porque los datos de threejs deben descargarse de todos modos. Si dividimos threejs en módulos más pequeños y dejamos que un sistema de compilación automatizado elija lo que necesita para una sola aplicación, en realidad la mayoría de las aplicaciones de threejs serían más ligeras.
Si por alguna razón aún desea separar el "documento del código de la biblioteca", aún puede hacer esto y usar una versión prediseñada como lo hacemos ahora. Incluso puede dividir su aplicación integrada en browserify en módulos separados usando los indicadores --standalone y --exclude .
Browserify es solo una forma de usar una API de definición de módulo probada en batalla (CommonJS) en el navegador. Simplificaría enormemente el desarrollo de complementos de threejs y mejoraría la claridad del código y, por lo tanto, la productividad, nos permitiría integrarnos en un ecosistema más grande (npm) donde el código es inherentemente mantenido por más personas mientras se mantiene la integridad a través del sistema de control de versiones (piense en la familia stackgl ), y ni siquiera obligaría a las personas a ingresar a CommonJS si no lo quieren.
Por supuesto que hay desventajas, pero no son las que mencionaste.
three.js y three.min.js se pueden almacenar en caché para ahorrar en el transporte (datos) mediante un proxy, la solución móvil común o un navegador de almacenamiento en caché.
En el momento en que selecciona y agrega el código threejs con el código específico del documento, el almacenamiento en caché no es factible.
Si browserify le permite a uno
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) mejora las cosas para los humanos. Mi propia felicidad psicológica y mi bienestar son más importantes que la facilidad con la que una máquina puede cargar y ejecutar cosas.
Muchos problemas de carga de la red móvil se mejorarán un poco con cosas como http / 2. Problemas como ese se resuelven mejor modificando las capas que están más abajo en la pila de abstracción. Los problemas de rendimiento no deberían impedirnos seguir las mejores prácticas de ingeniería de software como modularidad / separación de preocupaciones, etc.
Encontré este problema porque mi equipo comenzó a usar jspm recientemente. Podemos importar threejs (creo que esto se debe a que el archivo principal se ha explorado). Estaba buscando para ver si alguien había convertido threejs en módulos es6, principalmente debido a la función de compilación de jspm (agrupando todas las dependencias en un solo archivo, pero solo tomando las dependencias que se usan).
Si bien es genial que mrdoob mantenga el tamaño de threejs por debajo de 100kb, encuentro que la mayoría de mis proyectos no usan gran parte del código base (siento que es la mayoría, pero no he intentado averiguarlo). CubeCamera, OrthographicCamera, CanvasRenderer, varias luces, cargadores, curvas, geometrías, ayudantes, etc. Además, encuentro que la mayoría de mis proyectos incluyen algunos de los scripts de ejemplo.
Mi esperanza era que sería posible tener una sola ubicación de todos estos módulos (los que normalmente se incluyen con threejs y los de los ejemplos), y simplemente importar los que necesito, luego, cuando agrupe el proyecto, resulta en un archivo mucho más pequeño que el threejs original, aunque contiene muchas partes que no estaban incluidas originalmente.
También quería agregar que si threejs se construyeran usando módulos browserify, agregaría una pequeña sobrecarga del tamaño del archivo (pero incomparable con los 403kb actuales en r70), pero también eliminaría el uso de la variable global THREE del código, por lo tanto permitiendo que variables como THREE.Geometry se minimicen por cierre.
Hice una prueba rápida haciendo una búsqueda-reemplazo para deshacerme del objeto TRES (por lo que todos sus hijos contaminaron el espacio de nombres) y envolví todo el archivo en un IIFE, luego ejecuté todo hasta el cierre de Google. El archivo resultante (sin gzip) era de 238 kb, frente a 777 kb.
Si bien los resultados variarán, creo que definitivamente vale la pena asegurarse de que esto suceda.
gracias por contar - muchos puntos buenos y familiares para nosotros también. Tampoco usamos muchos renderizadores en un proyecto, pero hacemos cosas de lib a partir de ejemplos.
No me di cuenta de eso acerca de la minificación, esa es una gran diferencia.
y los módulos es6 ciertamente parecían prometedores; también ha sido bueno escuchar que hay una ruta allí desde el patrón de módulo AMD / CommonJS / tal y el uso de lib también.
@colin No estoy seguro de seguirte sobre cómo se navega
ayuda a su felicidad psicológica.
¿Está en la documentación?
browserify es una vaca de efectivo del transportista ...
Martes 31 de marzo de 2015, 10:11 p. M. -04: 00 de Colin Ballast Notifications@github.com :
@spaesani It (browserify) mejora las cosas para los humanos. Mi propia felicidad psicológica y mi bienestar son más importantes que la facilidad con la que una máquina puede cargar y ejecutar cosas.
Muchos problemas de carga de la red móvil se mejorarán un poco con cosas como http / 2. Problemas como ese se resuelven mejor modificando las capas que están más abajo en la pila de abstracción. Los problemas de rendimiento no deberían impedirnos seguir las mejores prácticas de ingeniería de software como modularidad / separación de preocupaciones, etc.
-
Responda a este correo electrónico directamente o véalo en GitHub.
Ahora, si browserify determinara automáticamente las dependencias sin una declaración require ... oye, espera ...
@spaesani En realidad prefiero las dependencias explícitas; te ayuda a comprender cómo encaja todo el código.
browserify es una vaca de efectivo del transportista ...
La sobrecarga de
Actualización de estado:
Tengo una rama con un código explorado arriba:
https://github.com/coballast/three.js/tree/browserify
Tenga en cuenta que esto es un trabajo en progreso. Este código se generó automáticamente y, como resultado, se verá bastante mal por un tiempo. Todavía estoy tratando de solucionar algunos problemas de compilación. Consulte coballast / threejs-browserify-conversion-utility # 10 si cree que puede solucionarlo. Estuvo construyendo por un tiempo, pero ahora no lo está.
@kumavis y yo hemos estado trabajando para abordar algunos problemas de tiempo de ejecución (y también para mejorar la arquitectura del software). Creo que lo mencioné arriba en alguna parte.
Perdón por la larga respuesta. TLDR: jspm / es6 se ejecuta, pero tiene algunas rarezas: 1) Exportar objetos antes de definirlos; 2) Exportar objetos que contienen una sola clase, en lugar de simplemente exportar una sola clase; 3) IIFE usando dependencias circulares; 4) Estructura de archivos.
Jugué con su rama explorada en jspm ( @spinchristopher arriba soy yo) y tengo algunas notas, aunque en primer lugar: ¿No sería bueno abrir problemas en esa bifurcación, para que este hilo no esté lleno de ellos y no lo están? revueltos juntos?
Aunque se ejecuta, en realidad no genera el resultado correcto. (usando la demostración simple al comenzar). Crea el lienzo y lo rellena de negro (a menos que establezca el color claro en transparente), pero en realidad no está renderizando el cubo. Sin embargo, no espero que funcione en este momento, ya que todavía es muy temprano en el proceso.
Me encontré con 3 problemas principales:
Uno. Este fue el más molesto, y honestamente no estoy seguro de cómo se puede compilar algo con este error en particular, ya que no debería funcionar en absoluto. Muchos de los archivos comienzan así (esto está bien porque las definiciones de funciones se elevan al tiempo y se ejecutan esencialmente antes de la línea module.exports, aunque aparece primero):
module.exports.Foo = Foo;
function Foo() {}
El problema viene en los muchos archivos que son así (el primero que vi fue math / Math.js). La inicialización del objeto se eleva (por lo que no hay un error indefinido) pero la definición permanece en su lugar (por lo que la exportación no está definida).
module.exports.Foo = Foo;
var Foo = {};
La única solución que encontré aquí es mover la línea de exportaciones al final, o reescribirla así (preferido):
var Foo = module.exports.Foo = {};
Dos. Los datos exportados. Cuando se trata de archivos modularizados, el estándar es que cada archivo exporta un solo objeto. Si bien la mayoría de los archivos son de esta manera (aunque algunos exportan más), no exportan el constructor único, exportan un objeto que contiene ese constructor (es decir: module.exports.Foo = Foo;
lugar de module.exports = Foo;
. Este último es la forma en que funcionan todos los ejemplos de browserify). Por lo tanto, cuando use los requisitos, debe avanzar un nivel más profundo ( var Vector3 = require('../math/Vector3').Vector3;
). Además de ser innecesario, no hay forma de hacer esto al importar a es6. ( import Vector3 from '../math/Vector3'; var vector = new Vector3.Vector3();
). Si bien es posible obtener una exportación en particular en es6, se aplica cuando se usan módulos explorados y aún tendría la misma redundancia ( import { Vector3 } from '../math/Vector3';
). Hay algunos archivos que simplemente recopilan otros objetos (el obvio es Three.js), pero estos deben mantenerse al mínimo, y realmente solo deben usarse para el proceso de compilación, no como una forma de capturar muchas cosas en producción .
Tres. Esto tiene que ver con las dependencias circulares. System.js (el cargador de módulos utilizado por jspm) puede manejar las dependencias circulares sin problemas, pero hay un problema. En muchos lugares, el código dice algo como lo siguiente. El problema es que, aunque Vector3 se ha pasado como una dependencia, en este momento no se ha cargado completamente (como Vector3 también incluye este archivo, cada uno no se puede resolver hasta que el otro se haya resuelto) y no se puede crear. Agregué una solución muy mala (que se muestra a continuación), aunque no estoy seguro de cómo se solucionaría mejor. Parece que este es un problema arquitectónico que puede no tener una solución simple. Sucede muchas, muchas veces. Parece ser una optimización para evitar la creación de un nuevo Vector3 cada vez que se llama a la función. Si de hecho hay un impacto significativo en el rendimiento que no se puede solucionar optimizando Vector3, ¿quizás agregar una función a Vector3 para devolver un vector3 no utilizado que se publicará más tarde?
Foo.prototype.bar = function() {
var vector = new Vector3();
return function() {
// some data which reuses vector repeatedly.
};
}();
La solución:
Foo.prototype.bar = function() {
var vector;
return function() {
if(!vector) vector = new Vector3();
// some data which reuses vector repeatedly.
};
}();
Finalmente, quería agregar un poco sobre la organización de archivos. Obviamente, esto es algo que debe abordarse después de que el conjunto actual se compile correctamente, pero quería mencionarlo ahora. Si bien la estructura de archivos actual funciona, algunas partes son bastante extrañas o incluso incómodas. Las agrupaciones principales (cámaras, materiales, geometrías, etc.) parecen tenerlo bien, aunque haría algunos cambios, como se ve a continuación. También movería los globales en ThreeGlobals cada uno a aquello para lo que son globales. IE: FrontSide, BackSide, DoubleSide pertenecen todos con Material (junto con NoShading, FlatShading y SmoothShading. En realidad, parece que la mayoría de ellos lo hacen ...).
Mis principales confusiones vinieron con el núcleo y los extras. core / Geometry.js debe estar en la carpeta de geometrías, al igual que Material está en la carpeta de materiales. Pero no hay una carpeta de geometrías, está en extras. Por cierto, los extras también tienen un núcleo y unas geometrías, pero la geometría base no está en esta carpeta. Existe esta gran colección de ayudantes, pero ¿no debería cada ayudante estar con lo que está ayudando? Los procesos de compilación se pueden configurar fácilmente para que solo tomen los archivos que desee, por lo que no hay excusa para colocar los archivos no importantes en otro lugar.
Actualmente tengo una línea en mi código que lee import BoxGeometry from 'threejs/extras/geometries/BoxGeometry';
y var geometry = new BoxGeometry.BoxGeometry( 1, 1, 1 );
Estar acostumbrado a usar `new THREE.BoxGeometry ()` `me tomó bastante tiempo encontrar el archivo. Cuando se usa de forma modular, la ubicación del archivo es tan importante como algo como las firmas de funciones.
Cambios generales que haría en la estructura de archivos. Estos se aplican en muchos lugares, pero solo estoy mostrando un ejemplo. (Como nota, siempre he preferido un modelo de nombrar el archivo después de la clase única que exporta y colocar el archivo en una carpeta con el mismo nombre. Cualquier descendiente directo generalmente iría en esa carpeta, pero nuevamente, en una carpeta con el mismo nombre que ellos. Sin embargo, si a uno no le gusta este patrón, se aplica la misma estructura a continuación, simplemente eliminando ese nivel adicional. Además, cualquier cargador de archivos se puede modificar fácilmente [los ganchos generalmente se proporcionan directamente, de hecho] para automatizar las capas y simplificar las declaraciones de requisitos].) (También prefiero todos los archivos en minúsculas, con guiones bajos cuando sea necesario).
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
También es probable que cambie el nombre de matemáticas a utilidades (cada categoría también puede tener una utilidad, como la geometría anterior) para que pueda contener más que solo matemáticas (muchas de las cosas del núcleo).
@HMUDesign @spinchristopher ¡ gracias por el gran análisis! Es mejor poner este tipo de problemas en el repositorio coballast / threejs-browserify-conversion-utility en el futuro.
ok déjame leer correctamente tu comentario ahora.
De alguna manera me perdí el enlace a ese repositorio anterior. Felizmente moveré mis asuntos
a ese repositorio mañana, dividiéndolo según sea necesario (me di cuenta de que al menos
algo de eso ya está ahí)
El 9 de abril de 2015 a las 12:09 a. M., "Kumavis" Notifications@github.com escribió:
@HMUDesign https://github.com/HMUDesign @spinchristopher
https://github.com/spinchristopher ¡ gracias por el gran análisis! Mejor
para poner este tipo de problemas en el
coballast / threejs-browserify-conversion-utility repo en el futuro.ok déjame leer correctamente tu comentario ahora.
-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -91132413.
Sí, y lo hago para mis propias bibliotecas de tipo util (* Los archivos util son los
la única vez que no tengo una exportación predeterminada, aunque a veces agregaré una
experto además de la predeterminada), sin embargo, esta sintaxis solo funciona cuando
exportar múltiples variables con nombre. El cargador de módulos js comunes trata
modules.exports como exportación predeterminada, que no se puede desestructurar en el
importar = (
El 9 de abril de 2015 a las 12:12 a. M., "Kumavis" Notifications@github.com escribió:
en es6 puede importar propiedades de los objetos de exportación a través de
desestructuración.importar {Vector3} desde '../math/Vector3';
Dicho esto, estoy de acuerdo en que se prefiere una exportación por módulo.
-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -91132982.
@HMUDesign, gracias de nuevo por su energía y análisis. Aquí estamos construyendo una lista de https://github.com/coballast/threejs-browserify-conversion-utility/issues/17
+1 para browserify.
También +1 para mover sombreadores a archivos separados usando glslify.
También +1 por adoptar algunas características de ES6, como clases y módulos. La nueva pila de compilación nos permitirá volver a compilar a ES5 si es necesario. Ver ejemplo:
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 Ya que estamos en eso, podemos usar los módulos es6 y usar babeljs para compilar todo.
@coballast Me interesaría ramificar tu rama browserify
y hacer que algunas de estas cosas sucedan
@lmcd No me molestaría. Voy a desarrollar herramientas automatizadas para mover las cosas de es5 a es6 automáticamente. Tiene sentido, ya que existe una gran cantidad de código es5, y el requisito de trabajo para moverlo a mano es astronómico.
@coballast Estaba pensando más en ejecutar un pase 5to6
: https://github.com/thomasloh/5to6
@lmcd oo buen hallazgo
pero tbh, parece que sería más fácil reescribir three.js desde cero: P
@lmcd Estoy tan feliz de que hayas encontrado eso. Era una de esas cosas que iba a hacer por pura necesidad, pero sonaba claramente no divertido.
@mrdoob ¿cuál es su opinión actual sobre este tema?
@anvaka En este momento estoy enfocado en refactorizar WebGLRenderer
. No tengo más ancho de banda mental 😅
Recientemente encontré un proyecto que estaba usando módulos es6 felizmente con el polyfill de babel que también se mencionó aquí. No podía recordar ni encontrar todavía lo que era, de todos modos me parecía bien.
También es6 parece estar terminado ahora en el frente de los estándares: "Finalmente, ECMA-262 Edición 6 fue oficialmente aprobado y publicado como estándar el 17 de junio de 2015", dice https://developer.mozilla.org/en-US/docs / Web / JavaScript / Nuevo_en_JavaScript / ECMAScript_6_support_in_Mozilla
Solo una nota que con respecto a las herramientas y la estabilidad de la especificación del módulo, la situación parece buena en ese frente.
Recientemente encontré un proyecto que estaba usando módulos es6 felizmente con el polyfill de babel que también se mencionó aquí. No podía recordar ni encontrar todavía lo que era, de todos modos me parecía bien.
También tiene 47kb de js adicionales y lee y transpila su javascript incluido a es5 en el navegador, por lo que no es ideal para el inicio.
No hay nada que impida que cualquiera que use three.js use es6 en su propio código; sin embargo, usarlo en la biblioteca introduciría problemas de rendimiento y compatibilidad del navegador en todos los ámbitos.
Ah - de pie corregido aquí, gracias por la información. Supongo que browserify y los que funcionan en el proceso de compilación son mejores ahora todavía.
Ah - de pie corregido aquí, gracias por la información. Supongo que browserify y los que funcionan en el proceso de compilación son mejores ahora todavía.
Uno de los principales problemas con es6 es que tiene importantes cambios de sintaxis con es5; por ejemplo, la flecha gruesa => no es válida es5 y hará que el analizador de JavaScript falle y deje de intentar compilar el código. Es de esperar que a alguien se le ocurra una forma de evitar esto, pero aún no lo ha hecho.
De hecho, estaba pensando solo en el sistema de módulos, la declaración de importación, etc.
También tiene 47kb de js adicionales y lee y transpila su javascript incluido a es5 en el navegador, por lo que no es ideal para el inicio.
por ejemplo, la flecha gorda => no es válida es5 y hará que el analizador de JavaScript falle y se resista al intentar compilar el código
El código es6 se puede transpilar a es5 durante _build_ sin penalización de tiempo de ejecución. Es solo cuestión de agregar un paso de babel a la canalización de compilación.
Por ejemplo, la función de flecha se puede transpilar a es5 durante la compilación sin polyfill o penalización por tiempo de ejecución. Babel transpilará este fragmento de es6
function MyObj() {
this.step = 1;
this.increment = function ( arr ) {
return arr.map( v => v + this.step );
}
}
en esta versión portátil:
function MyObj() {
this.step = 1;
this.increment = function (arr) {
var _this = this;
return arr.map(function (v) {
return v + _this.step;
});
};
}
Otra característica, como las clases es6, generará un pequeño polyfill (se puede ver en la réplica de babel http://babeljs.io/repl/).
@mrdoob entendió. ¿Apoyaría la idea de dividir three.js en módulos más pequeños alojados en el npm?
El repositorio principal de three.js permanecerá sin cambios: los consumidores no tendrán que construir nada. Los usuarios más experimentados podrían seleccionar los bits necesarios de three.js.
Eso suena bien. Aunque no conozco los detalles.
El código es6 se puede transpilar a es5 durante la compilación sin penalización de tiempo de ejecución. Es solo cuestión de agregar un paso de babel a la canalización de compilación.
Por ejemplo, la función de flecha se puede transpilar a es5 durante la compilación sin polyfill o penalización por tiempo de ejecución. Babel transpilará este fragmento de es6
La transpilación de ES6 todavía viene con una penalización de tiempo de ejecución significativa: http://www.incaseofstairs.com/2015/06/es6-feature-performance/ especialmente para una biblioteca de alto rendimiento.
módulos / npm / browserfy, etc., sin embargo, probablemente sea una buena idea
+1 en modularización adecuada usando módulos ES6
+1 en la modularización adecuada utilizando cualquier sistema de módulos sano (commonjs, amd, es6)
Creo que commonjs y amd son las opciones preferidas porque no necesitan transpilar
Sin embargo, necesitan un paso de construcción, que es equivalente al
paso de transpile.
El uso de ES6, además de ser la próxima versión del lenguaje, permitiría
utilizar las siguientes funciones como desee, pero sin romper el código nativo existente.
¿Es realmente prudente reaccionar la base del código en un sistema que ya está
no es el ultimo?
El 20 de julio de 2015 a las 12:05 p.m., "kumavis" Notifications@github.com escribió:
+1 en la modularización adecuada utilizando cualquier sistema de módulos sensato (commonjs, amd,
es6)
Creo que commonjs y amd son las opciones preferidas porque no
necesita transpilar-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -122990605.
Sin embargo, necesitan un paso de construcción, que es equivalente al
paso de transpile.
la construcción y el traspaso no son equivalentes en términos de la complejidad que introducen.
¿Es realmente prudente reaccionar la base del código en un sistema que ya está
no es el ultimo?
commonjs es simple y funciona muy bien. No estoy convencido de la idea de que 'último' === 'mejor'.
El uso de ES6 [...] permitiría el uso de las siguientes funciones según se desee
por lo que vale la pena considerarlo. ¿queremos funciones de es6? si comenzamos a transpilar es6, la gente comenzará a hacer relaciones públicas. como sugirió @benaadams, hay impactos de rendimiento no intuitivos en el uso de las funciones de es6.
Además, no necesitamos combinar los problemas de 'sistema de módulos' y 'características de es6'. puede transpilar es6 y usar commonjs. y puede introducirlos por separado.
+1 para browserify / commonjs: es sencillo compilar con browserify de tal manera que las personas aún pueden usar la biblioteca de la manera tradicional si lo desean: para esto es UMD, permitir que AMD requiera (como require.js), CommonJS requiere (como node + browserify) y una ventana global (para etiquetas de script) dependiendo del entorno en el que nos estamos ejecutando.
PIXI.js acaba de pasar a una arquitectura modular usando browserify y la biblioteca se configuró de una manera muy similar: todo lo que está adjunto a un objeto PIXI global. Su configuración es muy similar a la que describe @kumavis en la segunda publicación.
Ni browserify ni commonjs abordan las necesidades específicas de un motor 3D, lo que no significa que no se puedan usar, pero deben verse como una pieza de un rompecabezas mayor:
Los componentes necesitan exportar metainformación sobre las propiedades de sus instancias, por lo que puede haber un cargador para objetos arbitrarios y conexiones de datos de memoria compartida. Con tal arquitectura, sería solo una cuestión de sentido común cargar también código de componente fuera del núcleo en el primer uso. He estado haciendo una lluvia de ideas sobre estos temas en # 6464 y # 6557.
+1
+1
Como solución híbrida, también es posible agregar los requisitos como comentarios. Sé que browserfy ya está en muchos ecosistemas, pero solo quería dejar esto aquí como una variante rápida de implementar :) porque no tendrías que cambiar nada. Solo necesita agregar un comentario encima de cada archivo.
Como desarrollador, puede crear fácilmente sus propios archivos min.js con el complemento de información y gulp @requires
.
Hola a todos, recientemente tuve una necesidad similar de cargar recursos arbitrarios con sus propias dependencias de una manera limpia y estructurada y se me ocurrió la solución de escribir complementos require.js para cada tipo de recurso. De esta manera, dejo que la resolución de dependencias de require.js se encargue de descargar y almacenar en caché correctamente los recursos ... Al mismo tiempo, este enfoque crea 'paquetes' de recursos reutilizables que puedo usar en varios de mis proyectos.
Si está interesado, puede encontrar el proyecto aquí: https://github.com/wavesoft/three-bundles
(Un ejemplo de uso de esta biblioteca estará disponible pronto)
En el futuro, planeo incluir una fase de optimización en estos complementos para permitir que el optimizador require.js compile los recursos en un formato aún más compacto.
Mirando esta conversación https://twitter.com/defunctzombie/status/682279526454329344 , no parece que los módulos es6 se vayan a implementar en un futuro próximo. Algo para tener en cuenta.
Hice algunos prototipos con módulos commonjs y browserify.
Mi paquete final de navegador incluye todos los archivos de la carpeta src
y da como resultado el tamaño de archivo 962K
(en comparación con la versión original sin navegador 885K
).
El ejemplo de compilación dirigida de
580K
(~ 44% más pequeño)431K
(~ 8% más pequeño)Aquí está el desglose del tamaño del paquete: http://output.jsbin.com/yogoxawozu. Los renderizadores toman el 40% del paquete y el 10% de eso lo toma la biblioteca de sombreadores.
Creo que podríamos reducir el tamaño del paquete de la siguiente manera:
instance of
: requieren módulos de referencia explícita incluso cuando no se utilizan. Veo que algunas de las clases ya tienen type
; podríamos usar esto en toda la biblioteca.glslify
se trajo un par de veces, y definitivamente podría ayudar. Idealmente, cada componente que requiere sombreadores debe depender explícitamente de un sombreador.Puede verificar los resultados y verificar el 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
no parece que los módulos es6 se vayan a implementar en un futuro próximo. Algo para tener en cuenta.
Eso es cierto, pero también es importante darse cuenta de que el soporte del módulo CommonJS _nunca_ se implementará en los navegadores, por lo que la elección es entre
Las bibliotecas como D3 están adoptando módulos ES6 porque ya pueden hacer todo lo que los módulos CommonJS pueden hacer (excepto ejecutarse de forma nativa en Node.js, que no es realmente una preocupación para una biblioteca como Three.js) y dan como resultado compilaciones más pequeñas.
He hecho algunos experimentos en https://github.com/rollup/three-jsnext , y aunque no está listo para producción (¡necesito pasar un poco más de tiempo portando ejemplos, etc.!), La compilación UMD que genera es en realidad _más pequeña_ que la construcción actual.
Estoy de acuerdo con la nota sobre los módulos es6 frente a otros sistemas. Si o
no son un estándar es, son un estándar comunitario. Y aunque ellos
no se puede ejecutar "de forma nativa" en el nodo, puede parecer nativo con los ganchos de Babel.
Estaré haciendo un seguimiento con su repositorio pronto.
Además, el hecho de que sea más pequeño es algo que mencioné antes en
esta conversacion. "TRES.Geometría" se convierte en "geometría" que puede ser
minificado a "a" por ejemplo.
Además, la solución a la instancia de los cheques es eliminarlos todos
juntos. Un módulo no debe suplicarse de manera diferente dependiendo de qué
fue dado, sino más bien difiriendo a lo provisto para hacer lo que necesita
hacer. Entonces no hay verificaciones de tipo o instancia.
El 1 de enero de 2016 a las 8:23 p.m., "Rich Harris" Notifications@github.com escribió:
no parece que los módulos es6 se vayan a implementar cerca
futuro. Algo para tener en cuenta.Eso es cierto, pero también es importante darse cuenta de que el módulo CommonJS
El soporte _nunca_ se implementará en los navegadores, por lo que la elección es entre
- Continuando con una arquitectura no modular y una construcción ad hoc
sistema, que ha servido bien a Three.js hasta ahora, pero actúa como un freno al crecimiento
a la larga- utilizando módulos CommonJS, que implica algunos trucos en torno a cíclicos
dependencias y da como resultado una compilación más grande, o- utilizando módulos ES6, que se adaptan bien a una base de código como Three.js
que tiene dependencias cíclicas, y que resultan en la más pequeña y más
posible construcción minifiable. Eventualmente, los navegadores los admitirán de forma nativa,
y los cambios necesarios para adaptarse a cualquier peculiaridad imprevista en el cargador
lo más probable es que la especificación sea trivial en comparación con el esfuerzo involucrado en
actualizar desde una base de código CommonJS.Bibliotecas como D3 están adoptando módulos ES6 porque ya pueden hacer
todo lo que pueden hacer los módulos CommonJS (excepto ejecutarse de forma nativa en Node.js, que
no es realmente una preocupación para una biblioteca como Three.js), y resulta en una
construye.He hecho algunos experimentos en
https://github.com/rollup/three-jsnext , y mientras no es producción
listo (necesito pasar un poco más de tiempo portando ejemplos, etc.) la compilación UMD
que genera es en realidad _más pequeño_ que la construcción actual.-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -168363092.
¿CommonJS aún resultaría en una compilación más grande con una base de código que no tiene dependencias cíclicas?
@cecilemuller Sí, consulte https://github.com/nolanlawson/rollup-comparison. Con los módulos CommonJS, paga un costo por módulo (cada módulo debe incluirse en una función y debe volver a declarar las importaciones que se comparten en todo el paquete, por lo que se le penaliza por una base de código más modular), un costo por paquete (necesita simular un entorno Node.js) y otros costos, como nombres de propiedades de objetos no minificables que serían nombres de variables minificables en los módulos ES6. Los módulos ES6 le permiten combinar con literalmente cero gastos generales.
Aunque habría algunos gastos generales al transpilar luego a es5. En el presente,
Yo uso webpack con babel que agrega muy poco. Hay un costo por módulo
ya que también está envuelto en la función s. Las dependencias se declaran en la final
código llamando a una función require like con un índice entero, por lo que obtiene
reducido a algo como "var a = f (5)" de lo que originalmente era 'import
Geometría de "./geometry"; '
El uso de generadores también agrega un poco más, pero no imagino la estructura de
el código cambiaría tanto en el corto plazo.
El 2 de enero de 2016 a las 5:53 a. M., "Rich Harris" Notifications@github.com escribió:
@cecilemuller https://github.com/cecilemuller Sí - ver
https://github.com/nolanlawson/rollup-comparison. Con módulos CommonJS
paga un costo por módulo (cada módulo debe estar envuelto en una función,
y necesita volver a declarar las importaciones que se comparten en todo el paquete, por lo que
se le penaliza por una base de código más modular), un costo por paquete (necesita
para simular un entorno Node.js) y otros costos, como unminifiable
nombres de propiedad de objeto que serían nombres de variable minificables en ES6
módulos. Los módulos ES6 le permiten combinar con literalmente cero gastos generales.-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -168394376.
Aunque habría algunos gastos generales al transpilar luego a es5
Si solo está utilizando la sintaxis import
y export
para describir la relación entre los módulos, no es necesario transpilar el código en sí con Babel o algo similar. Es solo cuando comienza a agregar otras características de ES6 (como clases y funciones de alcance de bloque y flechas, etc.) que la transpilación se vuelve necesaria, por lo que no hay gastos generales para usar import
y export
. D3 y PouchDB son dos ejemplos de bibliotecas que usan import
y export
pero, por lo demás, son ES5 sin Babel, y three-jsnext se hace de la misma manera.
Ok, todos tuvimos la misma idea. Sería genial tener una historia como lodash.
Propongo crear un paquete _three-foo_ para cada componente _foo_ (por ejemplo, three-vector2) que se pueda modularizar, casi sin cambios en el código, de modo que se pueda importar en este repositorio sin impacto.
Las personas que publican en npm deberían jugar bien y colaborar con @mrdoob ya que él es el creador de esta gran pieza de software, por lo que si quiere centralizar nuevamente todos los paquetes como lo hizo _babel_ author (me refiero a todos los paquetes principales en la misma carpeta), el editor debe darle control sobre el espacio de nombres npm tomado.
Intentaré hacer eso, para los paquetes que necesito. Veamos qué pasa.
Solo hay una gran comunidad :)
No noté a nadie sugiriendo separar completamente la biblioteca como
lodash. Lodash es una colección de utilidades con un nombre común; tu taxi
toma una sola pieza y úsala. Threejs no lo es; es un completo
biblioteca, la mayor parte de la cual es inútil sin el resto. Hay algunas piezas
que se pueden separar, como los tipos de materiales específicos de nuestro
generadores de geometría, pero esos necesariamente van a estar muy de cerca
vinculado al núcleo, probablemente necesitando coincidencias de versión exactas. Considerando su
tamaño, crearía un dolor de cabeza de mantenimiento sin ganancia medible.
Sin embargo, si el señor Doob aprueba una división de esa naturaleza, no creo que
apropiado para cualquier persona que no sea un mantenedor oficial para reclamar threejs- *
paquetes.
Independientemente de lo anterior, creo que es prudente hacerlo funcionar de forma modular.
medio ambiente antes que nada. Hubo varios proyectos con este
gol, pero todos parecen haber fracasado.
El 6 de marzo de 2016 a las 11:39 a. M., "Gianluca Casati" Notifications@github.com escribió:
Ok, todos tuvimos la misma idea. Sería genial tener una historia como
lodash.Propongo crear un paquete _three-foo_ para cada componente _foo_ (para
instancia tres-vector2) que se puede modularizar, casi sin cambios en
el código, por lo que se puede importar en este repositorio sin impacto.Las personas que publican en npm deberían jugar bien y colaborar con @mrdoob
https://github.com/mrdoob ya que es el creador de esta gran pieza
de software, por lo que si quiere volver a centralizar todos los paquetes como en
_babel_, el editor debe darle control sobre el espacio de nombres npm tomado.Intentaré hacer eso, para los paquetes que necesito. Veamos qué pasa.
Solo hay una gran comunidad :)
-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -192970867.
@mattdesl : por ejemplo, su three-shader-fxaa usa THREE.Vector2 y THREE.Texture, aparte del compositor de tres efectos que no verifiqué, resultaría en una construcción realmente liviana usando el enfoque de modularidad propuesto anteriormente.
@HMUDesign : Entiendo sus dudas, pero todavía me parece un buen enfoque. Quiero intentarlo, pero escucharé sus consejos, usando paquetes npm de las URL de GitHub, no publicándolos en el registro santo.
Lo intenté, comenzando desde TrackballControls, que depende de Vector2, Vector3, Quaternion, etc.
Hay departamentos circulares (por ejemplo, Matrix4 depende de Vector3 y viceversa). No se puede hacer si la lib (es decir, threejs) se inició de forma monolítica.
Es una pena que el patrón del módulo con todos sus beneficios no se pueda aplicar fácilmente en proyectos importantes como este.
Intento también con otros proyectos como svg.js, vvvvjs, incluso x3dom, pero si los autores no están completamente convencidos de esta elección radical, no se puede hacer.
Perdón por el spam, pero quería intentarlo de forma proactiva: por cierto, comencé con el repositorio de tres controles de trackball .
El patrón del módulo
Estoy seguro de que has visto esto: https://github.com/kamicane/three-commonjsify Lo resolvió en commonJS.
@drcmda realmente interesante, lo intentaré
+1 para pasar a una arquitectura modular.
+1
+1
@drcmda tiene razón. Los módulos ES6 tienen un paso de inicialización y un paso de ejecución que permite referencias circulares. Sin embargo, tan pronto como tenga dependencias circulares directamente desde el contexto de ejecución del módulo (en el área global de un módulo), el primero que se cargue durante el tiempo de ejecución experimentará valores indefinidos para sus dependencias. Siempre que las referencias se utilicen dentro de un contexto diferente donde el orden de ejecución en tiempo de ejecución es importante, las dependencias circulares no son un problema.
Sugiero considerar también webpack en lugar de browserify.
@gionkunz tenemos referencias circulares en el paso de inicialización bc del patrón donde hay un cierre para generar variables de scratch
La versión beta de Webpack 2 acaba de ser lanzada (https://twitter.com/TheLarkInn/status/747955723003322368/photo/1), por lo que los módulos es6 también podrían beneficiarse del movimiento de árboles cuando se empaquetan.
@mrdoob
¿Ha habido una declaración oficial más recientemente? Como muchos, hemos abandonado ES5 y pegamento-concats hace mucho tiempo y es bastante malo que TRES se salga de la línea en un sistema de construcción moderno. Usamos quizás el 10% de lo que puede hacer, pero es la mayor dependencia que enviamos.
Este es quizás el proyecto más favorito en Github para mí personalmente; espero sinceramente que se reconsideren las prioridades.
Mmm, me gustaría conocer más detalles sobre la compatibilidad con el navegador. Qué navegadores hacen y cuáles no. Para los navegadores que no lo hacen, cuáles son las soluciones y cuáles son las penalizaciones de rendimiento.
En realidad, la compatibilidad con el navegador deja de ser un problema (quizás incluso menos de lo que es ahora). Los sistemas de compilación toman ese código ES6 y lo transpilan a es5 (a veces ocupan menos espacio del que ocuparía el ES5 original). Ciertos tipos de cosas transpiladas terminan siendo grandes (principalmente: generadores y funciones asíncronas), pero si las evita, no tendrá esa penalización.
Como mencionó @drcmda , el sistema de compilación aún produciría una salida monolítica (y sería muy fácil personalizar exactamente lo que se incluye en esa salida), pero los módulos individuales también podrían incluirse en nuestros propios proyectos, por lo tanto, solo usaría las partes que nosotros necesitamos. Para aprovechar al máximo
que las interdependencias deben ajustarse, pero eso puede suceder con el tiempo. Creo que las características principales que queremos es tenerlo modular con importación / exportación. Desde su punto de vista, permitiría el uso de clases sobre prototipos (todavía usan prototipos bajo el capó, por lo que aún puede
lío con él según sea necesario).
Hay algunos sistemas de construcción. Mi voto sería webpack (que usa babel para la transpilación). Con babel, puede definir cargadores personalizados, por lo que el sistema de fragmentación que desarrolló para los sombreadores podría reducirse al código glsl real con una extensión #include (de hecho, hago mis sombreadores de esta manera y estaría feliz de contribuir al proyecto). Esto obtiene los mismos beneficios de su sistema (sin duplicación de código), pero es muy simple de usar.
Me encantaría ser parte del proyecto de modularización, pero sé que esto no tendrá éxito de ninguna manera sin su apoyo (y probablemente su asistencia). Muchos de nosotros sabemos cómo usar la biblioteca, pero ninguno de nosotros sabe cómo funciona internamente en la medida en que tú lo sabes.
Ciertos tipos de cosas transpiladas terminan siendo grandes (principalmente: generadores y funciones asíncronas), pero si las evita, no tendrá esa penalización.
¿Que tan grande?
Además, no hablaste de penalización por desempeño. ¿No es eso un problema entonces?
Por lo que puedo ver, las importaciones de ES6 todavía no son compatibles con ningún navegador , por lo que esta refactorización de módulo sería principalmente para sistemas de compilación, ¿verdad?
No olvide los beneficios que obtiene al usar herramientas como rollupjs, esto excluiría automáticamente todas las exportaciones que un usuario no usa. (Que es predeterminado con JSPM)
El paquete babel-polyfil, que solo es necesario si está utilizando
generadores (que probablemente ni siquiera tengan sentido en este proyecto) o asíncronos
funciones (que realmente no creo que cambiarían mucho en el proyecto
ya sea), agrega alrededor de 50k a la compilación final. Pero nuevamente, esto es opcional.
En cuanto al rendimiento, realmente depende exactamente de las características que tenga.
utilizando. Por ejemplo, las funciones de flecha son un poquito más lentas, debido a la
enlace subyacente, las clases son un poco más lentas de crear, aunque el
instanciar el tiempo es lo mismo. https://kpdecker.github.io/six-speed/
Las importaciones / exportaciones de ES6 no son compatibles con los navegadores, pero como va
a través de un sistema de compilación, eso no es un problema. La salida del producto sería
utilizable exactamente como es actualmente (incluso siendo compatible con versiones anteriores), pero
permitiría que se integrara en nuestros sistemas de compilación, y haría que el
componentes internos reutilizables para nosotros.
Otra cosa a tener en cuenta es el tamaño de construcción final. Actualmente, cosas como geometría,
Material, Malla, etc. son parte del espacio de nombres TRES. Cuando se minifica,
Las referencias a TRES.Geometría, TRES.Material, TRES.Malla, etc., permanecen en el
código. Con un sistema modular, cada uno de esos archivos obtendría algo como
var Geometry = require('./geometry');
luego tenga referencias al
variable Geometry
más tarde. Luego, en minifaciton, Geometry
y require
ambos se cambian a caracteres únicos, el './geometry' se reemplaza con un
número, lo que se traduce en un gran ahorro. Matemáticas de la servilleta: lo minificado
compilación es de 511,794 bytes y contiene 2942 referencias a
THREE\.[A-Z][a-zA-Z]+
. Reemplazando todos estos con un solo carácter
da como resultado una reducción del tamaño de archivo de casi un 10% (hasta 464.782). (El gziped
los tamaños son 117,278 y 110,460 respectivamente, una reducción del 6%). La construcción
probablemente podría ajustarse para reducir esto aún más.
Rollup (que eliminó el código no utilizado de una compilación final) es el predeterminado
con jspm, será el predeterminado con webpack2 (y creo que se puede usar
con paquete web). Si las cosas están escritas de forma modular, no creo que esto sea
útil, sin embargo. En cualquier caso, siempre que el código pueda transpilarse con
babel, se puede usar en cualquier sistema de compilación (el cargador glsl que mencioné
antes también se puede hacer que funcione con webpack).
El jueves 7 de julio de 2016 a la 1:28 p.m., Mr.doob Notifications@github.com escribió:
Ciertos tipos de cosas transpiladas terminan siendo grandes (principalmente:
generadores y funciones asincrónicas), pero si los evita, no tendrá
esa pena.¿Que tan grande?
-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/mrdoob/three.js/issues/4776#issuecomment -231197171,
o silenciar el hilo
https://github.com/notifications/unsubscribe/AA71cqAqmgxsUjpvamnI_xyL2wpzeWrdks5qTWGBgaJpZM4B4aA7
.
No estoy seguro de si esto es muy útil, pero este es el hilo de discusión para D3 con respecto al mismo problema: https://github.com/d3/d3/issues/2220. D3 4.0 ha adoptado la importación / exportación de ES6 para administrar módulos, pero aún está escrito en ES5 (https://github.com/d3/d3/issues/2220#issuecomment-111655235).
Muy interesante @jpweeks!
Entonces ... con este enfoque de importación / exportación ... ¿Cómo se verían cosas como object instanceof THREE.Mesh
?
@mrdoob
import/export
es solo la forma en que se declaran y se requieren los módulos. No afectará / cambiará el código definido dentro de los módulos en absoluto:
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
¡Eso es muy útil @GGAlanSmithee! ¡Gracias!
Soy una persona visual, así que los ejemplos de pseudocódigo me convencen más que grandes trozos de texto 😅
Correcto, entonces requerirá un poco de refactorización ...
¿Alguien sabe si el compilador de cierre planea respaldar esto?
Correcto, entonces requerirá un poco de refactorización ...
¡Te entiendo! Desde que este hilo se animó durante los últimos días, he estado trabajando un poco más en three-jsnext . Es un proyecto que toma la base de código Three.js existente y la convierte en módulos ES automáticamente. Solo estoy discutiendo con un par de dependencias cíclicas complicadas (particularmente alrededor de KeyframeTrack
), pero debería tener algo para compartir muy pronto. Por lo que puedo decir, todos los ejemplos continúan funcionando, y la compilación minificada es más pequeña que la actual (usando Rollup para generar un archivo UMD), por lo que son buenas noticias.
Ok, abrí una solicitud de extracción para esto: # 9310
@mrdoob
Tenemos una biblioteca en producción que más o menos está estructurada como TRES. Funciona en navegadores y entornos modulares. El código base es ES6, pero los navegadores no son su preocupación en absoluto.
Enviaría esto en npm _ como está_, todos los módulos incluidos + un monolito de navegador de espacio de nombres global compilado (three.js). Quien necesite usar partes individuales usa herramientas para crear paquetes.
Considere una estructura como esta:
/src
classA.js
classB.js
classC.js
/index.js
/browser.js
index.js simplemente reexporta todos los módulos y funciones en un archivo:
export ClassA from './src/classA';
export ClassB from './src/classB';
export ClassC from './src/classC';
Entonces, el usuario final puede instalar npm la lib y usarla sin más preámbulos:
// 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 sería la única parte compilada del paquete. Por lo general, se transpila a ES5 a través de Babel y se exporta a un espacio de nombres global para que pueda usarse como un script incluido. Rollup, Webpack, etc. pueden crear esto con facilidad.
@mrdoob ha sido un viaje maravilloso 🚀
Comentario más útil
¡Te entiendo! Desde que este hilo se animó durante los últimos días, he estado trabajando un poco más en three-jsnext . Es un proyecto que toma la base de código Three.js existente y la convierte en módulos ES automáticamente. Solo estoy discutiendo con un par de dependencias cíclicas complicadas (particularmente alrededor de
KeyframeTrack
), pero debería tener algo para compartir muy pronto. Por lo que puedo decir, todos los ejemplos continúan funcionando, y la compilación minificada es más pequeña que la actual (usando Rollup para generar un archivo UMD), por lo que son buenas noticias.