Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Images not showing up in output folder #452

Open
zachwvk opened this issue Aug 19, 2021 · 1 comment
Open

Images not showing up in output folder #452

zachwvk opened this issue Aug 19, 2021 · 1 comment

Comments

@zachwvk
Copy link

zachwvk commented Aug 19, 2021

  • Electron Webpack Version: 2.8.2
  • Target: Windows

I've spent a more than a day debugging why my images and sound files were accessible in development but did not appear in the dist folder. Finally I have a "Fix" which is working for me, but I don't understand why is was necessary. Bellow is what I put into my webpack.renderer.js file.

Can anyone explain why the "url-loader" was being used for sound and image files? I'm not experienced in any of this, but because I had this issue is seems to me that this is a bug in electron webpack?

//webpack.renderer.js

var webpack = require('webpack')
fs = require('fs');

function replacer(key, value) {
  //RegExp would not print in a useful way without this
  if (value instanceof RegExp) {
    return value.toString();
  }
  return value;
}

module.exports = function(config) 
{
  fs.writeFileSync("webpack.renderer.before.js", JSON.stringify(config, replacer, 4));

  // replace image loader rules
  config.module.rules[6] = {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      use: {
          loader: 'file-loader',//"url-loader", why was this the default?
          options: {
              //limit: 10240,
              name: "imgs/[name]--[folder].[ext]"
          }
      },
  }
  // replace sound loader rules
  config.module.rules[7] = {
      test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
      use: {
          loader: 'file-loader',//"url-loader", why was this the default?
          options: {
              //"limit": 10240,
              name: "media/[name]--[folder].[ext]"
          }
      },
  }

  fs.writeFileSync("webpack.renderer.after.js", JSON.stringify(config, replacer, 4));

  return config
}
@loopmode
Copy link
Collaborator

loopmode commented Aug 20, 2021

Hi.

The url-loader works something like this: "if the file is smaller than the limit, behave just like file-loader and bundle the file into the javascript bundle. if the file is bigger, leave it as-is and load it at runtime".
(see "url-loader works like file-loader, but can return a DataURL if the file is smaller than a byte limit." at https://v4.webpack.js.org/loaders/url-loader/)
The reason for this is that base64 will always be at least 33% larger (more bytes) than the original, see https://developer.mozilla.org/en-US/docs/Glossary/Base64#encoded_size_increase, and especially in web apps, you won't see anything until the full bundle is loaded, parsed etc. You're slowing down the start and execution of your actual javascript etc.

What you have done now is definitely bundle it into the javascript by using file-loader, always making a base64.
This works in your case, but you produce very large bundles that need to be parsed, which hits on the performance at some point.

The way you should handle this in electron-webpack is using the "static assets" feature: https://webpack.electron.build/using-static-assets
However this comes with its own set of quirks.
The idea is: Any files that are not code should not be part of code bundles. Instead they should be treated as static files ("as-is", no costly processing by webpack).
So you would place your files into a folder "static" in your project (next to your src, not inside of it!). When building your app for production, this folder will be simply copied into the resulting "asar" file (the archive used by electron/chromium to contain your app).
In your code, you would use the magic global __static provided by electron-webpack when referencing those files, The __static global is supposed to give you the correct path to your static asset.
However, aas you can find out by searching for "static" in the issues here, it's .. somewhat buggy, or at least it doesn't provide out-of-the-box handling for both development and production.
But you could use a helper like this one:

import path from "path";
import * as url from "url";

const isDevelopment = process.env.NODE_ENV !== "production";

// see https://github.com/electron-userland/electron-webpack/issues/241#issuecomment-582920906
export default function getStatic(relativePathToAsset = "") {
  if (isDevelopment) {
    return url.resolve(window.location.origin, relativePathToAsset);
  }
  return path.resolve(__static, relativePathToAsset);
}

// e.g. react <audio src={ getStatic('sounds/sound.mp3') } />
// e.g. js document.write(`<img class="logo" src="${getStatic("electron.png")}" />`);

What it does is: In development, it returns a URL (with http: etc) pointing to the file as hosted by webpack-dev-server, and at production, it returns a local file: path to file inside aforementioned asar file, at the installed location of your app.

Sounds complicated, but I totally recommend doing it that way, and reverting your changes up there.
The files in your case are definitely static assets and should be treated as such. This is also the only scalable way. If you keep your config and bundle them into the source, the development process will become slower and slower, as webpack has to process all those files (maybe 100x, maybe 1000x more bytes than your actual code...)

You should check out this example project i set up once: https://github.com/loopmode/electron-webpack-static-examples
It showcases a couple ways of using static files with electron-webpack practically, working around quirks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants