Vite + React 中静态资源动态访问
Vite React 中静态资源动态访问本文基于Vite React 实现静态图片的动态访问说明在 Vite 项目中如何安全地按业务字段动态展示多张本地 PNG并记录常见踩坑与最终写法。一、业务诉求图标文件按约定放在src/assets/下命名为icon-{code}.png例如icon-1.png、icon-2.png。数据侧通过code区分类型需要在运行时根据 code 选中对应图片但图片集合在构建时已确定不会从 CDN 任意拼接未知路径。二、为什么new URL 模板字符串往往行不通常见尝试constfileNameicon-1;consticonnewURL(/assets/${fileName}.png,import.meta.url);在 Vite 中new URL(第一个参数, import.meta.url)要求第一个参数在编译期可被静态分析为确定资源路径打包器才能把文件纳入依赖并生成正确的 hash URL。一旦路径里出现运行时变量如${fileName}Vite 无法枚举具体文件可能出现资源未被打进产物或别名未在该场景下解析浏览器请求到错误路径。因此「构建期固定」不等于可以用任意字符串拼路径仍需要让构建器在编译期枚举出所有候选文件。三、推荐方案import.meta.glob预加载 运行时查表Vite 提供import.meta.glob在模式字符串保持静态的前提下构建阶段会扫描匹配到的所有模块运行时只需根据fileName在返回的Record里查找即可。核心实现如下const PaletteItem ({ item }) { const iconModules import.meta.glob(/assets/*.png, { eager: true, query: ?url, import: default, }) as Recordstring, string; const getIconUrl (fileName: string) { const key Object.keys(iconModules).find((k) k.endsWith(${fileName}.png)); return key ? iconModules[key] : ; }; const iconUrl getIconUrl(icon-${item.code}); return ( div className{/* ... */} img src{iconUrl} alt / /div ); };要点说明点说明glob模式/assets/*.png为字面量构建期可枚举目录下全部 pngquery: ?url将资源解析为 URL 字符串适合img srceager: true同步打包进当前 chunk避免异步import()的额外分支组件库图标数量可控时很合适import: default让每个匹配项的值直接为string URL而不是{ default: string }的模块对象避免img src{模块对象} /触发 React 警告四、踩坑记录src收到Module类型若仅使用eager: truequery: ?url未设置import: default运行时得到的往往是{default:/xxx/src/assets/.../icon-area.png?t...}若误把该对象传给img src{...} /会出现类似警告The providedsrcattribute is an unsupported type Module. This value must be coerced to a string…处理方式二选一加上import: defaultglob 结果为Recordstring, string推荐或类型声明为Recordstring, { default: string }取iconModules[key].default。新增组件类型时只需在components目录增加对应 png无需改glob模式。五、小结动态路径若交给new URL(\…${var}…)容易脱离 Vite 静态分析导致资源丢失或路径错误。构建期固定、运行期选择应使用import.meta.glob静态枚举 运行时按 key/endsWith查找。使用query: ?url时注意返回值是字符串还是{ default }用import: default或显式取.default保证img src始终是字符串。