使用Three.js开发水面效果时遭遇模块解析错误,求排查方案
Three.js水面效果模块解析错误排查
错误信息
Uncaught TypeError: Error resolving module specifier “three”. Relative module specifiers must start with “./”, “../” or “/”.
问题代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My first three.js app</title> <style> body { margin: 0; } </style> <script type="importmap"> { "imports": { "three": "./build/three.module.js", "three.js-master/examples/jsm/controls/OrbitControls":"./jsm/controls/OrbitControls.js", "three.js-master/examples/jsm/libs/stats.module":"./jsm/libs/stats.module.js", } } </script> </head> <body> <script type="module" src="https://cdn.jsdelivr.net/npm/three@0.143/build/three.min.js"></script> <script type="module" src="https://cdn.jsdelivr.net/npm/three@0.143/examples/js/controls/OrbitControls.js"></script> </script> <script type="module"> import { Water } from 'http://localhost/Lines/jsm/objects/Water.js'; import * as THREE from 'http://localhost/Lines/build/three.module.js'; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); camera.position.set( 0, 0, 50 ); camera.lookAt( 0, 0, 0 ); const renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); const WaterGeometry = new THREE.PlaneGeometry( 45, 45 ); const texture = new THREE.TextureLoader().load( 'https://i.imgur.com/mK9cHLq.jpeg' ); const material = new THREE.MeshBasicMaterial( { map: texture, side: THREE.DoubleSide } ); const controls = new THREE.OrbitControls( camera, renderer.domElement ); let water = new Water ( WaterGeometry, { textureWidth: 512, textureHeight: 512, waterNormals: new THREE.TextureLoader().load ( 'textures/waternormals.jpg', function ( texture ) { texture.wrapS = texture.wrapT = THREE.RepeatWrapping; } ), sunDirection: new THREE.Vector3(), sunColor: 0xffffff, waterColor: 0x001e0f, distortionScale: 3.7, fog: scene.fog !== undefined } ); controls.update(); scene.add( water ); function animate() { requestAnimationFrame( animate ); water.rotation.x += 0.00; water.rotation.y += 0.00; water.rotation.z += 0.01; renderer.render( scene, camera ); }; animate(); </script> </body> </html>
错误原因
- 模块映射未生效且混合引入冲突:配置了
importmap却未用模块名引入依赖,反而用绝对路径导入Three.js和Water.js。Water.js内部依赖three模块名,浏览器无法解析该非相对路径的模块,触发错误。 - 冗余且错误的CDN脚本:引入的CDN版Three.js是全局脚本,与ES模块环境冲突;OrbitControls用的是
examples/js下的非模块版本,不兼容模块导入规则。 - HTML语法错误:存在多余的
</script>标签,干扰脚本解析流程。
解决方法
1. 修复语法与清理冗余代码
删除多余的</script>标签,移除所有CDN引入的脚本,统一使用本地模块。
2. 完善importmap配置
更新importmap,加入Water.js的映射,确保所有依赖模块都能通过模块名解析:
<script type="importmap"> { "imports": { "three": "./build/three.module.js", "three/addons/controls/OrbitControls.js": "./jsm/controls/OrbitControls.js", "three/addons/objects/Water.js": "./jsm/objects/Water.js" } } </script>
3. 修改模块引入方式
用模块名代替绝对路径导入依赖:
import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { Water } from 'three/addons/objects/Water.js';
4. 修正OrbitControls实例化代码
模块导入的OrbitControls不属于THREE的属性,直接使用导入的类:
const controls = new OrbitControls(camera, renderer.domElement);
5. 验证本地文件路径
确保build/three.module.js、jsm/controls/OrbitControls.js、jsm/objects/Water.js的相对路径与HTML文件匹配,比如HTML在项目根目录时,上述路径需对应正确的本地文件位置。
内容的提问来源于stack exchange,提问作者Cambria
相关产品推荐
相关产品推荐

