Meta: Why does three.js check builds into the master git repo?

I’m just wondering why three.js commits built files to the main repo. I totally understand why it’s important to publish builds somewhere (npm, unpkg, or even a separate github repo, treating it as a sort of CDN), but it seems like this complicates life for all contributors.
For example, if I fork and clone three.js and do a build, git says I now have modified files even though I didn’t change anything yet! (Because the build/ tree is only updated every so often.) And if I do want to post a PR, I have to remember not to commit the build/ tree, and my IDE’s warning me about modified files…
So I’m just wondering what the logic behind this is – as an old-school C++ graphics guy it seems odd, but maybe it’s normal for Javascript projects?

1 Like

Making the build files part of the repo enables us to use sites like https://raw.githack.com/. If contributors change examples, docs or improve the editor, they can always provide a live demo with the latest dev version of three.js. Example: https://github.com/mrdoob/three.js/pull/16351

Or you can use the following link to test the examples with the latest dev version of three.js.

https://raw.githack.com/mrdoob/three.js/dev/examples/index.html

1 Like

Well, OK, wouldn’t be how I’d do it (you’re testing the examples off the tip of the branch, vs. a build from whenever it was last done, basically mixing git commits - if you like that, I’d just have the examples link to a CDN with the latest build) but if folks like it that way, who’m I to say.
(And yikes, that PR #16351 adds pretty large binary files without using git lfs! But that’s another story.)

1 Like

And yikes, that PR #16351 adds pretty large binary files without using git lfs! But that’s another story.

Sounds like a potentially useful change. Why don’t you open an issue on Github to discuss it?

But you did change something - or at least, you ran a script which changed something. We run scripts on code all the time to make changes, e.g. linting, refactoring etc. Why would creating build files be different?

I don’t have much experience with C++, but as you say, perhaps this confusion is caused by differences in the languages. Building files here is mainly just concatanation of modules, or replacing of functions with versions that have better support in older browsers. There isn’t the same conceptual difference between “source” and “build” that exists in compiled languages, and if you want you can use the files directly from source in your projects with only minor changes required to make it work.

And if I do want to post a PR, I have to remember not to commit the build/ tree, and my IDE’s warning me about modified files…

It’s not a big issues to remember not to add builds, and perhaps you can configure your IDE to stop displaying those warnings for this repo? Most JS devs use VSCode, Atom or Sublime Text, and I don’t recall seeing warnings in any of those.

Maybe you’re right and git GUIs hide the fact that you still have modified files. I’m an old git cmdline guy – get off my lawn! (haha)

But I think you still get conflicts on the build files whenever you do a git pull, right? (At least after a new build has been done upstream) So you have to resolve those conflicts (delete yours, accept theirs) and then do a rebuild. Not a huge deal, but my heart rate always goes up when I see conflicts from a git pull (or merge).

Anyway, I guess folks here like it this way so I’ll deal. :slight_smile:

1 Like

I think it’s somewhat more than that, like the GLSL files that are standalone are possibly a bit more than a simple concat.

I never looked into this, but i think the solution is more to have a local .ignore file that wouldn’t commit the build. But then you end up with a different ignore file.

I was hoping to address this bit, so i hope my comment does not get deleted. When i think of a modern javascript project, i think of React. When looking at the source of react, it seems to be using a very modern version of the language, you will see classes, arrow functions, async/await, and all kinds of stuff. When including three.js into a project with a lot of other javascript modules, three is very likely to be the only package without semver.

One huge thing, that i don’t really know how it works under the hood, but i let my imagination run wild, is running / building with development and production flags. This could allow for all kinds of optimizations to be done at compile time, which i don’t think three.js uses today. Today i could probably open the console on any three.js app out there, and log the draw calls, while i might want a production build that doesn’t even do that count.

So i don’t think you can apply any generic rule from three.js to all javascript projects, and vice versa. I’m always up for a constructive conversation, and am curious about the opinions, an opinionated dev coming from C++ may have.

Like storing ginormous meshes, audio files and videos is probably a job for LFS, but i never actually got to work with LFS because three.js doesn’t use it, and i learn everything from three.js. The idea there is that you wouldn’t have to sync the large files? I always had trouble setting this up.

I’d also like to know what kind of alternatives there are for publishing the builds. Could they be ignored in some public ignore file, but then manually committed by the maintainers ? Can they be committed to other repos?

This is in fact possible. You can use git update-index --skip-worktree to tell git to ignore the fact that certain files have changed in your worktree. It’s file-by-file, not the whole dir, but it does work for the most part. However, when you pull from upstream and the build has changed, you still get conflicts that you have to resolve, so it’s not a 100% solution.

If it were my project, I’d have a github CI hook that would publish builds somewhere (another git repo or just a CDN), including the examples and everything. Then githack and other endpoints would feed from that, rather than the source repo. But again, coming from a mostly C++ world, I don’t know the tooling for JS as well so there may be good reasons to not do that.

And as far as git lfs goes, please see the issue I recently created to track that suggestion. I’ve used git lfs for large binaries for years (VFX assets, customer repro cases as zip files, etc.), though I know some people aren’t comfortable with it. Github does enforce strict limits on file and pack sizes though (non-LFS file size < 100MB, repo size recommended <1GB, 2GB hard limit), which have bitten me before.

1 Like

I think what I’ve done before is to have my own feature dev and master branches. I’d dev and build in the dev, squash and not build in the master from which I’d make a pull request. Is this also a valid approach?

Sure. A little dangerous perhaps because you should do a build just before committing, to make sure everything is OK (especially if you’re merging or rebasing). But in that case you can do your build, run your final tests, and then git checkout build to reset the build dir before committing. All totally doable.

1 Like