three.js: [124] TiltLoader breaks in a module env
Repro: https://codesandbox.io/s/elegant-villani-9d3hr?file=/src/index.js
import { TiltLoader } from "three/examples/jsm/loaders/TiltLoader"
new TiltLoader().load("/model.tilt", (scene) => console.log(scene))
This is the error message in a local env (Parcel):
TiltLoader.js:42 TypeError: _jszipModuleMin.JSZip is not a constructor
at TiltLoader.parse (TiltLoader.js:59)
at Object.onLoad (TiltLoader.js:32)
at XMLHttpRequest.<anonymous> (three.module.js:36749)
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 32 (7 by maintainers)
Commits related to this issue
- Add Zip64 support for mrdoob/three.js#20941 — committed to 101arrowz/fflate by 101arrowz 4 years ago
- Add Zip64 support for mrdoob/three.js#20941 — committed to 101arrowz/fflate by 101arrowz 4 years ago
- Add Zip64 support for mrdoob/three.js#20941 — committed to 101arrowz/fflate by 101arrowz 4 years ago
- Add Zip64 support for mrdoob/three.js#20941 — committed to 101arrowz/fflate by 101arrowz 4 years ago
Hi, author of fflate here! The reason the async version exists in JSZip is beyond me, since it doesn’t actually offload the processing to other threads. On the other hand, if the assets in the ZIP are reasonably large (around 500kB), fflate will use worker threads to compress/decompress them faster.
However, I looked at some of the demos using JSZip and they don’t seem to load that much data, so using the synchronous unzipping algorithm would be no different to the async version. You could even replace
gunzip.js
, which is used by the NRRD loader, withfflate
because gunzip and unzip use the same core algorithm.Since it seems the ThreeJS team wants minified ES6 module scripts, I’ve hand-tuned a minified version of the library and pasted it below. It’s 4.4kB (2.2kB gzipped) and supports synchronous ZIP decompression (through the exported
unzipSync
method) and GZIP decompression (throughgunzipSync
).Usage:
Minified code (to put in
fflate.module.min.js
):This duplication issue will still exist if the examples were to use fflate, but since most users seem to think of 4kB as pocket change, it probably doesn’t matter.
I added the ZIP function into
fflateDeflate
.fflate-deflate.min.js
:fflate-deflate.min.module.js
:Usage:
Side note: in case @sciecode is still working on this,
fflate.unzlibSync(u8Data, new Uint8Array(uncompressedSize))
will work well for you. See the docs.Also, if you’re still looking into the EXR exporter, try
fflateDeflate.zlibSync(u8Data, options)
. DocsMy bad, updated the code in my most recent comment. I had forgotten to switch the CommonJS exports to ESM. UMD build should already be live on jsDelivr, I believe, but you could probably wrap the minified code to make the UMD build smaller too.
On looking again at the source code here, it seems that a lot of compression libraries could be replaced by a single one, which is probably better to avoid fragmentation…Will create a more complete minified copy soon and create a PR.
EDIT: Here are my (semi) final revisions for the versions:
fflate.min.js
(replacesgunzip.js
,inflate.js
,jszip.js
):fflate.module.min.js
:fflate-deflate.min.js
(replacesdeflate.js
):fflate-deflate.module.min.js
:Sorry to waste your time with the bugs @Mugen87!
You have the spec, and you have reality. V8 and Gecko use a 64 bit unsigned integer to store the size of typed arrays, which means a theoretical max of a lot, but they both cap the actual size at 231 on all devices I’ve tested. Node caps it at 232. No Zip64 data is strictly necessary while still being possible in JavaScript.
I understand that Zip64 is important, so I’ll add support for it. However, this might be a few days of work since it’s a much more messy specification.
yep, still plan on finalizing the exporter. I had already taken a note to update current deflate to fflate’s deflate, but thanks for the heads up 👍
I’m not exactly sure what the
resize
option does, but it seems like an optimization more than anything. I checked its usage in the source code and it seems to change basically nothing; the only difference is allocating a new array of length LEN and copying bytes 0 to LEN into the new array vs. taking the subarray from 0 to LEN directly. If anything, the O(n) allocation + copy would be slower…I actually took a closer look and found this comment that indicates that it’s a memory optimization. This is applied by default in
fflate
because if it weren’t, memory would be about 2x worse.Great! I’ve completed my first PR to migrate loaders from JSZip.js and gunzip.js to fflate.
I change inflate to fflate in a separate PR when the first one was merged.
I see. Okay, thanks!
Yes, that sounds good. I vote to place this file in
editor/js/libs
as long as it is not required elsewhere.Can you please also share an updated version of
fflate.min.js
? We need an UMD version for loaders inexamples/js
.Besides, when using the above code I get:
Turns out the problem was way easier to fix than I thought. Zip64 support was just added; it works on the 3MF files from what i can tell.
New code (4.6kB, 2.3kB gzipped):
Okay,
webgl_loader_3mf
works now but I get an empty objectzip
object inwebgl_loader_3mf_materials
. Please check out:https://raw.githack.com/Mugen87/three.js/0b388b5f6fa9228425acae87775d3a28088501a9/examples/webgl_loader_3mf_materials.html
Current prod version: https://threejs.org/examples/webgl_loader_3mf_materials
The issue there is that in your source code, you pass an ArrayBuffer to
fflate.unzipSync
but you need to pass a Uint8Array. To fix the problem, usefflate.unzipSync(new Uint8Array(data))
. I applied this hotfix within DevTools and the assets were displayed fine after that. Don’t worry about performance cost, this is a free operation (just creates an interface to view the same chunk of memory without any copying).Understood, wasn’t aware they changed the api that drastically. Fflate supports both async and sync, for instance
fflate.unzipSync(...)
. It’s smaller (~5kb vs 80kb), faster (they say up to 50%), no module bugs, maintained, seems like a good replacement. For me it’s not so pressing, just wanted to try out TiltLoader really, but maybe if time allows it could be amended. =)I looked, it’s a problem with JSzip: https://github.com/Stuk/jszip/issues/349 The lib appears unmaintained and i don’t think they will fix it. In that case the loader won’t be of much use imo.
Some people have suggested to use https://github.com/101arrowz/fflate instead.
Other projects have moved on as well for the same reason, this PR explains some of the problems with JSZip:
Not complaining, i was just curious, i just hope at some point in the future this will be re-considered because JSM has incredible value that is held back atm.
If we do this, the example would report:
So it seems the current import is correct. Could this be a problem of Parcel?
We do not want to force users into using
npm
for just working with the example code. Ideally, they can download the repository and host it on a local webserver.