jeromeetienne / tquery

extension system for three.js
http://jeromeetienne.github.io/tquery/
MIT License
652 stars 119 forks source link

require.js isnt yet settled #106

Closed jeromeetienne closed 12 years ago

jeromeetienne commented 12 years ago

just direcovered dat.gui uses require.js internally. It may be a good example to tQuery code.google.com/p/dat-gui/

jeromeetienne commented 12 years ago

Work in plugins/requirejs

konsumer commented 11 years ago

I feel like tQuery is not really taking advantage of require.js's strengths.

I think the build/testing could be greatly simplified, and dependency management could be stronger, but it would take a lot of file restructuring. I'd be happy to do it, if it's desired. I think it'd be great if it wasn't in shim's, and instead things returned refs to themselves, more like this: https://github.com/mrdoob/three.js/pull/2084

It makes the code more modular, and leaner (you include just what you need) and easier to test.

UMD project has great examples.

This will make it work in most javascript environments (AMD, CommonJS, or browser-global)

If all sub-parts of tQuery and it's plugins followed this standard, it would be much easier to incorporate into larger projects.

Require also has pretty awesome dependency-aware build & minification, and you can also use almond as a tiny all-in-one-file version for browsers.

I would like to make a new branch with everything moved around, a more efficient build script and all the tQuery core, plugins, and examples using requirejs, just to showoff how powerful it is. I could also separate out vendor stuff, and use npm for devs to build it (get require and almond) and CDNs so their stuff is not mirrored in the repo.

Should I fork&branch? Do you have a naming convention you prefer?

jeromeetienne commented 11 years ago

What would it provide which isnt there already?

konsumer commented 11 years ago

I get errors, with the current tquery-bundle-require.js build in the console, and minification doesn't happen at all, much less source-aware minification (like require provides, built-in). Those would be the first things to fix, for me.

Wrapping all the submodules in js/ in defines or even commonjs exports would mean that they are not crammed into browser-globals, and could be used in require and node properly. I would like to see all the sub-parts being testable without loading all of the the whole, and each piece aware of what it requires. This way you don't have to include every part, just the ones you need. It may also mean that tQuery (and threejs) could be used with non-web projects using node-webgl, for standalone apps, and servers that can track 3d objects. Using require or exports gives you 3 options: require what you need, as needed, cram it all into a closure at runtime (get same setup as now, but better managed, and easier to dev with parts) or use in commonjs environments. currently, the only options are a global var (which could be hacked to work in require or commonjs, but aren't.)

I am not saying that it necessarily should all be wrapped in defines, but some kind of structure (AMD and CommonJS are both great approaches, server or client-side) would help me to use it (rather than just using threejs) in larger projects & server-side projects.

jeromeetienne commented 11 years ago

current status:

jeromeetienne commented 11 years ago

im using tQuery in a large project myself, and i dont hit any specific issue due to require.js. Can you details the issue you hit ?

jeromeetienne commented 11 years ago

that said im no expert in require.js. Currenlty im not sure it is minified and include the whole require.js file which is rather large. So if you could make it minified or to be able to use almond on option. it would be nice.

konsumer commented 11 years ago

So, as a warning, this is pretty long-winded, but it's a topic I am passionate about, and would love to help with. here goes:

it is possible to get all plugins with require.js. loading dependancies automatically

I can't seem to do this, without a massive number of shims & I can't do it with the individual parts of tQuery. Maybe we mean something different.

require.js is optional i would like to keep this feature

I totally agree. Require is really just a dev/build tool, and completely optional to the end-user. I am proposing better AMD/CommonJS/UMD, which is not limited to requirejs (curl.js is totally awesome, and almond works automatically as a runtime to just put all the defines in an array, so you don't need to load requirejs or curl.) The whole thing can also be setup as CommonJS (node, rhino, etc) and requirejs optimizer can turn that into AMD. For me, I really like using CommonJS or the UMD approach.

Using the UMD approach, it works exactly the same as now, but if you have CommonJS or AMD, it works better. It complicates things a bit, and adds code to all your source-files, but in my opinion is often worth it (like in the case of underscore, which is the most-used npm dependency, but also used in browsers, and often just one or two things are needed.)

Another way to think about this stuff is that any js project favors one dep-management standard and adapts to others. The browser-global method does not adapt well to others, but AMD & CommonJS both do. Here is an example: curl/requirejs/almond favors AMD, but adapts to non-AMD when it makes a giant closure that stores all the minified source. It adapts to CommonJS by exporting functions that process AMD (so define() works.) When code is structured this way, you can also do source-mapping, which is handy for developers who want to go find the file that produced the error they are seeing. Here is an example setup that favors CommonJS, instead, and has no requirements otherwise, but supports AMD, CommonJS, and a browser-global (as it is now):

The real work is around tracking dependences, and is totally not related to the dependency management solution, or module-format. It's a matter of going through all the files and ensuring they track their dependencies correctly (either with AMD define()'s or CommonJS require()'s.)

there is only one global defined tQuery it is current best practice for libraries

I disagree. jQuery, underscore, dojo & YUI all use an organized dependency management solution, and can be used in node, require, etc, if you just want to use parts. You don't lose the browser-global way, so it's totally win-win, other than the work of tracking all the dependencies, which has other gains, especially in large projects, in my opinion.

im using tQuery in a large project myself, and i dont hit any specific issue due to require.js. Can you details the issue you hit ?

I am pulling from GitHub master, directly.

If I use it without a shim, I just get "Uncaught Error: Mismatched anonymous define() module: [BIG function definition]"

If I add the shim-config (not really using AMD) it works, but still outputs error.

Here is the code I am using:

// main.js
requirejs.config({
    "paths":{
        "tQuery": "https://raw.github.com/jeromeetienne/tquery/master/build/tquery-bundle-require"
    },
    shim: {
        "tQuery": { "exports": "tQuery" }
    },
    urlArgs: "v=" + (new Date()).getTime() // cache busting, set to ver in production
});

define(['tQuery'], function(tQuery){
    var world = tQuery.createWorld().boilerplate().start();
    var object = tQuery.createTorus().addTo(world);
});
<script data-main="main.js" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.1/require.min.js"></script>

As a sidenote: This is a simple example, but quickly grows when you need more parts of tQuery. Global browser-space is polluted with tQuery, which could be bad if you don't want your users easily live-hacking your game. If you are using require (wrap:true in config), a closure around tQuery defines, or a client-side CommonJS library (that doesn't use a global var), you don't need to worry about this quite as much (I mean, it's client-side code, so you still do...) If you don't care about users hacking stuff (or want to be able to, in dev) you can just use requirejs as-is, and it's actually easier to troubleshoot sometimes in console, because you can do this:

world=require('worlds/intro')
world.camera.lookAt(world.scene.position)

Since none of the individual files are aware of their own dependencies, and the current AMD wrapper is just a header+footer, the whole thing is more fragile, and doesn't take advantage of the great things about requirejs, like smaller code, and modular loading of just what you need (great for testing, just require the parts you actually use, also great for dev->production, where only the bits you use get included in final product.)

So if you could make it minified or to be able to use almond on option. it would be nice.

Yep, almond is just a runtime (that depends on requirejs for build) , and require does not need to be included (make it an npm devDependency for building, then have it generate the compiled version) but also can be pulled off CDN, so I dunno if size is a super-big deal.

As I mentioned before, though, AMD is not the only option. I like CommonJS, since I am used to node's require(), and it's simple and has a lot less overhead, but also works with AMD if you use browserify/requirejs.

I feel like in a situation like this, it's best for me to put-up or shut-up, and just make a nice code example of the ideas I am proposing. I would be happy to do this.

ghost commented 11 years ago

@konsumer It works in require for me no problem except the main lib I had to put on the old fashion way because it caused r.js optimizer to hang. It would be nice to standardize the AMD format the UMD format just seems really bloated I haven't found a good enough reason to justify it. When it comes down to heavy 3d engines we should care about bloat... Because everything is global you can just import it in the define. There is no need for having a argument or returning the object. For future I wish they would get some sort of module system together so we can have dependency injection/management. But for now you can compile it in your main package with r.js.