diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..bc63aca35b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'monthly' diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml index 6454f341f5..ad44091df6 100644 --- a/.github/workflows/add-to-project.yml +++ b/.github/workflows/add-to-project.yml @@ -21,7 +21,7 @@ jobs: creds: ${{ secrets.ECOSYSTEM_ISSUE_TRIAGE_GH_APP_CREDS }} org: electron - name: Add to Project - uses: dsanders11/project-actions/add-item@a24415515fa60a22f71f9d9d00e36ca82660cde9 # v1.0.1 + uses: dsanders11/project-actions/add-item@82e99438bd44a14ad18d92d036dbc25cbfb9a8c4 # v1.2.0 with: field: Opened field-value: ${{ github.event.pull_request.created_at || github.event.issue.created_at }} diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 11cd33c5cd..1c702e326c 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,14 +19,14 @@ jobs: creds: ${{ secrets.GH_APP_CREDS }} export-git-user: true - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: submodules: true fetch-depth: 0 token: ${{ steps.generate-token.outputs.token }} - name: Use Node.js LTS - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: 20.x cache: yarn diff --git a/.github/workflows/semantic.yml b/.github/workflows/semantic.yml index bd93660c16..ed275daf58 100644 --- a/.github/workflows/semantic.yml +++ b/.github/workflows/semantic.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: semantic-pull-request - uses: amannn/action-semantic-pull-request@01d5fd8a8ebb9aafe902c40c53f0f4744f7381eb # tag: v5 + uses: amannn/action-semantic-pull-request@e9fabac35e210fea40ca5b14c0da95a099eff26f # tag: v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.gitignore b/.gitignore index c570779205..69ecca3d78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store .nyc_output *.lcov /coverage diff --git a/package.json b/package.json index 4402283159..34c54074ed 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,10 @@ "lint:fix": "prettier --write .", "link:prepare": "lerna exec -- node ../../../tools/silent.js yarn link --silent --no-bin-links --link-folder ../../../.links", "link:remove": "lerna exec -- node ../../../tools/silent.js yarn unlink --silent --no-bin-links --link-folder ../../../.links", - "test": "xvfb-maybe cross-env NODE_ENV=test TS_NODE_PROJECT='./tsconfig.test.json' TS_NODE_FILES=1 mocha", + "test": "npm run test:clear && xvfb-maybe cross-env NODE_ENV=test TS_NODE_PROJECT='./tsconfig.test.json' TS_NODE_FILES=1 mocha", "test:fast": "npm run test -- --suite=fast", "test:slow": "npm run test -- --suite=slow", + "test:clear": "ts-node tools/test-clear", "postinstall": "rimraf node_modules/.bin/*.ps1 && ts-node ./tools/gen-tsconfigs.ts && ts-node ./tools/gen-ts-glue.ts", "prepare": "husky install", "preversion": "yarn build" @@ -74,7 +75,7 @@ "source-map-support": "^0.5.13", "sudo-prompt": "^9.1.1", "username": "^5.1.0", - "vite": "^4.5.1", + "vite": "^5.0.12", "webpack": "^5.69.1", "webpack-dev-server": "^4.0.0", "webpack-merge": "^5.7.3", diff --git a/packages/plugin/electronegativity/src/ElectronegativityPlugin.ts b/packages/plugin/electronegativity/src/ElectronegativityPlugin.ts index 36ff12d3aa..32b25e36c9 100644 --- a/packages/plugin/electronegativity/src/ElectronegativityPlugin.ts +++ b/packages/plugin/electronegativity/src/ElectronegativityPlugin.ts @@ -38,7 +38,7 @@ export type ElectronegativityConfig = { * * Defaults to `false`. */ - isRelative?: false; + isRelative?: boolean; /** * Specify a range to run Electron upgrade checks. For example, `'7..8'` checks an upgrade * from Electron 7 to Electron 8. @@ -49,7 +49,7 @@ export type ElectronegativityConfig = { * * Defaults to empty array (`[]`) */ - parserPlugins: Array; + parserPlugins?: Array; }; export default class ElectronegativityPlugin extends PluginBase { @@ -65,6 +65,7 @@ export default class ElectronegativityPlugin extends PluginBase= 16.4.0" }, - "dependencies": { - "@electron-forge/core-utils": "7.2.0", - "@electron-forge/plugin-base": "7.2.0", - "@electron-forge/shared-types": "7.2.0", - "@electron-forge/web-multi-logger": "7.2.0", - "chalk": "^4.0.0", - "debug": "^4.3.1", - "fs-extra": "^10.0.0", - "vite": "^4.5.1" - }, "publishConfig": { "access": "public" }, diff --git a/packages/plugin/vite/src/Config.ts b/packages/plugin/vite/src/Config.ts index 2f1ffd3601..bf20f6386a 100644 --- a/packages/plugin/vite/src/Config.ts +++ b/packages/plugin/vite/src/Config.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line node/no-unpublished-import import type { LibraryOptions } from 'vite'; export interface VitePluginBuildConfig { @@ -8,14 +9,14 @@ export interface VitePluginBuildConfig { /** * Vite config file path. */ - config?: string; + config: string; } export interface VitePluginRendererConfig { /** - * Human friendly name of your entry point + * Human friendly name of your entry point. */ - name: string; + name?: string; /** * Vite config file path. */ @@ -23,12 +24,16 @@ export interface VitePluginRendererConfig { } export interface VitePluginConfig { + // Reserved option, may support modification in the future. + // @defaultValue '.vite' + // baseDir?: string; + /** * Build anything such as Main process, Preload scripts and Worker process, etc. */ build: VitePluginBuildConfig[]; /** - * Renderer process. + * Renderer process Vite configs. */ renderer: VitePluginRendererConfig[]; } diff --git a/packages/plugin/vite/src/ViteConfig.ts b/packages/plugin/vite/src/ViteConfig.ts index dcb514fb3d..b91d8abb9e 100644 --- a/packages/plugin/vite/src/ViteConfig.ts +++ b/packages/plugin/vite/src/ViteConfig.ts @@ -1,36 +1,33 @@ -import path from 'node:path'; - import debug from 'debug'; -import { ConfigEnv, loadConfigFromFile, mergeConfig, UserConfig } from 'vite'; - -import { VitePluginConfig } from './Config'; -import { externalBuiltins } from './util/plugins'; +// eslint-disable-next-line node/no-unpublished-import +import { loadConfigFromFile } from 'vite'; -const d = debug('electron-forge:plugin:vite:viteconfig'); +import type { VitePluginBuildConfig, VitePluginConfig, VitePluginRendererConfig } from './Config'; +// eslint-disable-next-line node/no-unpublished-import +import type { ConfigEnv, UserConfig } from 'vite'; -/** - * Vite allows zero-config runs, if the user does not provide `vite.config.js`, - * then the value of `LoadResult` will become `null`. - */ -export type LoadResult = Awaited>; +const d = debug('@electron-forge/plugin-vite:ViteConfig'); export default class ViteConfigGenerator { - private readonly baseDir: string; - - private rendererConfigCache!: Promise[]; - constructor(private readonly pluginConfig: VitePluginConfig, private readonly projectDir: string, private readonly isProd: boolean) { - this.baseDir = path.join(projectDir, '.vite'); d('Config mode:', this.mode); } - resolveConfig(config: string, configEnv: Partial = {}) { - // `command` is to be passed as an arguments when the user export a function in `vite.config.js`. + resolveConfig(buildConfig: VitePluginBuildConfig | VitePluginRendererConfig, configEnv: Partial = {}) { // @see - https://vitejs.dev/config/#conditional-config configEnv.command ??= this.isProd ? 'build' : 'serve'; - // `mode` affects `.env.[mode]` file loading. + // `mode` affects `.env.[mode]` file load. configEnv.mode ??= this.mode; - return loadConfigFromFile(configEnv as ConfigEnv, config); + + // Hack! Pass the forge runtime config to the vite config file in the template. + Object.assign(configEnv, { + root: this.projectDir, + forgeConfig: this.pluginConfig, + forgeConfigSelf: buildConfig, + }); + + // `configEnv` is to be passed as an arguments when the user export a function in `vite.config.js`. + return loadConfigFromFile(configEnv as ConfigEnv, buildConfig.config); } get mode(): string { @@ -40,61 +37,15 @@ export default class ViteConfigGenerator { return this.isProd ? 'production' : 'development'; } - async getDefines(): Promise> { - const defines: Record = {}; - const rendererConfigs = await this.getRendererConfig(); - for (const [index, userConfig] of rendererConfigs.entries()) { - const name = this.pluginConfig.renderer[index].name; - if (!name) { - continue; - } - const NAME = name.toUpperCase().replace(/ /g, '_'); - // `server.port` is set in `launchRendererDevServers` in `VitePlugin.ts`. - defines[`${NAME}_VITE_DEV_SERVER_URL`] = this.isProd ? undefined : JSON.stringify(`http://localhost:${userConfig?.server?.port}`); - defines[`${NAME}_VITE_NAME`] = JSON.stringify(name); - } - return defines; - } - - async getBuildConfig(watch = false): Promise { + async getBuildConfig(): Promise { if (!Array.isArray(this.pluginConfig.build)) { throw new Error('"config.build" must be an Array'); } - const define = await this.getDefines(); - const plugins = [externalBuiltins()]; const configs = this.pluginConfig.build - .filter(({ entry, config }) => entry || config) - .map>(async ({ entry, config }) => { - const defaultConfig: UserConfig = { - // Ensure that each build config loads the .env file correctly. - mode: this.mode, - build: { - lib: entry - ? { - entry, - // Electron can only support cjs. - formats: ['cjs'], - fileName: () => '[name].js', - } - : undefined, - // Prevent multiple builds from interfering with each other. - emptyOutDir: false, - // 🚧 Multiple builds may conflict. - outDir: path.join(this.baseDir, 'build'), - watch: watch ? {} : undefined, - minify: this.isProd, - }, - clearScreen: false, - define, - plugins, - }; - if (config) { - const loadResult = await this.resolveConfig(config); - return mergeConfig(defaultConfig, loadResult?.config ?? {}); - } - return defaultConfig; - }); + // Prevent load the default `vite.config.js` file. + .filter(({ config }) => config) + .map>(async (buildConfig) => (await this.resolveConfig(buildConfig))?.config ?? {}); return await Promise.all(configs); } @@ -104,20 +55,9 @@ export default class ViteConfigGenerator { throw new Error('"config.renderer" must be an Array'); } - const configs = (this.rendererConfigCache ??= this.pluginConfig.renderer.map(async ({ name, config }) => { - const defaultConfig: UserConfig = { - // Ensure that each build config loads the .env file correctly. - mode: this.mode, - // Make sure that Electron can be loaded into the local file using `loadFile` after packaging. - base: './', - build: { - outDir: path.join(this.baseDir, 'renderer', name), - }, - clearScreen: false, - }; - const loadResult = (await this.resolveConfig(config)) ?? { path: '', config: {}, dependencies: [] }; - return mergeConfig(defaultConfig, loadResult.config); - })); + const configs = this.pluginConfig.renderer + .filter(({ config }) => config) + .map>(async (buildConfig) => (await this.resolveConfig(buildConfig))?.config ?? {}); return await Promise.all(configs); } diff --git a/packages/plugin/vite/src/VitePlugin.ts b/packages/plugin/vite/src/VitePlugin.ts index 3a1c6b5110..6e71ca7c6c 100644 --- a/packages/plugin/vite/src/VitePlugin.ts +++ b/packages/plugin/vite/src/VitePlugin.ts @@ -1,19 +1,22 @@ -import { AddressInfo } from 'node:net'; import path from 'node:path'; import { namedHookWithTaskFn, PluginBase } from '@electron-forge/plugin-base'; -import { ForgeMultiHookMap, ResolvedForgeConfig, StartResult } from '@electron-forge/shared-types'; import chalk from 'chalk'; import debug from 'debug'; import fs from 'fs-extra'; -// eslint-disable-next-line node/no-extraneous-import -import { RollupWatcher } from 'rollup'; +// eslint-disable-next-line node/no-unpublished-import import { default as vite } from 'vite'; -import { VitePluginConfig } from './Config'; import { getFlatDependencies } from './util/package'; +import { onBuildDone } from './util/plugins'; import ViteConfigGenerator from './ViteConfig'; +import type { VitePluginConfig } from './Config'; +import type { ForgeMultiHookMap, ResolvedForgeConfig, StartResult } from '@electron-forge/shared-types'; +import type { AddressInfo } from 'node:net'; +// eslint-disable-next-line node/no-extraneous-import +import type { RollupWatcher } from 'rollup'; + const d = debug('electron-forge:plugin:vite'); export default class VitePlugin extends PluginBase { @@ -144,7 +147,7 @@ the generated files). Instead, it is ${JSON.stringify(pj.main)}`); { title: 'Compiling main process code', task: async () => { - await this.build(true); + await this.build(); }, options: { showTimer: true, @@ -156,42 +159,34 @@ the generated files). Instead, it is ${JSON.stringify(pj.main)}`); }; // Main process, Preload scripts and Worker process, etc. - build = async (watch = false): Promise => { - await Promise.all( - ( - await this.configGenerator.getBuildConfig(watch) - ).map((userConfig) => { - return new Promise((resolve, reject) => { - vite - .build({ - // Avoid recursive builds caused by users configuring @electron-forge/plugin-vite in Vite config file. - configFile: false, - ...userConfig, - plugins: [ - { - name: '@electron-forge/plugin-vite:start', - closeBundle() { - resolve(); - - // TODO: implement hot-restart here - }, - }, - ...(userConfig.plugins ?? []), - ], - }) - .then((result) => { - const isWatcher = (x: any): x is RollupWatcher => typeof x?.close === 'function'; - - if (isWatcher(result)) { - this.watchers.push(result); - } - - return result; - }) - .catch(reject); - }); - }) - ); + build = async (): Promise => { + const configs = await this.configGenerator.getBuildConfig(); + const buildTasks: Promise[] = []; + const isWatcher = (x: any): x is RollupWatcher => typeof x?.close === 'function'; + + for (const userConfig of configs) { + const buildTask = new Promise((resolve, reject) => { + vite + .build({ + // Avoid recursive builds caused by users configuring @electron-forge/plugin-vite in Vite config file. + configFile: false, + ...userConfig, + plugins: [onBuildDone(resolve), ...(userConfig.plugins ?? [])], + }) + .then((result) => { + if (isWatcher(result)) { + this.watchers.push(result); + } + + return result; + }) + .catch(reject); + }); + + buildTasks.push(buildTask); + } + + await Promise.all(buildTasks); }; // Renderer process diff --git a/packages/plugin/vite/src/util/plugins.ts b/packages/plugin/vite/src/util/plugins.ts index fb5df3db1b..ca7f630bb7 100644 --- a/packages/plugin/vite/src/util/plugins.ts +++ b/packages/plugin/vite/src/util/plugins.ts @@ -1,35 +1,11 @@ -import { builtinModules } from 'node:module'; - +// eslint-disable-next-line node/no-unpublished-import import type { Plugin } from 'vite'; -/** - * `electron` and Node.js built-in modules should always be externalize. - */ -export function externalBuiltins() { - return { - name: '@electron-forge/plugin-vite:external-builtins', - config(config) { - const nativeModules = builtinModules.filter((e) => !e.startsWith('_')); - const builtins = ['electron', ...nativeModules, ...nativeModules.map((m) => `node:${m}`)]; - - config.build ??= {}; - config.build.rollupOptions ??= {}; - - let external = config.build.rollupOptions.external; - if (Array.isArray(external) || typeof external === 'string' || external instanceof RegExp) { - external = builtins.concat(external as string[]); - } else if (typeof external === 'function') { - const original = external; - external = function (source, importer, isResolved) { - if (builtins.includes(source)) { - return true; - } - return original(source, importer, isResolved); - }; - } else { - external = builtins; - } - config.build.rollupOptions.external = external; +export function onBuildDone(callback: () => void) { + return { + name: '@electron-forge/plugin-vite:build-done', + closeBundle() { + callback(); }, - }; + } as Plugin; } diff --git a/packages/plugin/vite/test/ViteConfig_spec.ts b/packages/plugin/vite/test/ViteConfig_spec.ts index f4d07aec0a..9ee0c4f3ab 100644 --- a/packages/plugin/vite/test/ViteConfig_spec.ts +++ b/packages/plugin/vite/test/ViteConfig_spec.ts @@ -1,92 +1,64 @@ -import { AddressInfo } from 'node:net'; +import { builtinModules } from 'node:module'; import path from 'node:path'; import { expect } from 'chai'; -import { UserConfig, default as vite, ViteDevServer } from 'vite'; -import { VitePluginConfig } from '../src/Config'; import ViteConfigGenerator from '../src/ViteConfig'; -describe('ViteConfigGenerator', () => { - it('is `getDefines` will be gets auto-updated `server.port`', async () => { - const config = { - renderer: [{ name: 'foo_window' }, { name: 'bar_window' }], - } as VitePluginConfig; - const generator = new ViteConfigGenerator(config, '', false); - const servers: ViteDevServer[] = []; - - for (const userConfig of await generator.getRendererConfig()) { - const viteDevServer = await vite.createServer({ - configFile: false, - ...userConfig, - }); - - await viteDevServer.listen(); - viteDevServer.printUrls(); - servers.push(viteDevServer); +import type { VitePluginConfig } from '../src/Config'; +import type { UserConfig } from 'vite'; - // Make suee that `getDefines` in VitePlugin.ts gets the correct `server.port`. (#3198) - const addressInfo = viteDevServer.httpServer!.address() as AddressInfo; - userConfig.server ??= {}; - userConfig.server.port = addressInfo.port; - } - - const define = await generator.getDefines(); - - for (const server of servers) { - server.close(); - } - servers.length = 0; - - expect(define.FOO_WINDOW_VITE_DEV_SERVER_URL).equal('"http://localhost:5173"'); - expect(define.FOO_WINDOW_VITE_NAME).equal('"foo_window"'); - expect(define.BAR_WINDOW_VITE_DEV_SERVER_URL).equal('"http://localhost:5174"'); - expect(define.BAR_WINDOW_VITE_NAME).equal('"bar_window"'); - }); +const builtins = ['electron', ...builtinModules.map((m) => [m, `node:${m}`]).flat()]; +const configRoot = path.join(__dirname, 'fixture/config'); +describe('ViteConfigGenerator', () => { it('getBuildConfig', async () => { const config = { - build: [{ entry: 'foo.js' }], + build: [{ config: path.join(configRoot, 'vite.main.config.mjs') }], renderer: [], } as VitePluginConfig; - const generator = new ViteConfigGenerator(config, '', true); - const buildConfig = (await generator.getBuildConfig())[0]; - expect(buildConfig).deep.equal({ + const generator = new ViteConfigGenerator(config, configRoot, true); + const buildConfig1 = (await generator.getBuildConfig())[0]; + const buildConfig2: UserConfig = { + root: configRoot, mode: 'production', build: { lib: { - entry: 'foo.js', + entry: 'src/main.js', formats: ['cjs'], // shims - fileName: (buildConfig.build?.lib as any)?.fileName, + fileName: (buildConfig1.build?.lib as any)?.fileName, }, emptyOutDir: false, - outDir: path.join('.vite', 'build'), - watch: undefined, + outDir: '.vite/build', minify: true, // this.isProd === true + watch: null, + rollupOptions: { + external: builtins, + }, }, clearScreen: false, - define: {}, - // shims - plugins: [buildConfig.plugins?.[0]], - } as UserConfig); + }; + + expect(buildConfig1).deep.equal(buildConfig2); }); it('getRendererConfig', async () => { const config = { - renderer: [{ name: 'foo_window' }, { name: 'bar_window' }], + build: [{ config: path.join(configRoot, 'vite.renderer.config.mjs') }], + renderer: [], } as VitePluginConfig; - const generator = new ViteConfigGenerator(config, '', false); - const configs = await generator.getRendererConfig(); - for (const [index, rendererConfig] of configs.entries()) { - expect(rendererConfig).deep.equal({ - mode: 'development', - base: './', - build: { - outDir: path.join('.vite', 'renderer', config.renderer[index].name), - }, - clearScreen: false, - } as UserConfig); - } + const generator = new ViteConfigGenerator(config, configRoot, true); + const buildConfig1 = (await generator.getBuildConfig())[0]; + const buildConfig2: UserConfig = { + root: configRoot, + mode: 'production', + base: './', + build: { + outDir: 'renderer/main_window', + }, + }; + + expect(buildConfig1).deep.equal(buildConfig2); }); }); diff --git a/packages/plugin/vite/test/fixture/config/vite.main.config.mjs b/packages/plugin/vite/test/fixture/config/vite.main.config.mjs new file mode 100644 index 0000000000..ef5cff2d1a --- /dev/null +++ b/packages/plugin/vite/test/fixture/config/vite.main.config.mjs @@ -0,0 +1,31 @@ +import { builtinModules } from 'node:module'; + +// eslint-disable-next-line import/namespace +import { defineConfig } from 'vite'; + +const builtins = [ + 'electron', + ...builtinModules.map((m) => [m, `node:${m}`]).flat(), +]; + +export default defineConfig((env) => ({ + root: env.root, + mode: env.mode, + build: { + lib: { + entry: 'src/main.js', + fileName: () => '[name].js', + formats: ['cjs'], + }, + // Prevent multiple builds from interfering with each other. + emptyOutDir: false, + // 🚧 Multiple builds may conflict. + outDir: '.vite/build', + minify: env.command === 'build', + watch: env.command === 'serve' ? {} : null, + rollupOptions: { + external: builtins, + }, + }, + clearScreen: false, +})); diff --git a/packages/plugin/vite/test/fixture/config/vite.renderer.config.mjs b/packages/plugin/vite/test/fixture/config/vite.renderer.config.mjs new file mode 100644 index 0000000000..a7fcc5f5ba --- /dev/null +++ b/packages/plugin/vite/test/fixture/config/vite.renderer.config.mjs @@ -0,0 +1,11 @@ +// eslint-disable-next-line import/namespace +import { defineConfig } from 'vite'; + +export default defineConfig((env) => ({ + root: env.root, + mode: env.mode, + base: './', + build: { + outDir: 'renderer/main_window', + }, +})); diff --git a/packages/plugin/vite/test/util/plugins_spec.ts b/packages/plugin/vite/test/util/plugins_spec.ts deleted file mode 100644 index 9375dee789..0000000000 --- a/packages/plugin/vite/test/util/plugins_spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { builtinModules } from 'module'; - -import { expect } from 'chai'; -// eslint-disable-next-line node/no-extraneous-import -import { ExternalOption } from 'rollup'; -import { resolveConfig } from 'vite'; - -import { externalBuiltins } from '../../src/util/plugins'; - -describe('util/plugins', () => { - it('externalBuiltins', async () => { - const nativeModules = builtinModules.filter((e) => !e.startsWith('_')); - const builtins: any[] = ['electron', ...nativeModules, ...nativeModules.map((m) => `node:${m}`)]; - const getConfig = (external: ExternalOption) => - resolveConfig( - { - configFile: false, - build: { - rollupOptions: { - external, - }, - }, - plugins: [externalBuiltins()], - }, - 'build' - ); - - const external_string: ExternalOption = 'electron'; - const external_string2 = (await getConfig(external_string))!.build!.rollupOptions!.external; - expect(external_string2).deep.equal(builtins.concat(external_string)); - - const external_array: ExternalOption = ['electron']; - const external_array2 = (await getConfig(external_array))!.build!.rollupOptions!.external; - expect(external_array2).deep.equal(builtins.concat(external_array)); - - const external_regexp: ExternalOption = /electron/; - const external_regexp2 = (await getConfig(external_regexp))!.build!.rollupOptions!.external; - expect(external_regexp2).deep.equal(builtins.concat(external_regexp)); - - const external_function: ExternalOption = (source) => ['electron'].includes(source); - const external_function2 = (await getConfig(external_function))!.build!.rollupOptions!.external; - expect((external_function2 as (source: string) => boolean)('electron')).true; - }); -}); diff --git a/packages/plugin/vite/vite-env.d.ts b/packages/plugin/vite/vite-env.d.ts new file mode 100644 index 0000000000..297a6fc911 --- /dev/null +++ b/packages/plugin/vite/vite-env.d.ts @@ -0,0 +1,2 @@ +// Fix build types check error. +declare module 'rollup/parseAst'; diff --git a/packages/publisher/github/src/Config.ts b/packages/publisher/github/src/Config.ts index acd2b1ed91..35f504f1a0 100644 --- a/packages/publisher/github/src/Config.ts +++ b/packages/publisher/github/src/Config.ts @@ -47,4 +47,8 @@ export interface PublisherGitHubConfig { * Re-upload the new asset if you upload an asset with the same filename as existing asset */ force?: boolean; + /** + * Whether to automatically generate release notes for the release + */ + generateReleaseNotes?: boolean; } diff --git a/packages/publisher/github/src/PublisherGithub.ts b/packages/publisher/github/src/PublisherGithub.ts index 6bb351f39f..803bf90605 100644 --- a/packages/publisher/github/src/PublisherGithub.ts +++ b/packages/publisher/github/src/PublisherGithub.ts @@ -79,6 +79,7 @@ export default class PublisherGithub extends PublisherBase { + await this.copyTemplateFile(directory, 'forge.env.d.ts'); await this.copyTemplateFile(directory, 'forge.config.ts'); await fs.remove(path.resolve(directory, 'forge.config.js')); }, @@ -24,9 +25,10 @@ class ViteTypeScriptTemplate extends BaseTemplate { const filePath = (fileName: string) => path.join(directory, 'src', fileName); // Copy Vite files + await this.copyTemplateFile(directory, 'vite.base.config.ts'); await this.copyTemplateFile(directory, 'vite.main.config.ts'); - await this.copyTemplateFile(directory, 'vite.renderer.config.ts'); await this.copyTemplateFile(directory, 'vite.preload.config.ts'); + await this.copyTemplateFile(directory, 'vite.renderer.config.ts'); // Copy tsconfig with a small set of presets await this.copyTemplateFile(directory, 'tsconfig.json'); @@ -39,7 +41,6 @@ class ViteTypeScriptTemplate extends BaseTemplate { await this.copyTemplateFile(path.join(directory, 'src'), 'main.ts'); await this.copyTemplateFile(path.join(directory, 'src'), 'renderer.ts'); - await this.copyTemplateFile(path.join(directory, 'src'), 'types.d.ts'); // Remove preload.js and replace with preload.ts await fs.remove(filePath('preload.js')); diff --git a/packages/template/vite-typescript/test/ViteTypeScriptTemplate_spec_slow.ts b/packages/template/vite-typescript/test/ViteTypeScriptTemplate_spec_slow.ts index ad606a6664..4ab251c854 100644 --- a/packages/template/vite-typescript/test/ViteTypeScriptTemplate_spec_slow.ts +++ b/packages/template/vite-typescript/test/ViteTypeScriptTemplate_spec_slow.ts @@ -1,5 +1,5 @@ -import cp from 'child_process'; -import path from 'path'; +import os from 'node:os'; +import path from 'node:path'; import { yarnOrNpmSpawn } from '@electron-forge/core-utils'; import * as testUtils from '@electron-forge/test-utils'; @@ -20,11 +20,10 @@ describe('ViteTypeScriptTemplate', () => { after(async () => { await yarnOrNpmSpawn(['link:remove']); - await killWindowsEsbuildExe(); - // TODO: use the async API @caoxiemeihao - // In the vite@4 running test will occupy the `dist` folder, causing an error on the Windows PC when call `fs.remove()`. - // Currently, vite has released 5 version, and forge-vite-plugin will be upgrade soon vite@5 and I will try to fix issue in the next PR about vite@5. - fs.rmSync(dir, { recursive: true, force: true }); + if (os.platform() !== 'win32') { + // Windows platform `fs.remove(dir)` logic useing npm `npm run test:clear`. + await fs.remove(dir); + } }); describe('template files are copied to project', () => { @@ -37,16 +36,18 @@ describe('ViteTypeScriptTemplate', () => { }); const expectedFiles = [ + 'package.json', 'tsconfig.json', '.eslintrc.json', + 'forge.env.d.ts', 'forge.config.ts', + 'vite.base.config.ts', 'vite.main.config.ts', - 'vite.renderer.config.ts', 'vite.preload.config.ts', + 'vite.renderer.config.ts', path.join('src', 'main.ts'), path.join('src', 'renderer.ts'), path.join('src', 'preload.ts'), - path.join('src', 'types.d.ts'), ]; for (const filename of expectedFiles) { it(`${filename} should exist`, async () => { @@ -105,43 +106,3 @@ describe('ViteTypeScriptTemplate', () => { }); }); }); - -/** - * TODO: resolve `esbuild` can not exit normally on the Windows platform. - * @deprecated - */ -async function killWindowsEsbuildExe() { - if (process.platform !== 'win32') { - return Promise.resolve(); - } - - return new Promise((resolve, reject) => { - cp.exec('tasklist', (error, stdout) => { - if (error) { - reject(error); - return; - } - - const esbuild = stdout - .toString() - .split('\n') - .map((line) => line.split(/\s+/)) - .find((line) => line.includes('esbuild.exe')); - - if (!esbuild) { - resolve(); - return; - } - - // ['esbuild.exe', '4564', 'Console', '1', '14,400', 'K', ''] - const [, pid] = esbuild; - const result = process.kill(+pid, 'SIGINT'); - - if (result) { - resolve(); - } else { - reject(new Error('kill esbuild process failed')); - } - }); - }); -} diff --git a/packages/template/vite-typescript/tmpl/forge.config.ts b/packages/template/vite-typescript/tmpl/forge.config.ts index ec2b06b858..1ab9f7e906 100644 --- a/packages/template/vite-typescript/tmpl/forge.config.ts +++ b/packages/template/vite-typescript/tmpl/forge.config.ts @@ -4,9 +4,13 @@ import { MakerZIP } from '@electron-forge/maker-zip'; import { MakerDeb } from '@electron-forge/maker-deb'; 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'; const config: ForgeConfig = { - packagerConfig: {}, + packagerConfig: { + asar: true, + }, rebuildConfig: {}, makers: [new MakerSquirrel({}), new MakerZIP({}, ['darwin']), new MakerRpm({}), new MakerDeb({})], plugins: [ @@ -31,6 +35,17 @@ const config: ForgeConfig = { }, ], }), + // 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, + }), ], }; diff --git a/packages/template/vite-typescript/tmpl/forge.env.d.ts b/packages/template/vite-typescript/tmpl/forge.env.d.ts new file mode 100644 index 0000000000..d7d95f9052 --- /dev/null +++ b/packages/template/vite-typescript/tmpl/forge.env.d.ts @@ -0,0 +1,28 @@ +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; + } + } + + type VitePluginConfig = ConstructorParameters[0]; + type ForgeConfigEnv = import('vite').ConfigEnv & { + root: string; + forgeConfig: VitePluginConfig; + forgeConfigSelf: VitePluginConfig[K][number]; + }; + + interface VitePluginRuntimeKeys { + VITE_DEV_SERVER_URL: `${string}_VITE_DEV_SERVER_URL`; + VITE_NAME: `${string}_VITE_NAME`; + } +} diff --git a/packages/template/vite-typescript/tmpl/package.json b/packages/template/vite-typescript/tmpl/package.json index 4e477a9ce6..cd0bbb4f61 100644 --- a/packages/template/vite-typescript/tmpl/package.json +++ b/packages/template/vite-typescript/tmpl/package.json @@ -1,11 +1,14 @@ { "devDependencies": { + "@electron/fuses": "^1.7.0", + "@electron-forge/plugin-fuses": "^7.2.0", "@electron-forge/plugin-vite": "ELECTRON_FORGE/VERSION", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.0.1", "eslint-plugin-import": "^2.25.0", "ts-node": "^10.0.0", - "typescript": "~4.5.4" + "typescript": "~4.5.4", + "vite": "^5.0.12" } } diff --git a/packages/template/vite-typescript/tmpl/types.d.ts b/packages/template/vite-typescript/tmpl/types.d.ts deleted file mode 100644 index eae3393f14..0000000000 --- a/packages/template/vite-typescript/tmpl/types.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -// 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). -declare const MAIN_WINDOW_VITE_DEV_SERVER_URL: string; -declare const MAIN_WINDOW_VITE_NAME: string; diff --git a/packages/template/vite-typescript/tmpl/vite.base.config.ts b/packages/template/vite-typescript/tmpl/vite.base.config.ts new file mode 100644 index 0000000000..477a44b159 --- /dev/null +++ b/packages/template/vite-typescript/tmpl/vite.base.config.ts @@ -0,0 +1,93 @@ +import { builtinModules } from 'node:module'; +import type { AddressInfo } from 'node:net'; +import type { Plugin, UserConfig } from 'vite'; +import pkg from './package.json'; + +export const builtins = ['electron', ...builtinModules.map((m) => [m, `node:${m}`]).flat()]; + +export const external = [...builtins, ...Object.keys('dependencies' in pkg ? (pkg.dependencies as Record) : {})]; + +export function getBuildConfig(env: ForgeConfigEnv<'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, + }; +} + +export function getDefineKeys(names: string[]) { + const define: { [name: string]: VitePluginRuntimeKeys } = {}; + + return names.reduce((acc, name) => { + const NAME = name.toUpperCase(); + const keys: VitePluginRuntimeKeys = { + VITE_DEV_SERVER_URL: `${NAME}_VITE_DEV_SERVER_URL`, + VITE_NAME: `${NAME}_VITE_NAME`, + }; + + return { ...acc, [name]: keys }; + }, define); +} + +export function getBuildDefine(env: ForgeConfigEnv<'build'>) { + const { command, forgeConfig } = env; + const names = forgeConfig.renderer.filter(({ name }) => name != null).map(({ name }) => name!); + const defineKeys = getDefineKeys(names); + const define = 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); + + return define; +} + +export function pluginExposeRenderer(name: string): Plugin { + const { VITE_DEV_SERVER_URL } = getDefineKeys([name])[name]; + + return { + name: '@electron-forge/plugin-vite:expose-renderer', + configureServer(server) { + process.viteDevServers ??= {}; + // Expose server for preload scripts hot reload. + 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') { + for (const server of Object.values(process.viteDevServers)) { + // Preload scripts hot reload. + 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'); + } + }, + }; +} diff --git a/packages/template/vite-typescript/tmpl/vite.main.config.ts b/packages/template/vite-typescript/tmpl/vite.main.config.ts index c93ad03824..7b4696910b 100644 --- a/packages/template/vite-typescript/tmpl/vite.main.config.ts +++ b/packages/template/vite-typescript/tmpl/vite.main.config.ts @@ -1,10 +1,29 @@ -import { defineConfig } from 'vite'; +import { type UserConfig, defineConfig, mergeConfig } from 'vite'; +import { getBuildConfig, getBuildDefine, external, pluginHotRestart } from './vite.base.config'; // https://vitejs.dev/config -export default defineConfig({ - resolve: { - // Some libs that can run in both Web and Node.js, such as `axios`, we need to tell Vite to build them in Node.js. - browserField: false, - mainFields: ['module', 'jsnext:main', 'jsnext'], - }, +export default defineConfig((env) => { + const forgeConfigEnv = env as ForgeConfigEnv<'build'>; + const { forgeConfigSelf } = forgeConfigEnv; + const define = getBuildDefine(forgeConfigEnv); + 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(forgeConfigEnv), config); }); diff --git a/packages/template/vite-typescript/tmpl/vite.preload.config.ts b/packages/template/vite-typescript/tmpl/vite.preload.config.ts index 690be5b1a9..bce782bee5 100644 --- a/packages/template/vite-typescript/tmpl/vite.preload.config.ts +++ b/packages/template/vite-typescript/tmpl/vite.preload.config.ts @@ -1,4 +1,27 @@ -import { defineConfig } from 'vite'; +import { type UserConfig, defineConfig, mergeConfig } from 'vite'; +import { getBuildConfig, external, pluginHotRestart } from './vite.base.config'; // https://vitejs.dev/config -export default defineConfig({}); +export default defineConfig((env) => { + const { forgeConfigSelf } = env as ForgeConfigEnv<'build'>; + 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(env as any), config); +}); diff --git a/packages/template/vite-typescript/tmpl/vite.renderer.config.ts b/packages/template/vite-typescript/tmpl/vite.renderer.config.ts index 690be5b1a9..bf15562ac8 100644 --- a/packages/template/vite-typescript/tmpl/vite.renderer.config.ts +++ b/packages/template/vite-typescript/tmpl/vite.renderer.config.ts @@ -1,4 +1,22 @@ -import { defineConfig } from 'vite'; +import { type UserConfig, defineConfig } from 'vite'; +import { pluginExposeRenderer } from './vite.base.config'; // https://vitejs.dev/config -export default defineConfig({}); +export default defineConfig((env) => { + const { root, mode, forgeConfigSelf } = env as ForgeConfigEnv<'renderer'>; + const name = forgeConfigSelf.name ?? ''; + + return { + root, + mode, + base: './', + build: { + outDir: `.vite/renderer/${name}`, + }, + plugins: [pluginExposeRenderer(name)], + resolve: { + preserveSymlinks: true, + }, + clearScreen: false, + } as UserConfig; +}); diff --git a/packages/template/vite/src/ViteTemplate.ts b/packages/template/vite/src/ViteTemplate.ts index 2dbe62e474..d7e557a0e7 100644 --- a/packages/template/vite/src/ViteTemplate.ts +++ b/packages/template/vite/src/ViteTemplate.ts @@ -20,9 +20,10 @@ class ViteTemplate extends BaseTemplate { { title: 'Setting up Vite configuration', task: async () => { - await this.copyTemplateFile(directory, 'vite.renderer.config.mjs'); + await this.copyTemplateFile(directory, 'vite.base.config.mjs'); await this.copyTemplateFile(directory, 'vite.main.config.mjs'); await this.copyTemplateFile(directory, 'vite.preload.config.mjs'); + await this.copyTemplateFile(directory, 'vite.renderer.config.mjs'); await this.copyTemplateFile(path.join(directory, 'src'), 'renderer.js'); await this.copyTemplateFile(path.join(directory, 'src'), 'preload.js'); diff --git a/packages/template/vite/test/ViteTemplate_spec.ts b/packages/template/vite/test/ViteTemplate_spec.ts index d6c5d07eea..f6415c6316 100644 --- a/packages/template/vite/test/ViteTemplate_spec.ts +++ b/packages/template/vite/test/ViteTemplate_spec.ts @@ -23,9 +23,12 @@ describe('ViteTemplate', () => { context('template files are copied to project', () => { const expectedFiles = [ - 'vite.renderer.config.mjs', + 'package.json', + 'forge.config.js', + 'vite.base.config.mjs', 'vite.main.config.mjs', 'vite.preload.config.mjs', + 'vite.renderer.config.mjs', path.join('src', 'renderer.js'), path.join('src', 'preload.js'), ]; diff --git a/packages/template/vite/tmpl/forge.config.js b/packages/template/vite/tmpl/forge.config.js index 04403354a6..45572b88fe 100644 --- a/packages/template/vite/tmpl/forge.config.js +++ b/packages/template/vite/tmpl/forge.config.js @@ -1,5 +1,10 @@ +const { FusesPlugin } = require('@electron-forge/plugin-fuses'); +const { FuseV1Options, FuseVersion } = require('@electron/fuses'); + module.exports = { - packagerConfig: {}, + packagerConfig: { + asar: true, + }, rebuildConfig: {}, makers: [ { @@ -44,5 +49,16 @@ module.exports = { ], }, }, + // 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, + }), ], }; diff --git a/packages/template/vite/tmpl/package.json b/packages/template/vite/tmpl/package.json index 03feaefeef..8cb3c12655 100644 --- a/packages/template/vite/tmpl/package.json +++ b/packages/template/vite/tmpl/package.json @@ -1,5 +1,8 @@ { "devDependencies": { - "@electron-forge/plugin-vite": "ELECTRON_FORGE/VERSION" + "@electron/fuses": "^1.7.0", + "@electron-forge/plugin-fuses": "^7.2.0", + "@electron-forge/plugin-vite": "ELECTRON_FORGE/VERSION", + "vite": "^5.0.12" } } diff --git a/packages/template/vite/tmpl/vite.base.config.mjs b/packages/template/vite/tmpl/vite.base.config.mjs new file mode 100644 index 0000000000..243bf29266 --- /dev/null +++ b/packages/template/vite/tmpl/vite.base.config.mjs @@ -0,0 +1,107 @@ +import { builtinModules } from 'node:module'; +import pkg from './package.json'; + +export const builtins = [ + 'electron', + ...builtinModules.map((m) => [m, `node:${m}`]).flat(), +]; + +export const external = [...builtins, ...Object.keys(pkg.dependencies || {})]; + +/** @type {(env: import('vite').ConfigEnv & { root: string; }) => import('vite').UserConfig} */ +export const getBuildConfig = (env) => { + 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, + }; +}; + +/** @type {(names: string[]) => { [name: string]: { VITE_DEV_SERVER_URL: `${string}_VITE_DEV_SERVER_URL`; VITE_NAME: `${string}_VITE_NAME`; } }} */ +export const getDefineKeys = (names) => { + const define = {}; + + return names.reduce((acc, name) => { + const NAME = name.toUpperCase(); + const keys = { + VITE_DEV_SERVER_URL: `${NAME}_VITE_DEV_SERVER_URL`, + VITE_NAME: `${NAME}_VITE_NAME`, + }; + + return { ...acc, [name]: keys }; + }, define); +}; + +/** @type {(env: Record) => Record} */ +export const getBuildDefine = (env) => { + const { command, forgeConfig } = env; + const names = forgeConfig.renderer + .filter(({ name }) => name != null) + .map(({ name }) => name); + const defineKeys = getDefineKeys(names); + const define = 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 }; + }, {}); + + return define; +}; + +/** @type {(name: string) => import('vite').Plugin} */ +export const pluginExposeRenderer = (name) => { + const { VITE_DEV_SERVER_URL } = getDefineKeys([name])[name]; + + return { + name: '@electron-forge/plugin-vite:expose-renderer', + configureServer(server) { + process.viteDevServers ??= {}; + // Expose server for preload scripts hot reload. + process.viteDevServers[name] = server; + + server.httpServer?.once('listening', () => { + /** @type {import('node:net').AddressInfo} */ + const addressInfo = server.httpServer?.address(); + // Expose env constant for main process use. + process.env[ + VITE_DEV_SERVER_URL + ] = `http://localhost:${addressInfo?.port}`; + }); + }, + }; +}; + +/** @type {(command: 'reload' | 'restart') => import('vite').Plugin} */ +export const pluginHotRestart = (command) => { + return { + name: '@electron-forge/plugin-vite:hot-restart', + closeBundle() { + if (command === 'reload') { + for (const server of Object.values(process.viteDevServers)) { + // Preload scripts hot reload. + 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'); + } + }, + }; +}; diff --git a/packages/template/vite/tmpl/vite.main.config.mjs b/packages/template/vite/tmpl/vite.main.config.mjs index 300b63c0d9..61759a98ae 100644 --- a/packages/template/vite/tmpl/vite.main.config.mjs +++ b/packages/template/vite/tmpl/vite.main.config.mjs @@ -1,11 +1,33 @@ -import { defineConfig } from 'vite'; +import { defineConfig, mergeConfig } from 'vite'; +import { + getBuildConfig, + getBuildDefine, + external, + pluginHotRestart, +} from './vite.base.config.mjs'; // https://vitejs.dev/config -export default defineConfig({ - resolve: { - // Some libs that can run in both Web and Node.js, such as `axios`, we need to tell Vite to build them in Node.js. - browserField: false, - conditions: ['node'], - mainFields: ['module', 'jsnext:main', 'jsnext'], - }, +export default defineConfig((env) => { + const { forgeConfigSelf } = env; + const define = getBuildDefine(env); + const config = { + 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(env), config); }); diff --git a/packages/template/vite/tmpl/vite.preload.config.mjs b/packages/template/vite/tmpl/vite.preload.config.mjs index 690be5b1a9..6006c8e7c2 100644 --- a/packages/template/vite/tmpl/vite.preload.config.mjs +++ b/packages/template/vite/tmpl/vite.preload.config.mjs @@ -1,4 +1,32 @@ -import { defineConfig } from 'vite'; +import { defineConfig, mergeConfig } from 'vite'; +import { + getBuildConfig, + external, + pluginHotRestart, +} from './vite.base.config.mjs'; // https://vitejs.dev/config -export default defineConfig({}); +export default defineConfig((env) => { + const { forgeConfigSelf } = env; + /** @type {import('vite').UserConfig} */ + const config = { + 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(env), config); +}); diff --git a/packages/template/vite/tmpl/vite.renderer.config.mjs b/packages/template/vite/tmpl/vite.renderer.config.mjs index 690be5b1a9..327f0ac593 100644 --- a/packages/template/vite/tmpl/vite.renderer.config.mjs +++ b/packages/template/vite/tmpl/vite.renderer.config.mjs @@ -1,4 +1,23 @@ import { defineConfig } from 'vite'; +import { pluginExposeRenderer } from './vite.base.config.mjs'; // https://vitejs.dev/config -export default defineConfig({}); +export default defineConfig((env) => { + const { root, mode, forgeConfigSelf } = env; + const name = forgeConfigSelf.name ?? ''; + + /** @type {import('vite').UserConfig} */ + return { + root, + mode, + base: './', + build: { + outDir: `.vite/renderer/${name}`, + }, + plugins: [pluginExposeRenderer(name)], + resolve: { + preserveSymlinks: true, + }, + clearScreen: false, + }; +}); diff --git a/packages/template/webpack-typescript/tmpl/forge.config.ts b/packages/template/webpack-typescript/tmpl/forge.config.ts index a303ad52ee..1dcc889870 100644 --- a/packages/template/webpack-typescript/tmpl/forge.config.ts +++ b/packages/template/webpack-typescript/tmpl/forge.config.ts @@ -5,6 +5,8 @@ import { MakerDeb } from '@electron-forge/maker-deb'; import { MakerRpm } from '@electron-forge/maker-rpm'; import { AutoUnpackNativesPlugin } from '@electron-forge/plugin-auto-unpack-natives'; import { WebpackPlugin } from '@electron-forge/plugin-webpack'; +import { FusesPlugin } from '@electron-forge/plugin-fuses'; +import { FuseV1Options, FuseVersion } from '@electron/fuses'; import { mainConfig } from './webpack.main.config'; import { rendererConfig } from './webpack.renderer.config'; @@ -33,6 +35,17 @@ const config: ForgeConfig = { ], }, }), + // 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, + }), ], }; diff --git a/packages/template/webpack-typescript/tmpl/package.json b/packages/template/webpack-typescript/tmpl/package.json index 72d70fb4d9..0c73cd5272 100644 --- a/packages/template/webpack-typescript/tmpl/package.json +++ b/packages/template/webpack-typescript/tmpl/package.json @@ -1,5 +1,7 @@ { "devDependencies": { + "@electron/fuses": "^1.7.0", + "@electron-forge/plugin-fuses": "^7.2.0", "@electron-forge/plugin-webpack": "ELECTRON_FORGE/VERSION", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", diff --git a/packages/template/webpack/tmpl/forge.config.js b/packages/template/webpack/tmpl/forge.config.js index 6ad9269c6f..d6aa49c127 100644 --- a/packages/template/webpack/tmpl/forge.config.js +++ b/packages/template/webpack/tmpl/forge.config.js @@ -1,3 +1,6 @@ +const { FusesPlugin } = require('@electron-forge/plugin-fuses'); +const { FuseV1Options, FuseVersion } = require('@electron/fuses'); + module.exports = { packagerConfig: { asar: true, @@ -45,5 +48,16 @@ module.exports = { }, }, }, + // 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, + }), ], }; diff --git a/tools/test-clear.ts b/tools/test-clear.ts new file mode 100644 index 0000000000..25751276ad --- /dev/null +++ b/tools/test-clear.ts @@ -0,0 +1,23 @@ +import os from 'node:os'; +import path from 'node:path'; + +import chalk from 'chalk'; +import glob from 'fast-glob'; +import fs from 'fs-extra'; + +(async () => { + // https://github.com/electron/forge/blob/v7.2.0/packages/utils/test-utils/src/index.ts#L24 + const dirs = await glob(path.resolve(os.tmpdir(), 'electron-forge-test-*')); + + if (dirs.length) { + for (const dir of dirs) { + console.log('Clean up the test dir:', dir); + + // Remove the tmp files generated by run `template/**/*_spec_slow.ts`, + // see here 👉 https://github.com/electron/forge/pull/3468#issuecomment-1920805240 + await fs.remove(dir); + } + } else { + console.log(chalk.gray('There is no "electron-forge-test-*" dir that needs to be cleaned.')); + } +})(); diff --git a/yarn.lock b/yarn.lock index 92bb5f70a4..afa63c26f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1111,115 +1111,120 @@ fs-extra "^11.1.1" minimist "^1.2.8" -"@esbuild/android-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" - integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== - -"@esbuild/android-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" - integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== - -"@esbuild/android-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" - integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== - -"@esbuild/darwin-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" - integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== - -"@esbuild/darwin-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" - integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== - -"@esbuild/freebsd-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" - integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== - -"@esbuild/freebsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" - integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== - -"@esbuild/linux-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" - integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== - -"@esbuild/linux-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" - integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== - -"@esbuild/linux-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" - integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== - -"@esbuild/linux-loong64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" - integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== - -"@esbuild/linux-mips64el@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" - integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== - -"@esbuild/linux-ppc64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" - integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== - -"@esbuild/linux-riscv64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" - integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== - -"@esbuild/linux-s390x@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" - integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== - -"@esbuild/linux-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" - integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== - -"@esbuild/netbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" - integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== - -"@esbuild/openbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" - integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== - -"@esbuild/sunos-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" - integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== - -"@esbuild/win32-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" - integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== - -"@esbuild/win32-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" - integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== - -"@esbuild/win32-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" - integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== +"@esbuild/aix-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3" + integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g== + +"@esbuild/android-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz#b45d000017385c9051a4f03e17078abb935be220" + integrity sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q== + +"@esbuild/android-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz#f46f55414e1c3614ac682b29977792131238164c" + integrity sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw== + +"@esbuild/android-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz#bfc01e91740b82011ef503c48f548950824922b2" + integrity sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg== + +"@esbuild/darwin-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz#533fb7f5a08c37121d82c66198263dcc1bed29bf" + integrity sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ== + +"@esbuild/darwin-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz#62f3819eff7e4ddc656b7c6815a31cf9a1e7d98e" + integrity sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g== + +"@esbuild/freebsd-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a" + integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA== + +"@esbuild/freebsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz#7bdcc1917409178257ca6a1a27fe06e797ec18a2" + integrity sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw== + +"@esbuild/linux-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545" + integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg== + +"@esbuild/linux-arm@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz#ce82246d873b5534d34de1e5c1b33026f35e60e3" + integrity sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q== + +"@esbuild/linux-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4" + integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA== + +"@esbuild/linux-loong64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121" + integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg== + +"@esbuild/linux-mips64el@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz#38eecf1cbb8c36a616261de858b3c10d03419af9" + integrity sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg== + +"@esbuild/linux-ppc64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912" + integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA== + +"@esbuild/linux-riscv64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz#2dc4486d474a2a62bbe5870522a9a600e2acb916" + integrity sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ== + +"@esbuild/linux-s390x@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8" + integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q== + +"@esbuild/linux-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766" + integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA== + +"@esbuild/netbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz#d633c09492a1721377f3bccedb2d821b911e813d" + integrity sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ== + +"@esbuild/openbsd-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2" + integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw== + +"@esbuild/sunos-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767" + integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ== + +"@esbuild/win32-arm64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee" + integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ== + +"@esbuild/win32-ia32@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz#481a65fee2e5cce74ec44823e6b09ecedcc5194c" + integrity sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg== + +"@esbuild/win32-x64@0.19.11": + version "0.19.11" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04" + integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw== "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" @@ -2216,6 +2221,71 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@rollup/rollup-android-arm-eabi@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz#66b8d9cb2b3a474d115500f9ebaf43e2126fe496" + integrity sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg== + +"@rollup/rollup-android-arm64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz#46327d5b86420d2307946bec1535fdf00356e47d" + integrity sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw== + +"@rollup/rollup-darwin-arm64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz#166987224d2f8b1e2fd28ee90c447d52271d5e90" + integrity sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw== + +"@rollup/rollup-darwin-x64@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz#a2e6e096f74ccea6e2f174454c26aef6bcdd1274" + integrity sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog== + +"@rollup/rollup-linux-arm-gnueabihf@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz#09fcd4c55a2d6160c5865fec708a8e5287f30515" + integrity sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ== + +"@rollup/rollup-linux-arm64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz#19a3c0b6315c747ca9acf86e9b710cc2440f83c9" + integrity sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ== + +"@rollup/rollup-linux-arm64-musl@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz#94aaf95fdaf2ad9335983a4552759f98e6b2e850" + integrity sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ== + +"@rollup/rollup-linux-riscv64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz#160510e63f4b12618af4013bddf1761cf9fc9880" + integrity sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA== + +"@rollup/rollup-linux-x64-gnu@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz#5ac5d068ce0726bd0a96ca260d5bd93721c0cb98" + integrity sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw== + +"@rollup/rollup-linux-x64-musl@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz#bafa759ab43e8eab9edf242a8259ffb4f2a57a5d" + integrity sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ== + +"@rollup/rollup-win32-arm64-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz#1cc3416682e5a20d8f088f26657e6e47f8db468e" + integrity sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA== + +"@rollup/rollup-win32-ia32-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz#7d2251e1aa5e8a1e47c86891fe4547a939503461" + integrity sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ== + +"@rollup/rollup-win32-x64-msvc@4.9.6": + version "4.9.6" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz#2c1fb69e02a3f1506f52698cfdc3a8b6386df9a6" + integrity sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ== + "@sigstore/bundle@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@sigstore/bundle/-/bundle-1.1.0.tgz#17f8d813b09348b16eeed66a8cf1c3d6bd3d04f1" @@ -2874,7 +2944,7 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== -"@types/estree@^1.0.0": +"@types/estree@1.0.5", "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -5736,33 +5806,34 @@ es6-weak-map@^2.0.1: es6-iterator "^2.0.3" es6-symbol "^3.1.1" -esbuild@^0.18.10: - version "0.18.20" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" - integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== +esbuild@^0.19.3: + version "0.19.11" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.11.tgz#4a02dca031e768b5556606e1b468fe72e3325d96" + integrity sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA== optionalDependencies: - "@esbuild/android-arm" "0.18.20" - "@esbuild/android-arm64" "0.18.20" - "@esbuild/android-x64" "0.18.20" - "@esbuild/darwin-arm64" "0.18.20" - "@esbuild/darwin-x64" "0.18.20" - "@esbuild/freebsd-arm64" "0.18.20" - "@esbuild/freebsd-x64" "0.18.20" - "@esbuild/linux-arm" "0.18.20" - "@esbuild/linux-arm64" "0.18.20" - "@esbuild/linux-ia32" "0.18.20" - "@esbuild/linux-loong64" "0.18.20" - "@esbuild/linux-mips64el" "0.18.20" - "@esbuild/linux-ppc64" "0.18.20" - "@esbuild/linux-riscv64" "0.18.20" - "@esbuild/linux-s390x" "0.18.20" - "@esbuild/linux-x64" "0.18.20" - "@esbuild/netbsd-x64" "0.18.20" - "@esbuild/openbsd-x64" "0.18.20" - "@esbuild/sunos-x64" "0.18.20" - "@esbuild/win32-arm64" "0.18.20" - "@esbuild/win32-ia32" "0.18.20" - "@esbuild/win32-x64" "0.18.20" + "@esbuild/aix-ppc64" "0.19.11" + "@esbuild/android-arm" "0.19.11" + "@esbuild/android-arm64" "0.19.11" + "@esbuild/android-x64" "0.19.11" + "@esbuild/darwin-arm64" "0.19.11" + "@esbuild/darwin-x64" "0.19.11" + "@esbuild/freebsd-arm64" "0.19.11" + "@esbuild/freebsd-x64" "0.19.11" + "@esbuild/linux-arm" "0.19.11" + "@esbuild/linux-arm64" "0.19.11" + "@esbuild/linux-ia32" "0.19.11" + "@esbuild/linux-loong64" "0.19.11" + "@esbuild/linux-mips64el" "0.19.11" + "@esbuild/linux-ppc64" "0.19.11" + "@esbuild/linux-riscv64" "0.19.11" + "@esbuild/linux-s390x" "0.19.11" + "@esbuild/linux-x64" "0.19.11" + "@esbuild/netbsd-x64" "0.19.11" + "@esbuild/openbsd-x64" "0.19.11" + "@esbuild/sunos-x64" "0.19.11" + "@esbuild/win32-arm64" "0.19.11" + "@esbuild/win32-ia32" "0.19.11" + "@esbuild/win32-x64" "0.19.11" escalade@^3.1.1: version "3.1.1" @@ -6842,6 +6913,11 @@ fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -10791,7 +10867,7 @@ postcss-selector-parser@^6.0.10: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss@^8.4.27: +postcss@^8.4.32: version "8.4.33" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742" integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg== @@ -11465,11 +11541,26 @@ roarr@^2.15.3: semver-compare "^1.0.0" sprintf-js "^1.1.2" -rollup@^3.27.1: - version "3.29.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" - integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== +rollup@^4.2.0: + version "4.9.6" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.6.tgz#4515facb0318ecca254a2ee1315e22e09efc50a0" + integrity sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg== + dependencies: + "@types/estree" "1.0.5" optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.9.6" + "@rollup/rollup-android-arm64" "4.9.6" + "@rollup/rollup-darwin-arm64" "4.9.6" + "@rollup/rollup-darwin-x64" "4.9.6" + "@rollup/rollup-linux-arm-gnueabihf" "4.9.6" + "@rollup/rollup-linux-arm64-gnu" "4.9.6" + "@rollup/rollup-linux-arm64-musl" "4.9.6" + "@rollup/rollup-linux-riscv64-gnu" "4.9.6" + "@rollup/rollup-linux-x64-gnu" "4.9.6" + "@rollup/rollup-linux-x64-musl" "4.9.6" + "@rollup/rollup-win32-arm64-msvc" "4.9.6" + "@rollup/rollup-win32-ia32-msvc" "4.9.6" + "@rollup/rollup-win32-x64-msvc" "4.9.6" fsevents "~2.3.2" run-async@^2.2.0, run-async@^2.4.0: @@ -12950,16 +13041,16 @@ version-guard@^1.1.1: resolved "https://registry.yarnpkg.com/version-guard/-/version-guard-1.1.1.tgz#7a6e87a1babff1b43d6a7b0fd239731e278262fa" integrity sha512-MGQLX89UxmYHgDvcXyjBI0cbmoW+t/dANDppNPrno64rYr8nH4SHSuElQuSYdXGEs0mUzdQe1BY+FhVPNsAmJQ== -vite@^4.5.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.1.tgz#3370986e1ed5dbabbf35a6c2e1fb1e18555b968a" - integrity sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA== +vite@^5.0.12: + version "5.0.12" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47" + integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w== dependencies: - esbuild "^0.18.10" - postcss "^8.4.27" - rollup "^3.27.1" + esbuild "^0.19.3" + postcss "^8.4.32" + rollup "^4.2.0" optionalDependencies: - fsevents "~2.3.2" + fsevents "~2.3.3" vscode-jsonrpc@8.1.0: version "8.1.0"