Skip to content

Instantly share code, notes, and snippets.

@bbudd
Created June 13, 2019 12:30
Show Gist options
  • Star 43 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bbudd/2a246a718b7757584950b4ed98109115 to your computer and use it in GitHub Desktop.
Save bbudd/2a246a718b7757584950b4ed98109115 to your computer and use it in GitHub Desktop.
Loading static assets using electron-forge v6 and the webpack plugin

I spent a few hours chasing down just how to get my static assets (css, fonts, images) to load in an Electron app built using electron-forge v6 (https://www.electronforge.io/) and its webpack plugin (https://www.electronforge.io/config/plugins/webpack) while in development mode. There really isn't any documentation available online, either in the electron-forge documentation or in places like blogs or gists or stackoverflow. So I thought I'd put it down here.

Step 1

Load CopyWebpackPlugin npm i -D copy-webpack-plugin


Step 2

Use the plugin to move your directories into place.

It's important that they be at bare minimum in .webpack/renderer, since that is the root used for localhost

webpack.renderer.config.js

const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const assets = [ 'img', 'css', 'fonts' ]; // asset directories

module.exports = {
  // Put your normal webpack config below here
  module: {
    rules: require('./webpack.rules'),
  },
  plugins: assets.map(asset => {
    return new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, 'src', asset),
        to: path.resolve(__dirname, '.webpack/renderer', asset)
      }
    ]);
  })
};

Step 3

IMPORTANT: Access files with absolute paths

Files without absolute paths do not appear to work, even when everything is relatively placed.

index.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="/css/main.css">
  </head>
  <body>
    <img src="/img/img_src.png" />
    <p style="font-family: MyFancyFont, sans-serif;">👆 that's an image!</p>
  </body>
</html>
@johannesgiani
Copy link

Another way could be to use webpack file-loader. I use it to import icons in the main process but that should work for a renderer as well.

Given a /src/renderer.ts/js and /assets/icon.png:

import icon from '../assets/icon.png';

add a rule in webpack.rules.js:

//...
  {
    test: /\.png$/,
    use: {
      loader: 'file-loader',
    }
  }
//...

@nkallen
Copy link

nkallen commented Apr 9, 2021

I've got this working in both dev and prod using file-loader. Here's what I've done:

webpack.renderer.config

rules.push({
    test: /\.(png|jpg|svg|jpeg|gif)$/i,
    use: [
        {
            loader: 'file-loader',
            options: {
                name: 'img/[name].[ext]',
                publicPath: '../.'
            }
        },
    ],
});

I needed to set publicPath because in prod files are relative to your entryPoints.name (which is "main_window" by default with electron-forge) but the asset files are copied into render not render/main_window

In a random js/ts file:

import porcelain from './img/matcap-porcelain-white.jpg';

And my file is located in '/src/img/matcap-porcelain-white.jpg

@jin-yee
Copy link

jin-yee commented Apr 20, 2021

Thanks for the help!

It works fine, for npm 7 and later please downgrade the npm to 6 and copyWebpackPlugin please use the following configuration:

 plugins: assets.map(asset => {
    return new CopyWebpackPlugin(
      {
        patterns: [
          {
            from: path.resolve(__dirname, asset),
            to: path.resolve(__dirname, '.webpack/renderer', asset)
          }
        ]
      }
    );
  })

@DK013
Copy link

DK013 commented Jun 19, 2021

I've got this working in both dev and prod using file-loader. Here's what I've done:

webpack.renderer.config

rules.push({
    test: /\.(png|jpg|svg|jpeg|gif)$/i,
    use: [
        {
            loader: 'file-loader',
            options: {
                name: 'img/[name].[ext]',
                publicPath: '../.'
            }
        },
    ],
});

I needed to set publicPath because in prod files are relative to your entryPoints.name (which is "main_window" by default with electron-forge) but the asset files are copied into render not render/main_window

In a random js/ts file:

import porcelain from './img/matcap-porcelain-white.jpg';

And my file is located in '/src/img/matcap-porcelain-white.jpg

This really did wonders. Thanks Mate !!

@anztrax
Copy link

anztrax commented Aug 20, 2021

This is awesome it worked wonders for me, the only issue I had was using a newer version of copy-webpack-plugin so I had to use a slightly different way to wrap it:

const copyPlugins = assets.map((asset) => {
  return new CopyWebpackPlugin({
    patterns: [{ from: path.resolve(__dirname, 'src', asset), to: asset }],
  });
});

it requires the patterns wrapping now and then it works this was very helpful

thanks bro this works for me 👍

@AlexPasharin
Copy link

Thanks, you are live saver!!!

@Daveiano
Copy link

Daveiano commented Feb 18, 2022

Thank you very much!

EDIT: While this works in development, it does not work in production? Am I missing something?

@sharkrice
Copy link

Thank you very much!

@smarthug
Copy link

Thank you! It works!!

@JamesGrom
Copy link

@bbudd - thank you so much for sharing this

@acequants
Copy link

@a358003542
Copy link

Here is my solution:

webpack.renderer.config.js

const rules = require('./webpack.rules');

const CopyPlugin = require("copy-webpack-plugin");
rules.push({
  test: /\.css$/,
  use: [{ loader: 'style-loader' }, { loader: 'css-loader' }],
});

module.exports = {
  // Put your normal webpack config below here
  module: {
    rules,
  },
  plugins: [
    new CopyPlugin({
      patterns: [
        { from: 'resources/images', to: 'main_window/static/images' },
      ],
    }),
  ]
};

use copy-webpack-plugin copy the image file to the .webpack/renderer and the main_window .

and use like this to reference the image file:

        let image_src = `../main_window/static/${LatexSettings[button_key]["button_image"]}`

notice the .. double dot symbole, when in the npm start devserver it useless, but can work out. and in the package mode, the double dot symbole is very critical.

@rodolfojnn
Copy link

Thank you very much!

EDIT: While this works in development, it does not work in production? Am I missing something?

In production, images are bundled within resources/app.asar.
Try referencing the image in your HTML like this:

<img src="../img/img_src.png" />

This should ensure it works both in development and in production.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment