Description
I'm creating a replica of the "Jeopardy" game for my college project and chose Electron React Webpack in typescript for it. The game is going to need a scenario (made it in .json) to play and the scenario usually involves some images. Obviously, it's better to load the scenarios dynamically so that I don't need to rebuild whole app for every scenario. Therefore I need to load images dynamically as well.
Actual behaviour
I made everything work in the dev env so that I put the images in a folder and then load them by name via require.context
. But after the app is packaged, I find that all of the images were moved to resources\app\.webpack\renderer\
and their names were changed like that: f9cbb866db6c9b73d628c76a72d55bc7.jpg
. So, I believe, all of my code was just optimized away so that the images are static now.
Expected behaviour
Images after packaging should stay in some folder with old names so that I can change both the images and references in the scenario.
Code
This is for loading:
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)$/));
This is for representing:
<img src={images[this._question.imagePath].default}></img>
CodePudding user response:
I managed to solve it using some official documentation:
First of all, I changed the way the program loads the images: now there is a button to pick a directory and a button to pick the scenario file. After this is done, the program evaluates content of picked directory:
That is how you pick a directory:
// @ts-ignore
this.assetsDIR = await window.showDirectoryPicker();
This is the evaluation:
// @ts-ignore
for await (const entry of this.props.assetsDIR.values()) {
entry.getFile().then((val: any) => {
this._assets.set(val.name, URL.createObjectURL(val));
});
}
Now I have all the images' URLs in the map with their names as the keys. After this is done I can just use the name of the image to get it from the map:
<img src={this._assets.get(this._question.imagePath)} />
This seemed perfect, but I ran into a problem with the security policy which didn't let me load the image, so I added this line in the forge.config.ts
file:
devContentSecurityPolicy: `default-src * self blob: data: gap:; style-src * self 'unsafe-inline' blob: data: gap:; script-src * 'self' 'unsafe-eval' 'unsafe-inline' blob: data: gap:; object-src * 'self' blob: data: gap:; img-src * self 'unsafe-inline' blob: data: gap:; connect-src self * 'unsafe-inline' blob: data: gap:; frame-src * self blob: data: gap:;`,
The line is from the answer to issue on GitHub: https://github.com/electron/forge/issues/2331 and should be placed like that:
const config: ForgeConfig = {
packagerConfig: {},
rebuildConfig: {},
makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})],
plugins: [
new WebpackPlugin({
devContentSecurityPolicy: `default-src * self blob: data: gap:; style-src * self 'unsafe-inline' blob: data: gap:; script-src * 'self' 'unsafe-eval' 'unsafe-inline' blob: data: gap:; object-src * 'self' blob: data: gap:; img-src * self 'unsafe-inline' blob: data: gap:; connect-src self * 'unsafe-inline' blob: data: gap:; frame-src * self blob: data: gap:;`,
mainConfig,
renderer: {
config: rendererConfig,
entryPoints: [
{
html: './src/index.html',
js: './src/renderer.ts',
name: 'main_window',
preload: {
js: './src/preload.ts',
},
},
],
},
}),
],
};
Also I move assets folder from the workspace folder in User's documents so that the compiler and builder don't see them and don't optimize them. Thanks to @Alexander Leithner for the help