如何在Rails 7(esbuild)的JSX中引用Rails图片资源?
在使用jsbundling-rails搭配esbuild处理JSX代码时,你会发现JSX里的资源路径无法像cssbundling-rails那样自动被替换为带哈希的完整路径。比如你当前的代码:
<img src={`zone_icons/${zone}.png` }/>
这里的路径不会被处理,导致资源无法正确加载(尤其是开启资源哈希化后),又不想把资源放在/public目录下,以下是几个可行的解决方案:
用esbuild插件处理资源打包与哈希
借助esbuild的第三方插件,比如esbuild-plugin-copy或esbuild-plugin-assets-manifest,配置后让esbuild在打包时自动处理图片资源,生成带哈希的文件名并生成资源映射表。
示例配置(esbuild.config.js):const esbuild = require('esbuild'); const copyPlugin = require('esbuild-plugin-copy'); esbuild.build({ entryPoints: ['app/javascript/application.js'], bundle: true, outdir: 'app/assets/builds', plugins: [ copyPlugin({ assets: [ { from: ['app/javascript/zone_icons/**/*'], to: ['zone_icons/[name]-[hash].[ext]'] } ], manifest: { filename: 'asset-manifest.json', path: './app/assets/builds' } }) ] });打包后会生成
asset-manifest.json,在JSX里引入这个manifest文件,通过键值对获取哈希后的路径:import manifest from '../assets/builds/asset-manifest.json'; <img src={manifest[`zone_icons/${zone}.png`]} />通过Rails视图传递asset pipeline生成的路径
利用Rails原生的asset pipeline辅助方法,在erb视图中把资源基础路径注入到全局变量,再在JSX里使用:<%= javascript_tag do %> window.railsAssetPaths = { zoneIcons: "<%= asset_path('zone_icons/') %>" }; <% end %>然后在JSX中:
<img src={`${window.railsAssetPaths.zoneIcons}${zone}.png`} />这种方式完全依赖Rails的asset pipeline处理哈希,不需要额外配置esbuild,适合不想折腾插件的场景。
直接import图片资源
把图片放在app/assets/images/zone_icons/目录下,在JSX里通过import引入(动态导入需esbuild支持):// 静态导入示例 import zoneA from 'assets/images/zone_icons/zone_a.png'; <img src={zoneA} /> // 动态导入示例(处理动态zone值) const loadZoneIcon = async (zone) => { const iconModule = await import(`assets/images/zone_icons/${zone}.png`); return iconModule.default; }; // 在组件中使用 const [iconSrc, setIconSrc] = useState(''); useEffect(() => { loadZoneIcon(zone).then(src => setIconSrc(src)); }, [zone]); <img src={iconSrc} />这种方式让esbuild将图片作为打包依赖,自动处理哈希和路径,注意需要在esbuild配置中正确设置resolve路径,确保能找到
assets/images目录。
内容的提问来源于stack exchange,提问作者pixelearth

