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

What is the correct path of "renderer/public"? #23

Open
immafrady opened this issue Sep 19, 2022 · 12 comments
Open

What is the correct path of "renderer/public"? #23

immafrady opened this issue Sep 19, 2022 · 12 comments

Comments

@immafrady
Copy link
Contributor

so i'm adding an 404.png in renderer/public,
and using it like src="/404.png"

it worked at develop mode, but failed to load at prod mode.

image

it seems like after build at prod mode, the resource path become strange
image

@Deluze
Copy link
Owner

Deluze commented Sep 19, 2022

Interesting, looking at your build directory it should find the 404.png on /404.png.

What is being logged to the console? Are you getting a 404 from the network?
Did you modify electron-builder.json config?

Path looks fine to me, why do you think it's strange?

@Deluze
Copy link
Owner

Deluze commented Sep 19, 2022

I tried this on my Windows & Mac system to be sure, but can't seem to reproduce.

@Deluze Deluze added bug Something isn't working help wanted Extra attention is needed labels Sep 21, 2022
@immafrady
Copy link
Contributor Author

I'm sorry for being busy and then forgot to reply.🥵

I've cloned a new project and try to reproduce the problem, and it seems ok.

I need to find the difference between your project and mine.

Thanks anyway😌

@dss886
Copy link

dss886 commented Jan 23, 2024

@Deluze hi, I got the same problem.

I have a google.png image in the src/renderer/public/ dir, and using it like /google.png in my vue file.

Everything works fine when in develop mode, but got an error when build to zip on Windows.

image

The /google.png seems to be directed to the root directory like file:///D:/google.png (while my program is unpacked to the D:/Software/xxx).

Any help would be greatly appreciated!

@Deluze
Copy link
Owner

Deluze commented Jan 23, 2024

Hey @dss886, what's your Vite config like? The default svg icons that come with this project work fine on my end.

What commands are you running?

@dss886
Copy link

dss886 commented Jan 23, 2024

@Deluze Hey,

vite.config.js:

const Path = require("path");
const vuePlugin = require("@vitejs/plugin-vue");

const { defineConfig } = require("vite");

/**
 * https://vitejs.dev/config
 */
const config = defineConfig({
    root: Path.join(__dirname, "src", "renderer"),
    publicDir: "public",
    server: {
        port: 8080,
    },
    open: false,
    build: {
        outDir: Path.join(__dirname, "build", "renderer"),
        emptyOutDir: true,
        rollupOptions: {
            input: {
                main: Path.join(__dirname, "src", "renderer", "index.html"),
                hardware: Path.join(__dirname, "src", "renderer", "plugins", "hardware", "index.html"),
                spotlight: Path.join(__dirname, "src", "renderer", "plugins", "spotlight", "index.html"),
            }
        }
    },
    plugins: [vuePlugin()],
});

module.exports = config;

Build Command: node scripts/build.js && electron-builder --win zip:x64

Build result is a zip file. After unzip is like:

20240123163450

Unzip the app.asar file:

image

@Deluze
Copy link
Owner

Deluze commented Jan 23, 2024

@dss886 The directory tree in your last screenshot looks correct. Vite's behavior is to pull any file from the public dir into the build root (which is renderer).

I tried to reproduce it on my Linux environment by packing up the build in a tar, deb and snap package but can't seem to reproduce.

Could you create a minimal repo to reproduce this issue? @dss886
I'll try it on my Windows environment at a later time.

@Deluze Deluze reopened this Jan 23, 2024
@dss886
Copy link

dss886 commented Jan 24, 2024

Hi @Deluze, I found the problem, but haven't solved it yet.

I have a vue component named ListItem, which accept props like:

interface Props {
    icon: string;
    title: string;
    subtitle?: string;
}
withDefaults(defineProps<Props>(), {
    icon: "",
    title: "",
    subtitle: "",
});

App.vue pass the name of icon to the ListItem component:

<ListItem 
  v-for="(item, index) in itemList"
  :key="item.title"
  :icon="item.icon" 
  :title="item.title" 
/>

But the item.icon is the filename of images in public directory (like 'google.png'), and I concat the src attribute of manually, which is the problem:

<img 
    v-if="icon !== ''" 
    :src="'/' + icon"
    class="icon"
>

I tried removing string concat and passing the /google.png directly, but didn’t work either. It seems that the src only written directly in the vue file can be converted correctly.

Do you have any suggestions? 😨

PS: You may want to check the minimal bug repo: https://github.com/dss886/electron-vue-troubleshooting

@Deluze
Copy link
Owner

Deluze commented Jan 26, 2024

Thanks @dss886 I'll take a look this weekend

@tob-at-lovelace
Copy link

Hi all. Maybe this is unrelated, but I was hitting this exact problem with code that I was porting over.

I'm using this template with Vuetify. I just cloned this template and added Vuetify, as described here.

At that point if you just try a trivial change to App.vue you can experience this firsthand. I added a single Vuetify image:

<template>
  <v-app>
    <v-img :width="60" src="/vue.svg"></v-img>
    <div>
      <a href="https://vitejs.dev" target="_blank">
        <img src="/logomark_white.png" class="logo" alt="Vite logo" />
      </a>
      <a href="https://vuejs.org/" target="_blank">
        <img src="/vue.svg" class="logo vue" alt="Vue logo" />
      </a>
    </div>
    <HelloWorld msg="Vite + Vue" />
  </v-app>
</template>

So this code is in the same file, using the same image, as the code that works. The above will work with an npm run dev but if you build it with npm run build the resulting binary won't draw the Vuetify image.

Thanks to running into something similar in the past, I tried changing the file path from /vue.svg to ./vue.svg and it works as expected.

Maybe this will help someone else who happens upon this thread.

@Deluze
Copy link
Owner

Deluze commented Apr 21, 2024

To add some more information to this thread, it's difficult to use the public directory on dynamically resolved paths (or the lack thereof).

There's a big difference when it comes to fetching resources from your dev server, compared to the final build.

Dev Server
The Vite server will be able to intercept the request to /image.png, and respond with the contents of <project>/public/image.png. This works as intended.

Building your app
During build time, Vite will transform a snippet like

<img src="/image.png">

into

<img src="/absolute/path/to/image.png">

This is because there is of course no web server running on the host's machine. Instead, all resources need to be loaded directly from the filesystem.

Runtime computed filepaths
There's a big caveat when it comes to src paths being computed on run-time.

Imagine the following snippet:

<script setup>
const filename = new Date().getDay() & 1 ? 'vite.svg' : 'vue.svg';
</script>

<template>
  <img :src=`/${filename}`>
</template>

Vite will not transform /${filename} into the absolute path during build time.
The file URL will be something like: file:///vite.svg instead.

I'm not sure if there's a Vite option that will always inject the full path when there's a string starting with / in certain contexts. Maybe someone else wrote a plugin for that, but I think it is pretty difficult to do, if not impossible to do it correctly.


So... are there any other solutions? Yes!

In case you have some icons that you want to show depending on the users device for example:

import androidIconPath from './icons/android.svg';
import appleIconPath from './icons/apple.svg';

<script setup>
const iconPath = 2 > 5 ? androidIconPath : appleIconPath; // silly example
</script>

<template>
  <img :src="iconPath"> <!-- This will work on both dev server and final build! -->
</template>

I can believe this can become pretty cumbersome if you have 1000 icons.
In that case, there might be some more fitting options for you: https://vitejs.dev/guide/assets.html#new-url-url-import-meta-url
I think this solution is similar to what @tob-at-lovelace posted.

To conclude, I don't think this is an issue that has something to do with this template specifically.
I think I will leave this issue open to continue discussion and have it open for discoverability.

I don't really maintain this template any more as I'm not using Electron at all at the moment.
If anyone has any suggestions on how to improve the template and how to streamline the behavior between the dev server and the packaged build, suggestions and contributions are always welcome 😄

@Deluze Deluze removed the bug Something isn't working label Apr 21, 2024
@Deluze Deluze pinned this issue Apr 21, 2024
@dss886
Copy link

dss886 commented Apr 30, 2024

Sorry for the late reply to this post. My solution at that time was indeed similar to the ones of @tob-at-lovelace , which using the relative paths. And I did the path-compute job like:

const iconPath = computed(() => {
    if (import.meta.env.DEV) {
        return `/${props.icon}`;
    } else {
        // after packed, we are in renderer/plugins/xxx/
        return `../../${props.icon}`;
    }
});

But the solution of @Deluze is new knowledge to me and looks more elegant, I will learn and use it later!

Thanks all, I'm really appreciate about it. @tob-at-lovelace @Deluze

@Deluze Deluze removed the help wanted Extra attention is needed label May 10, 2024
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

4 participants