Grafana面板插件使用ThreeJS加载.gltf文件出现404错误求助
在Grafana面板插件中加载ThreeJS GLTF模型的404问题解决
问题概述
开发Grafana面板插件时,尝试通过ThreeJS加载.gltf模型文件,已将模型置于src文件夹并在src/components/SimplePanel.tsx中引用,但始终出现GET请求404错误。Three依赖已正确安装,面板能显示Three默认黑屏,核心问题为资源路径或打包配置错误。
错误日志
threejs-panel | logger=context userId=0 orgId=1 uname= t=*** level=info msg="Request Completed" method=GET path=/api/live/ws status=-1 remote_addr=172.18.0.1 time_ms=0 duration=693.968µs size=0 referer= handler=/api/live/ws
当前代码与配置
SimplePanel.tsx
import React, { useEffect, useRef } from 'react'; import { PanelProps } from '@grafana/data'; import { SimpleOptions } from 'types'; import * as THREE from 'three'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; interface Props extends PanelProps<SimpleOptions> {} export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) => { const containerRef = useRef<HTMLDivElement>(null); useEffect(() => { if (!containerRef.current) return; const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); const loader = new GLTFLoader(); renderer.setSize(width, height); containerRef.current.appendChild(renderer.domElement); loader.load('./src/Blackhawk.gltf', (gltf) => { const model = gltf.scene; model.scale.set(0.1, 0.1, 0.1); scene.add(model); // Adjust camera position const box = new THREE.Box3().setFromObject(model); const size = box.getSize(new THREE.Vector3()); const center = box.getCenter(new THREE.Vector3()); const maxDim = Math.max(size.x, size.y, size.z); const fov = camera.fov * (Math.PI / 180); let distance = maxDim / (2 * Math.tan(fov / 2)); distance += maxDim * 0.25; camera.position.copy(center); camera.position.z += distance; camera.lookAt(center); // Optional: Add lighting to the scene const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(5, 5, 5); scene.add(directionalLight); function animate() { requestAnimationFrame(animate); renderer.render(scene, camera); } animate(); }); }, []); return ( <div ref={containerRef} style={{ width: '100%', height: '100%', overflow: 'hidden' }} ></div> ); };
Webpack.config.ts相关片段
test: /\.(png|jpe?g|gif|svg|gltf)$/, type: 'asset/resource', generator: { // Keep publicPath relative for host.com/grafana/ deployments publicPath: `public/plugins/${getPluginId}/img/`, outputPath: 'img/', filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]', },
遇到的额外问题
- 运行dev脚本时,.gltf文件未被打包到dist文件夹
- 曾成功打包出两个文件:
dist/img/2efghij3***.gltf和dist/9dbql***.gltf(后者引用前者),但仍无法加载
解决步骤
1. 调整资源存放位置
将.gltf模型及关联资源(如.bin、纹理图)移至插件根目录的public/img文件夹。Grafana插件默认从public目录加载静态资源,此位置能确保Webpack正确识别并打包资源。
2. 更新Webpack配置
添加对.bin文件的支持(GLTF模型常包含二进制数据),修改规则如下:
test: /\.(png|jpe?g|gif|svg|gltf|bin)$/, type: 'asset/resource', generator: { publicPath: `public/plugins/${getPluginId}/img/`, outputPath: 'img/', filename: Boolean(env.production) ? '[hash][ext]' : '[name][ext]', },
3. 修正模型加载路径
使用Grafana提供的getPluginUrl方法获取插件基础URL,避免硬编码相对路径:
- 首先导入方法:
import { getPluginUrl } from '@grafana/runtime'; - 修改loader.load的路径:
const modelUrl = `${getPluginUrl()}/img/Blackhawk.gltf`; loader.load(modelUrl, (gltf) => { // 原有模型处理逻辑保持不变 });
4. 重新构建与验证
- 删除dist文件夹,清理旧构建产物
- 运行dev或build命令,确认模型及关联资源被打包到
dist/img目录 - 重启Grafana容器,刷新面板验证模型是否加载成功
内容的提问来源于stack exchange,提问作者zebedee freeman
相关产品推荐
相关产品推荐

