diff --git a/packages/plugin/vite/package.json b/packages/plugin/vite/package.json index 08d56f185a..774595add8 100644 --- a/packages/plugin/vite/package.json +++ b/packages/plugin/vite/package.json @@ -16,6 +16,7 @@ "@electron-forge/shared-types": "7.10.2", "chalk": "^4.0.0", "debug": "^4.3.1", + "flora-colossus": "^2.0.0", "fs-extra": "^10.0.0", "listr2": "^7.0.2" }, diff --git a/packages/plugin/vite/spec/VitePlugin.spec.ts b/packages/plugin/vite/spec/VitePlugin.spec.ts index a67d91ea61..6a60f8f238 100644 --- a/packages/plugin/vite/spec/VitePlugin.spec.ts +++ b/packages/plugin/vite/spec/VitePlugin.spec.ts @@ -19,6 +19,10 @@ describe('VitePlugin', async () => { const tmpdir = path.join(tmp, 'electron-forge-test-'); const viteTestDir = await fs.promises.mkdtemp(tmpdir); + afterAll(async () => { + await fs.promises.rm(viteTestDir, { recursive: true }); + }); + describe('packageAfterCopy', () => { const packageJSONPath = path.join(viteTestDir, 'package.json'); const packagedPath = path.join(viteTestDir, 'packaged'); @@ -88,10 +92,6 @@ describe('VitePlugin', async () => { plugin.packageAfterCopy({} as ResolvedForgeConfig, packagedPath), ).rejects.toThrow(/entry point/); }); - - afterAll(async () => { - await fs.promises.rm(viteTestDir, { recursive: true }); - }); }); describe('resolveForgeConfig', () => { @@ -99,6 +99,7 @@ describe('VitePlugin', async () => { beforeAll(() => { plugin = new VitePlugin(baseConfig); + plugin.setDirectories(viteTestDir); }); it('sets packagerConfig and packagerConfig.ignore if it does not exist', async () => { @@ -133,6 +134,7 @@ describe('VitePlugin', async () => { it('ignores source map files by default', async () => { const viteConfig = { ...baseConfig }; plugin = new VitePlugin(viteConfig); + plugin.setDirectories(viteTestDir); const config = await plugin.resolveForgeConfig( {} as ResolvedForgeConfig, ); @@ -171,6 +173,7 @@ describe('VitePlugin', async () => { it('includes source map files when specified by config', async () => { const viteConfig = { ...baseConfig, packageSourceMaps: true }; plugin = new VitePlugin(viteConfig); + plugin.setDirectories(viteTestDir); const config = await plugin.resolveForgeConfig( {} as ResolvedForgeConfig, ); @@ -205,6 +208,17 @@ describe('VitePlugin', async () => { ), ).toEqual(false); }); + + it('includes /node_modules directory', async () => { + plugin = new VitePlugin(baseConfig); + plugin.setDirectories(viteTestDir); + const config = await plugin.resolveForgeConfig( + {} as ResolvedForgeConfig, + ); + const ignore = config.packagerConfig.ignore as IgnoreFunction; + + expect(ignore('/node_modules')).toEqual(false); + }); }); }); }); diff --git a/packages/plugin/vite/src/VitePlugin.ts b/packages/plugin/vite/src/VitePlugin.ts index 8b72f5f960..0fc8ad8364 100644 --- a/packages/plugin/vite/src/VitePlugin.ts +++ b/packages/plugin/vite/src/VitePlugin.ts @@ -6,6 +6,7 @@ import path from 'node:path'; import { namedHookWithTaskFn, PluginBase } from '@electron-forge/plugin-base'; import chalk from 'chalk'; import debug from 'debug'; +import { DepType, Module, Walker } from 'flora-colossus'; import fs from 'fs-extra'; import { Listr, PRESET_TIMER } from 'listr2'; import { default as vite } from 'vite'; @@ -77,6 +78,18 @@ export default class VitePlugin extends PluginBase { )); } + /** + * Scans node_modules to find packages in production dependencies + */ + private async getFlatDependencies(): Promise { + const nodeModulesPath = path.join(this.projectDir, 'node_modules'); + + const walker = new Walker(nodeModulesPath); + const deps = await walker.walkTree(); + + return deps.filter((dep) => dep.depType === DepType.PROD); + } + getHooks = (): ForgeMultiHookMap => { return { preStart: [ @@ -175,15 +188,33 @@ Your packaged app may be larger than expected if you dont ignore everything othe return forgeConfig; } + // Find packages containing native modules (.node files) + // These need to be included in the asar for AutoUnpackNativesPlugin to work + const flatDeps = await this.getFlatDependencies(); + forgeConfig.packagerConfig.ignore = (file: string) => { if (!file) return false; // `file` always starts with `/` // @see - https://github.com/electron/packager/blob/v18.1.3/src/copy-filter.ts#L89-L93 - // Collect the files built by Vite - return !file.startsWith('/.vite'); + // Include files built by Vite + if (file.startsWith('/.vite')) return false; + + // Include node_modules folder itself (required for the ignore function to work) + if (file === '/node_modules') return false; + + // For files inside node_modules, only include packages with native modules + if (file.startsWith('/node_modules/')) { + // Collect dependencies from package.json + const [, , name] = file.split('/'); + return flatDeps.some((dep) => dep.name === name); + } + + // Exclude everything else + return true; }; + return forgeConfig; }; diff --git a/yarn.lock b/yarn.lock index 608b513f7b..b8b168c1b3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1166,6 +1166,7 @@ __metadata: "@types/node": "npm:^18.0.3" chalk: "npm:^4.0.0" debug: "npm:^4.3.1" + flora-colossus: "npm:^2.0.0" fs-extra: "npm:^10.0.0" listr2: "npm:^7.0.2" vite: "npm:^5.0.12"