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

The 'path' argument must be of type string. Received undefined #3578

Open
3 tasks done
a1392136 opened this issue Apr 26, 2024 · 2 comments
Open
3 tasks done

The 'path' argument must be of type string. Received undefined #3578

a1392136 opened this issue Apr 26, 2024 · 2 comments

Comments

@a1392136
Copy link

a1392136 commented Apr 26, 2024

Pre-flight checklist

  • I have read the contribution documentation for this project.
  • I agree to follow the code of conduct that this project uses.
  • I have searched the issue tracker for a bug that matches the one I want to file, without success.

Electron Forge version

7.3.1

Electron version

v29.1.6

Operating system

Windows11

Last known working Electron Forge version

No response

Expected behavior

After packaging, the application runs normally

Actual behavior

It can be used normally with electron-forge start before it is packaged.
Startup error after packaging:
uncaught Exception TypeError [ERR_INVALID_ARG_TYPE]: The 'path' argument must be of type string. Received undefined
image

Steps to reproduce

package.json

{
   ...
   "main": ".vite/build/main.js",
   "scripts": {
      "start": "electron-forge start",
      "package": "electron-forge package",
      "make": "electron-forge make",
      "publish": "electron-forge publish",
      "rebuild-sqlite": "npx electron-rebuild -f -w better-sqlite3"
   },
   "devDependencies": {
      "@electron-forge/cli": "^7.3.1",
      "@electron-forge/maker-deb": "^7.3.1",
      "@electron-forge/maker-rpm": "^7.3.1",
      "@electron-forge/maker-squirrel": "^7.3.1",
      "@electron-forge/maker-zip": "^7.3.1",
      "@electron-forge/plugin-auto-unpack-natives": "^7.3.1",
      "@electron-forge/plugin-fuses": "^7.3.1",
      "@electron-forge/plugin-vite": "^7.3.1",
      "@electron-forge/shared-types": "^7.3.1",
      "@electron/fuses": "^1.7.0",
      "@swc/cli": "^0.3.10",
      "@swc/core": "^1.4.8",
      "@types/lodash": "^4.17.0",
      "@types/node": "^20.12.7",
      "@types/react": "^18.2.74",
      "@types/react-dom": "^18.2.23",
      "autoprefixer": "^10.4.19",
      "electron": "29.1.6",
      "electron-playwright-helpers": "^1.7.1",
      "electron-rebuild": "^3.2.9",
      "postcss": "^8.4.38",
      "prettier": "^3.2.5",
      "prettier-plugin-tailwindcss": "^0.5.12",
      "tailwindcss": "^3.4.1",
      "ts-node": "^10.9.2",
      "typescript": "~5.4.3",
      "vite": "^5.2.3"
   },
   "dependencies": {
      "@ant-design/pro-components": "^2.7.1",
      "@emotion/css": "^11.11.2",
      "@radix-ui/react-avatar": "^1.0.4",
      "@radix-ui/react-dialog": "^1.0.5",
      "@radix-ui/react-label": "^2.0.2",
      "@radix-ui/react-menubar": "^1.0.4",
      "@radix-ui/react-select": "^2.0.0",
      "@radix-ui/react-slot": "^1.0.2",
      "@radix-ui/react-tabs": "^1.0.4",
      "@radix-ui/react-tooltip": "^1.0.7",
      "@types/es6-shim": "^0.31.45",
      "@uiw/react-markdown-editor": "^6.1.1",
      "@vitejs/plugin-react": "^4.2.1",
      "antd": "^5.16.0",
      "better-sqlite3": "^9.4.5",
      "class-variance-authority": "^0.7.0",
      "clsx": "^2.1.0",
      "electron-squirrel-startup": "^1.0.0",
      "localforage": "^1.10.0",
      "lucide-react": "^0.364.0",
      "match-sorter": "^6.3.4",
      "react": "^18.2.0",
      "react-dom": "^18.2.0",
      "react-query": "^3.39.3",
      "react-router-dom": "^6.22.3",
      "reflect-metadata": "^0.2.2",
      "sort-by": "^1.2.0",
      "tailwind-merge": "^2.2.2",
      "tailwindcss-animate": "^1.0.7",
      "typeorm": "^0.3.20",
      "vaul": "^0.9.0",
      "zod": "^3.22.4"
   }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "outDir": "dist",
    "module": "commonjs",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "sourceMap": true,
    "jsx": "react",
    "resolveJsonModule": true,
    "strictPropertyInitialization": false,
    "forceConsistentCasingInFileNames": true,
    "allowJs": false,
    "skipLibCheck": true,
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "./src/*"
      ]
    },
    "include": [
      "./src"
    ],
    "exclude": [
      "node_modules"
    ]
  }
}

Additional information

vite.ase.config.ts

import {builtinModules} from "node:module";
import type {AddressInfo} from "node:net";
import type {ConfigEnv, Plugin, UserConfig} from "vite";
import pkg from "./package.json";
import path from "path";

export const builtins = ["electron", ...builtinModules.map((m) => [m, `node:${m}`]).flat()];

export const external = [
    ...builtins,
    ...Object.keys("dependencies" in pkg ? (pkg.dependencies as Record<string, unknown>) : {}),
];

// @ts-ignore
export function getBuildConfig(env: ConfigEnv<"build">): UserConfig {
    const { root, mode, command } = env;

    return {
        root,
        mode,
        build: {
            // Prevent multiple builds from interfering with each other.
            emptyOutDir: false,
            // 🚧 Multiple builds may conflict.
            outDir: ".vite/build",
            watch: command === "serve" ? {} : null,
            minify: command === "build",
        },
        clearScreen: false,
        resolve: {
            alias: {
                "@": path.resolve(__dirname, "./src"),
            },
        },
    };
}

export function getDefineKeys(names: string[]) {
    const define: { // @ts-ignore
        [name: string]: VitePluginRuntimeKeys } = {};

    return names.reduce((acc, name) => {
        const NAME = name.toUpperCase();
        // @ts-ignore
        const keys: VitePluginRuntimeKeys = {
            VITE_DEV_SERVER_URL: `${NAME}_VITE_DEV_SERVER_URL`,
            VITE_NAME: `${NAME}_VITE_NAME`,
        };

        return { ...acc, [name]: keys };
    }, define);
}

// @ts-ignore
export function getBuildDefine(env: ConfigEnv<"build">) {
    const { command, forgeConfig } = env;
    // @ts-ignore
    const names = forgeConfig.renderer.filter(({ name }) => name != null).map(({ name }) => name!);
    const defineKeys = getDefineKeys(names);
    return Object.entries(defineKeys).reduce(
      (acc, [name, keys]) => {
          const {VITE_DEV_SERVER_URL, VITE_NAME} = keys;
          const def = {
              [VITE_DEV_SERVER_URL]:
                command === "serve"
                  ? JSON.stringify(process.env[VITE_DEV_SERVER_URL])
                  : undefined,
              [VITE_NAME]: JSON.stringify(name),
          };
          return {...acc, ...def};
      },
      {} as Record<string, any>
    );
}

export function pluginExposeRenderer(name: string): Plugin {
    const { VITE_DEV_SERVER_URL } = getDefineKeys([name])[name];

    return {
        name: "@electron-forge/plugin-vite:expose-renderer",
        configureServer(server) {
            // @ts-ignore
            process.viteDevServers ??= {};
            // Expose server for preload scripts hot reload.
            // @ts-ignore
            process.viteDevServers[name] = server;

            server.httpServer?.once("listening", () => {
                const addressInfo = server.httpServer!.address() as AddressInfo;
                // Expose env constant for main process use.
                process.env[VITE_DEV_SERVER_URL] = `http://localhost:${addressInfo?.port}`;
            });
        },
    };
}

export function pluginHotRestart(command: "reload" | "restart"): Plugin {
    return {
        name: "@electron-forge/plugin-vite:hot-restart",
        closeBundle() {
            if (command === "reload") {
                // @ts-ignore
                for (const server of Object.values(process.viteDevServers)) {
                    // Preload scripts hot reload.
                    // @ts-ignore
                    server.ws.send({ type: "full-reload" });
                }
            } else {
                // Main process hot restart.
                // https://github.com/electron/forge/blob/v7.2.0/packages/api/core/src/api/start.ts#L216-L223
                process.stdin.emit("data", "rs");
            }
        },
    };
}

vite.main.config.ts

import type { ConfigEnv, UserConfig } from "vite";
import { defineConfig, mergeConfig } from "vite";
import { getBuildConfig, getBuildDefine, external, pluginHotRestart } from "./vite.base.config";
import path from "path";

// https://vitejs.dev/config
export default defineConfig((env) => {
  // @ts-ignore
  const forgeEnv = env as ConfigEnv<"build">;
  const { forgeConfigSelf } = forgeEnv;
  const define = getBuildDefine(forgeEnv);
  const config: UserConfig = {
    build: {
      lib: {
        entry: forgeConfigSelf.entry!,
        fileName: () => "[name].js",
        formats: ["cjs"],
      },
      rollupOptions: {
        external,
      },
    },
    plugins: [pluginHotRestart("restart")],
    define,
    resolve: {
      // Load the Node.js entry.
      mainFields: ["module", "jsnext:main", "jsnext"],
    },
  };

  return mergeConfig(getBuildConfig(forgeEnv), config);
});

vite.preload.config.ts

import type { ConfigEnv, UserConfig } from "vite";
import { defineConfig, mergeConfig } from "vite";
import { getBuildConfig, external, pluginHotRestart } from "./vite.base.config";
import path from "path";

// https://vitejs.dev/config
export default defineConfig((env) => {
  const forgeEnv = env as ConfigEnv<"build">;
  const { forgeConfigSelf } = forgeEnv;
  const config: UserConfig = {
    build: {
      rollupOptions: {
        external,
        // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`.
        input: forgeConfigSelf.entry!,
        output: {
          format: "cjs",
          // It should not be split chunks.
          inlineDynamicImports: true,
          entryFileNames: "[name].js",
          chunkFileNames: "[name].js",
          assetFileNames: "[name].[ext]",
        },

      },
    },
    plugins: [pluginHotRestart("reload")],
  };

  return mergeConfig(getBuildConfig(forgeEnv), config);
});

vite.renderer.config.ts

import path from "path";
import react from "@vitejs/plugin-react";
import type { ConfigEnv, UserConfig } from "vite";
import { defineConfig } from "vite";
import { pluginExposeRenderer } from "./vite.base.config";

// https://vitejs.dev/config
export default defineConfig((env) => {
    // @ts-ignore
    const forgeEnv = env as ConfigEnv<"renderer">;
    const { root, mode, forgeConfigSelf } = forgeEnv;
    const name = forgeConfigSelf.name ?? "";

    return {
        root,
        mode,
        base: "./",
        build: {
            outDir: `.vite/renderer/${name}`,
        },
        plugins: [pluginExposeRenderer(name), react()],
        resolve: {
            preserveSymlinks: true,
            alias: {
                "@": path.resolve(__dirname, "./src"),
            },
        },
        clearScreen: false,
    } as UserConfig;
});

forge.config.ts

import type { ForgeConfig } from "@electron-forge/shared-types";
import { MakerZIP } from "@electron-forge/maker-zip";
import { MakerRpm } from "@electron-forge/maker-rpm";
import { VitePlugin } from "@electron-forge/plugin-vite";
import { FusesPlugin } from "@electron-forge/plugin-fuses";
import { FuseV1Options, FuseVersion } from "@electron/fuses";
import path from "path";
import configs from "./package.json";

const iconPath = path.resolve(__dirname, "src/assets/favicon");
const iconPathWithSuffix = iconPath + ".ico";
const appVersion = configs.version;

const config: ForgeConfig = {
  packagerConfig: {
    asar: true,
    icon: iconPath,
    appVersion: appVersion,
    extraResource: [path.resolve(__dirname, "data")],
  },
  rebuildConfig: {},
  makers: [
    {
      name: "@electron-forge/maker-squirrel",
      config: {
        iconUrl: iconPathWithSuffix,
        setupIcon: iconPathWithSuffix,
      },
    },
    {
      name: "@electron-forge/maker-deb",
      config: {
        options: {
          // Path to a single image that will act as icon for the application
          icon: iconPathWithSuffix,
        },
      },
    },
    new MakerZIP({}, ["darwin"]),
    new MakerRpm({}),
  ],
  plugins: [
    new VitePlugin({
      // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
      // If you are familiar with Vite configuration, it will look really familiar.
      build: [
        {
          // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
          entry: "src/main.ts",
          config: "vite.main.config.ts",
        },
        {
          entry: "src/preload.ts",
          config: "vite.preload.config.ts",
        },
      ],
      renderer: [
        {
          name: "main_window",
          config: "vite.renderer.config.ts",
        },
      ],
    }),
    // Fuses are used to enable/disable various Electron functionality
    // at package time, before code signing the application
    new FusesPlugin({
      version: FuseVersion.V1,
      [FuseV1Options.RunAsNode]: false,
      [FuseV1Options.EnableCookieEncryption]: true,
      [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
      [FuseV1Options.EnableNodeCliInspectArguments]: false,
      [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
      [FuseV1Options.OnlyLoadAppFromAsar]: true,
    }),
  ],
};

export default config;

forge.env.d.ts

export {}; // Make this a module

declare global {
    // This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Vite
    // plugin that tells the Electron app where to look for the Vite-bundled app code (depending on
    // whether you're running in development or production).
    const MAIN_WINDOW_VITE_DEV_SERVER_URL: string;
    const MAIN_WINDOW_VITE_NAME: string;

    namespace NodeJS {
        interface Process {
            // Used for hot reload after preload scripts.
            viteDevServers: Record<string, import("vite").ViteDevServer>;
        }
    }

    type VitePluginConfig = ConstructorParameters<
        typeof import("@electron-forge/plugin-vite").VitePlugin
    >[0];

    interface VitePluginRuntimeKeys {
        VITE_DEV_SERVER_URL: `${string}_VITE_DEV_SERVER_URL`;
        VITE_NAME: `${string}_VITE_NAME`;
    }
}

declare module "vite" {
    interface ConfigEnv<K extends keyof VitePluginConfig = keyof VitePluginConfig> {
        root: string;
        forgeConfig: VitePluginConfig;
        forgeConfigSelf: VitePluginConfig[K][number];
    }
}
@caoxiemeihao
Copy link
Member

Can you provide a minimal reproduction repo?

@a1392136
Copy link
Author

a1392136 commented Apr 28, 2024

Can you provide a minimal reproduction repo?

Thank you for taking the time to reply
I spent the afternoon re-combing through my code and found out that it was a problem with the typeorm entity.
But I still have a problem, when the error appears after clicking confirm, the process will run in the background without ending.
How do I end the background process in code.

image

@a1392136 a1392136 reopened this Apr 28, 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

2 participants