Electron-React-Typescript-Webpack打包后动态加载图片异常求助
我用Electron + React + Webpack + TypeScript做大学项目,复刻Jeopardy游戏。游戏依赖JSON格式的场景文件运行,场景中包含图片资源,为了避免每次修改场景都重新构建应用,需要实现图片和场景的动态加载。
实际表现
开发环境下,把图片放在指定文件夹,通过require.context按文件名加载完全正常。但应用打包后,所有图片被转移到resources\app\.webpack\renderer\目录,文件名被替换成哈希值(例如f9cbb866db6c9b73d628c76a72d55bc7.jpg),导致原来的动态加载代码失效,图片无法正常显示。
预期表现
打包后的图片保留原文件名,存放在指定的独立文件夹中,这样修改图片或场景中的引用时,无需重新构建应用。
代码示例
加载图片的代码:
function importAll(r: any) { let images = {}; // @ts-ignore r.keys().map((item: string, index: any) => { images[item.replace('./', '')] = r(item); }); return images; } // @ts-ignore const images = importAll(require.context("../assets", false, /\.(png|jpe?g|svg)$/));
渲染图片的代码:
<img src={images[this._question.imagePath].default}></img>
1. 修改Webpack配置,保留图片原文件名
调整Webpack中处理图片资源的规则,关闭哈希命名并指定输出目录:
module.exports = { // 其他Webpack配置... module: { rules: [ // 其他loader规则... { test: /\.(png|jpe?g|svg)$/i, type: 'asset/resource', generator: { filename: 'assets/[name][ext]' // 保留原文件名,输出到assets子目录 } } ] } };
如果使用的是旧版Webpack的file-loader,配置如下:
{ test: /\.(png|jpe?g|svg)$/i, use: [ { loader: 'file-loader', options: { name: 'assets/[name][ext]', outputPath: 'assets/' } } ] }
2. 配置Electron打包工具(electron-builder)
在项目的package.json中添加build字段,将assets文件夹标记为额外资源,确保打包时直接复制到应用根目录:
{ "build": { "extraResources": [ { "from": "src/assets/", "to": "assets/" } ] } }
这样打包后,图片会被放在应用根目录的assets文件夹下,而非Webpack编译后的内部目录。
3. 调整图片加载逻辑
不再依赖require.context,改为通过Electron的路径API获取资源目录,动态加载图片:
主进程配置
import { app, BrowserWindow, ipcMain } from 'electron'; import { join } from 'path'; let mainWindow: BrowserWindow | null; app.on('ready', () => { mainWindow = new BrowserWindow({ // 窗口配置... webPreferences: { nodeIntegration: true, // 若Electron版本低于12,需开启;高版本建议用contextBridge contextIsolation: false } }); // 向渲染进程发送assets目录路径 const assetsPath = join(app.getAppPath(), 'assets'); mainWindow.webContents.send('assets-path', assetsPath); });
渲染进程代码
import { ipcRenderer } from 'electron'; let assetsPath: string; // 接收主进程发送的assets路径 ipcRenderer.on('assets-path', (_, path) => { assetsPath = path; }); // 渲染图片时使用本地文件路径 <img src={`file://${assetsPath}/${this._question.imagePath}`} alt="" />
如果是高版本Electron,建议使用contextBridge暴露路径,避免开启nodeIntegration:
// 主进程preload脚本 import { contextBridge, ipcRenderer } from 'electron'; contextBridge.exposeInMainWorld('electronAPI', { getAssetsPath: () => ipcRenderer.invoke('get-assets-path') }); // 主进程 ipcMain.handle('get-assets-path', () => join(app.getAppPath(), 'assets')); // 渲染进程 const assetsPath = await window.electronAPI.getAssetsPath(); <img src={`file://${assetsPath}/${this._question.imagePath}`} alt="" />
4. 验证动态修改效果
打包完成后,直接替换assets文件夹中的图片或修改JSON场景文件,重启游戏即可生效,无需重新构建应用。
内容的提问来源于stack exchange,提问作者esperor

