Skip to content

Conversation

@marcofugaro
Copy link
Contributor

@marcofugaro marcofugaro commented Jan 28, 2022

Related issue: #23354

Description

With this PR, npm users that rely on bundlers which have tree-shaking built in, will be able to do this:

import * as THREE from 'three';
import { GLTFLoader, OrbitControls } from 'three/addons';

The old examples/jsm imports would still work fine, and nothing is changed on that front.

The main commit is 2d3d558, after that I did some cleaning up in the exports of the examples.

You can test this PR by doing:

npm install three@marcofugaro/three.js#node-addons

@marcofugaro
Copy link
Contributor Author

Fixed some duplicate export conflicts (for example Pass and FullScreenPass are already available in Pass.js), should be all good now.

@CodyJasonBennett
Copy link
Contributor

CodyJasonBennett commented Jan 28, 2022

Seems there's a few side effects that'll have to be ironed out (they break tree-shaking and will run/bundle regardless if you import them).

image

More concerningly, WebGPURenderer emits a side-effect that can break camera math for WebGL (related #20283).

I suppose we can move WebGPURenderer's matrix stuff to its init method as a workaround but these will need a bigger fix.

@marcofugaro
Copy link
Contributor Author

Right.. forgot to check tree-shaking. I'll investigate, thanks for testing!

@mrdoob
Copy link
Owner

mrdoob commented Jan 28, 2022

Actually, if we don't flatten the paths in examples/jsm/addons.js and we rename it to examples/jsm/index.js...

This would work, right?

<script type="importmap">
	{
		"imports": {
			"three": "https://unpkg.com/three@0.137.0/build/three.module.js",
			"three/addons": "https://unpkg.com/three@0.137.0/examples/jsm/"
		}
	}
</script>
    
<script type="module">
      
	import * as THREE from 'three';
	import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
	import { VRButton } from 'three/addons/webxr/VRButton.js';

	...
</script>

Edit: Or I guess it needs to be "three/addons": "https://unpkg.com/three@0.137.0/examples/jsm/index.js"...

@marcofugaro
Copy link
Contributor Author

marcofugaro commented Jan 28, 2022

@mrdoob as of now, you can alias only full paths with import maps 😬

So for this to work:

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

you would have to add as import map the full path meaning three/addons/loaders/GLTFLoader.js.

wrong, see #23368 (comment)

@marcofugaro
Copy link
Contributor Author

Also we can't use examples/jsm/addons.js on the browser because it would import every module 😂

@mrdoob
Copy link
Owner

mrdoob commented Jan 28, 2022

lol

@mrdoob
Copy link
Owner

mrdoob commented Jan 28, 2022

This works~! ✨

<script type="importmap">
	{
		"imports": {
			"three": "https://unpkg.com/three@0.137.0/build/three.module.js",
			"three-addons/": "https://unpkg.com/three@0.137.0/examples/jsm/"
		}
	}
</script>
    
<script type="module">
      
	import * as THREE from 'three';
	import { GLTFLoader } from 'three-addons/loaders/GLTFLoader.js';
	import { VRButton } from 'three-addons/webxr/VRButton.js';

	...
</script>

https://github.com/WICG/import-maps#packages-via-trailing-slashes

(Thanks to Russell Bicknell and Justin Ridgewell for the pointers! 🙏)

@mrdoob
Copy link
Owner

mrdoob commented Jan 28, 2022

So I guess we do not need this PR?

We'll have to make another script to implement that pattern in all the examples though.

@CodyJasonBennett
Copy link
Contributor

CodyJasonBennett commented Jan 28, 2022

Maybe, but it also exposed some potential issues for users regarding the chevrotain module and WebGPURenderer (the latter being a bit more concerning).

Is there still an issue to track tree-shaking? WebGPURenderer can break some apps as-is if ever bundled alongside WebGLRenderer despite the workaround though.

@mrdoob
Copy link
Owner

mrdoob commented Jan 28, 2022

Is there still an issue to track tree-shaking?

Maybe better creating new issues for these.

@marcofugaro
Copy link
Contributor Author

marcofugaro commented Jan 28, 2022

After a bit of digging, it looks like rollup correctly tree-shakes all unused files, while webpack and esbuild have difficulty tree-shaking the following files:

List of unshaken files (excluding webgpu + nodes)
node_modules/three/examples/jsm/animation/CCDIKSolver.js
node_modules/three/examples/jsm/animation/MMDPhysics.js
node_modules/three/examples/jsm/animation/MMDAnimationHelper.js
node_modules/three/examples/jsm/shaders/BokehShader2.js
node_modules/three/examples/jsm/controls/FirstPersonControls.js
node_modules/three/examples/jsm/controls/TransformControls.js
node_modules/three/examples/jsm/controls/DragControls.js
node_modules/three/examples/jsm/controls/PointerLockControls.js
node_modules/three/examples/jsm/controls/ArcballControls.js
node_modules/three/examples/jsm/controls/OrbitControls.js
node_modules/three/examples/jsm/csm/CSMFrustum.js
node_modules/three/examples/jsm/csm/CSMShader.js
node_modules/three/examples/jsm/csm/CSM.js
node_modules/three/examples/jsm/deprecated/Geometry.js
node_modules/three/examples/jsm/exporters/GLTFExporter.js
node_modules/three/examples/jsm/libs/fflate.module.js
node_modules/three/examples/jsm/exporters/DRACOExporter.js
node_modules/three/examples/jsm/libs/mmdparser.module.js
node_modules/three/examples/jsm/geometries/ParametricGeometry.js
node_modules/three/examples/jsm/geometries/ParametricGeometries.
node_modules/three/examples/jsm/math/ConvexHull.js
node_modules/three/examples/jsm/math/SimplexNoise.js
node_modules/three/examples/jsm/geometries/LightningStrike.js
node_modules/three/examples/jsm/geometries/RoundedBoxGeometry.js
node_modules/three/examples/jsm/helpers/VertexTangentsHelper.js
node_modules/three/examples/jsm/helpers/VertexNormalsHelper.js
node_modules/three/examples/jsm/interactive/InteractiveGroup.js
node_modules/three/examples/jsm/interactive/SelectionBox.js
node_modules/three/examples/jsm/lines/LineSegmentsGeometry.js
node_modules/three/examples/jsm/lines/LineGeometry.js
node_modules/three/examples/jsm/lines/LineMaterial.js
node_modules/three/examples/jsm/lines/Wireframe.js
node_modules/three/examples/jsm/lines/WireframeGeometry2.js
node_modules/three/examples/jsm/lines/LineSegments2.js
node_modules/three/examples/jsm/lines/Line2.js
node_modules/three/examples/jsm/loaders/FBXLoader.js
node_modules/three/examples/jsm/misc/VolumeSlice.js
node_modules/three/examples/jsm/misc/Volume.js
node_modules/three/examples/jsm/loaders/ifc/web-ifc-api.js
node_modules/three/examples/jsm/loaders/FontLoader.js
node_modules/three/examples/jsm/loaders/GLTFLoader.js
node_modules/three/examples/jsm/libs/chevrotain.module.min.js
node_modules/three/examples/jsm/loaders/VRMLLoader.js
node_modules/three/examples/jsm/utils/WorkerPool.js
node_modules/three/examples/jsm/loaders/KTX2Loader.js
node_modules/three/examples/jsm/loaders/LogLuvLoader.js
node_modules/three/examples/jsm/libs/opentype.module.min.js
node_modules/three/examples/jsm/loaders/BasisTextureLoader.js
node_modules/three/examples/jsm/loaders/LDrawLoader.js
node_modules/three/examples/jsm/loaders/lwo/LWO2Parser.js
node_modules/three/examples/jsm/loaders/lwo/LWO3Parser.js
node_modules/three/examples/jsm/loaders/lwo/IFFParser.js
node_modules/three/examples/jsm/loaders/OBJLoader.js
node_modules/three/examples/jsm/shaders/MMDToonShader.js
node_modules/three/examples/jsm/loaders/MMDLoader.js
node_modules/three/examples/jsm/loaders/KTXLoader.js
node_modules/three/examples/jsm/loaders/RGBMLoader.js
node_modules/three/examples/jsm/loaders/PLYLoader.js
node_modules/three/examples/jsm/objects/Lensflare.js
node_modules/three/examples/jsm/objects/MarchingCubes.js
node_modules/three/examples/jsm/objects/LightningStorm.js
node_modules/three/examples/jsm/objects/Reflector.js
node_modules/three/examples/jsm/objects/ReflectorForSSRPass.js
node_modules/three/examples/jsm/objects/Refractor.js
node_modules/three/examples/jsm/objects/ShadowMesh.js
node_modules/three/examples/jsm/objects/Sky.js
node_modules/three/examples/jsm/objects/Water.js
node_modules/three/examples/jsm/objects/Water2.js
node_modules/three/examples/jsm/math/MeshSurfaceSampler.js
node_modules/three/examples/jsm/math/OBB.js
node_modules/three/examples/jsm/math/Capsule.js
node_modules/three/examples/jsm/math/ImprovedNoise.js
node_modules/three/examples/jsm/math/Octree.js
node_modules/three/examples/jsm/math/Lut.js
node_modules/three/examples/jsm/misc/ConvexObjectBreaker.js
node_modules/three/examples/jsm/misc/Gyroscope.js
node_modules/three/examples/jsm/modifiers/CurveModifier.js
node_modules/three/examples/jsm/modifiers/SimplifyModifier.js
node_modules/three/examples/jsm/modifiers/EdgeSplitModifier.js
node_modules/three/examples/jsm/libs/OimoPhysics/OimoPhysics.js
node_modules/three/examples/jsm/libs/OimoPhysics/index.js
node_modules/three/examples/jsm/postprocessing/Pass.js
node_modules/three/examples/jsm/shaders/HalftoneShader.js
node_modules/three/examples/jsm/shaders/SMAAShader.js
node_modules/three/examples/jsm/shaders/CopyShader.js
node_modules/three/examples/jsm/postprocessing/OutlinePass.js
node_modules/three/examples/jsm/shaders/SSAOShader.js
node_modules/three/examples/jsm/postprocessing/SSAOPass.js
node_modules/three/examples/jsm/shaders/SSRrShader.js
node_modules/three/examples/jsm/postprocessing/SSRrPass.js
node_modules/three/examples/jsm/shaders/LuminosityHighPassShader.
node_modules/three/examples/jsm/postprocessing/UnrealBloomPass.js
node_modules/three/examples/jsm/shaders/SAOShader.js
node_modules/three/examples/jsm/shaders/DepthLimitedBlurShader.js
node_modules/three/examples/jsm/shaders/UnpackDepthRGBAShader.js
node_modules/three/examples/jsm/postprocessing/SAOPass.js
node_modules/three/examples/jsm/shaders/DotScreenShader.js
node_modules/three/examples/jsm/shaders/SSRShader.js
node_modules/three/examples/jsm/postprocessing/SSRPass.js
node_modules/three/examples/jsm/shaders/ConvolutionShader.js
node_modules/three/examples/jsm/postprocessing/BloomPass.js
node_modules/three/examples/jsm/renderers/CSS2DRenderer.js
node_modules/three/examples/jsm/renderers/CSS3DRenderer.js
node_modules/three/examples/jsm/renderers/SVGRenderer.js
node_modules/three/examples/jsm/libs/flow.module.js
node_modules/three/examples/jsm/shaders/GodRaysShader.js
node_modules/three/examples/jsm/shaders/VerticalBlurShader.js
node_modules/three/examples/jsm/shaders/ColorCorrectionShader.js
node_modules/three/examples/jsm/shaders/TriangleBlurShader.js
node_modules/three/examples/jsm/shaders/FXAAShader.js
node_modules/three/examples/jsm/shaders/
node_modules/three/examples/jsm/shaders/ToonShader.js
node_modules/three/examples/jsm/shaders/NormalMapShader.js
node_modules/three/examples/jsm/shaders/FreiChenShader.js
node_modules/three/examples/jsm/shaders/VolumeShader.js
node_modules/three/examples/jsm/shaders/
node_modules/three/examples/jsm/shaders/VerticalTiltShiftShader.
node_modules/three/examples/jsm/shaders/SobelOperatorShader.js
node_modules/three/examples/jsm/shaders/HorizontalBlurShader.js
node_modules/three/examples/jsm/shaders/ColorifyShader.js
node_modules/three/examples/jsm/libs/stats.module.js
node_modules/three/examples/jsm/utils/GPUStatsPanel.js
node_modules/three/examples/jsm/webxr/XRHandPrimitiveModel.js
node_modules/three/examples/jsm/libs/motion-controllers.module.js
node_modules/three/examples/jsm/webxr/OculusHandPointerModel.js
node_modules/three/examples/jsm/webxr/VRButton.js

If you want to dig into it more, here is the resulting esbuild bundle: addons-esbuild.js.zip

Most of them are unshaken because of the missing /* @__PURE__ */ notation on variables, while other because of various side-effects.

@marcofugaro
Copy link
Contributor Author

I am going to close this PR for now since I don't have the bandwitdth to solve the tree-shaking problems in all these files.

We'll go with the pattern proposed by @mrdoob, best part is that it would be exactly the same both on node and the browser 💪

import * as THREE from 'three';
import { GLTFLoader } from 'three-addons/loaders/GLTFLoader.js';
import { VRButton } from 'three-addons/webxr/VRButton.js';

I'll make a PR sometime next week.

@donmccurdy
Copy link
Collaborator

Is "three-addons" a new npm package, or just an alias used for examples in an import map here?

@CodyJasonBennett
Copy link
Contributor

An alias but it can be a bit misleading indeed.

@marcofugaro
Copy link
Contributor Author

Is "three-addons" a new npm package, or just an alias used for examples in an import map here?

Right.. we probably want this, to avoid confusion

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { VRButton } from 'three/addons/webxr/VRButton.js';

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants