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

feat(template): add vite template #3071

Merged
merged 26 commits into from
Feb 25, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f8b8863
feat(template): add vite template
caoxiemeihao Nov 13, 2022
f344601
refactor: better `CLIOptions` type define
caoxiemeihao Jan 11, 2023
381cfba
feat: semantic Renderer config
caoxiemeihao Jan 11, 2023
7a3bd0a
feat!:support multiple renderer
caoxiemeihao Jan 15, 2023
386f499
chore: cleanup
caoxiemeihao Jan 17, 2023
3c391f6
feat: add ViteConfig test
caoxiemeihao Jan 24, 2023
67ab9b8
chore: format code
caoxiemeihao Jan 25, 2023
fc2e585
feat: add util/plugins test
caoxiemeihao Jan 25, 2023
a654219
fix(test): compatible Windows OS
caoxiemeihao Jan 25, 2023
d8317a8
Update packages/plugin/vite/src/ViteConfig.ts
caoxiemeihao Jan 29, 2023
afe9e2a
Update packages/plugin/vite/src/util/plugins.ts
caoxiemeihao Jan 29, 2023
13e1cf7
Update packages/template/vite/.eslintignore
caoxiemeihao Jan 29, 2023
9d4a084
Update packages/plugin/vite/src/ViteConfig.ts
caoxiemeihao Jan 29, 2023
ac9262a
fix: typo
caoxiemeihao Jan 29, 2023
26d9376
Update packages/plugin/vite/README.md
caoxiemeihao Jan 29, 2023
0cb2d09
Update packages/plugin/vite/src/VitePlugin.ts
caoxiemeihao Jan 29, 2023
f523cf4
Update packages/plugin/vite/src/VitePlugin.ts
caoxiemeihao Jan 29, 2023
0d2956f
Update packages/plugin/vite/src/VitePlugin.ts
caoxiemeihao Jan 29, 2023
a1ee377
Update packages/plugin/vite/src/VitePlugin.ts
caoxiemeihao Jan 29, 2023
6835f64
chore: format code
caoxiemeihao Jan 30, 2023
ec48dd6
chore: update version
caoxiemeihao Feb 8, 2023
b026eea
Merge branch 'main' into caoxie-vite
erickzhao Feb 24, 2023
b465708
chore: update version numbers
erickzhao Feb 24, 2023
696bd62
Merge pull request #1 from electron/caoxie-vite
caoxiemeihao Feb 24, 2023
094bb64
chore: update lockfile
erickzhao Feb 24, 2023
89a63ac
Merge pull request #2 from electron/caoxie-vite
caoxiemeihao Feb 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"source-map-support": "^0.5.13",
"sudo-prompt": "^9.1.1",
"username": "^5.1.0",
"vite": "^4.1.1",
"webpack": "^5.69.1",
"webpack-dev-server": "^4.0.0",
"webpack-merge": "^5.7.3",
Expand Down
36 changes: 36 additions & 0 deletions packages/plugin/vite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## plugin-vite

This plugin makes it easy to set up standard vite tooling to compile both your main process code and your renderer process code, with built-in support for Hot Module Replacement (HMR) in the renderer process and support for multiple renderers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: replace this text with one specific for the vite plugin


```javascript
// forge.config.js

module.exports = {
plugins: [
{
name: '@electron-forge/plugin-vite',
config: {
// `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.js',
config: 'vite.main.config.mjs',
},
{
entry: 'src/preload.js',
config: 'vite.preload.config.mjs',
},
],
renderer: [
{
name: 'main_window',
config: 'vite.renderer.config.mjs',
},
],
},
},
],
};
```
38 changes: 38 additions & 0 deletions packages/plugin/vite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@electron-forge/plugin-vite",
"version": "6.1.0",
"description": "Vite plugin for Electron Forge, lets you use Vite directly in your tooling",
"repository": {
"type": "git",
"url": "https://github.com/electron/forge",
"directory": "packages/plugin/vite"
},
"author": "caoxiemeihao",
"license": "MIT",
"main": "dist/VitePlugin.js",
"typings": "dist/VitePlugin.d.ts",
"scripts": {
"test": "xvfb-maybe mocha --config ../../../.mocharc.js test/**/*_spec.ts"
},
"devDependencies": {
"@malept/cross-spawn-promise": "^2.0.0",
"@types/node": "^18.0.3",
"chai": "^4.3.3",
"fs-extra": "^10.0.0",
"mocha": "^9.0.1",
"which": "^2.0.2",
"xvfb-maybe": "^0.2.1"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"dependencies": {
"@electron-forge/core-utils": "6.0.4",
"@electron-forge/plugin-base": "6.0.4",
"@electron-forge/shared-types": "6.0.4",
"@electron-forge/web-multi-logger": "6.0.4",
"chalk": "^4.0.0",
"debug": "^4.3.1",
"vite": "^4.1.1"
}
}
34 changes: 34 additions & 0 deletions packages/plugin/vite/src/Config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { LibraryOptions } from 'vite';

export interface VitePluginBuildConfig {
/**
* Alias of `build.lib.entry` in `config`.
*/
entry?: LibraryOptions['entry'];
/**
* Vite config file path.
*/
config?: string;
}

export interface VitePluginRendererConfig {
/**
* Human friendly name of your entry point
*/
name: string;
/**
* Vite config file path.
*/
config: string;
}

export interface VitePluginConfig {
/**
* Build anything such as Main process, Preload scripts and Worker process, etc.
*/
build: VitePluginBuildConfig[];
/**
* Renderer process.
*/
renderer: VitePluginRendererConfig[];
}
129 changes: 129 additions & 0 deletions packages/plugin/vite/src/ViteConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
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';

const d = debug('electron-forge:plugin:vite:viteconfig');

/**
* 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<ReturnType<typeof loadConfigFromFile>>;

export default class ViteConfigGenerator {
private readonly baseDir: string;

private rendererConfigCache!: Promise<UserConfig>[];

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<ConfigEnv> = {}) {
// `command` is to be passed as an arguments when the user export a function in `vite.config.js`.
// @see - https://vitejs.dev/config/#conditional-config
configEnv.command ??= this.isProd ? 'build' : 'serve';
// `mode` affects `.env.[mode]` file loading.
configEnv.mode ??= this.mode;
return loadConfigFromFile(configEnv as ConfigEnv, config);
}

get mode(): string {
// Vite's `mode` can be passed in via command.
// Since we are currently using the JavaScript API, we are opinionated defining two default values for mode here.
// The `mode` set by the end user in `vite.config.js` has a higher priority.
return this.isProd ? 'production' : 'development';
}

async getDefines(): Promise<Record<string, string>> {
const defines: Record<string, any> = {};
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, '_');
// There is no guarantee that `port` will always be available, because it may auto increment.
// https://github.com/vitejs/vite/blob/v4.0.4/packages/vite/src/node/http.ts#L170
defines[`${NAME}_VITE_DEV_SERVER_URL`] = this.isProd
? undefined
: userConfig?.server?.port && JSON.stringify(`http://localhost:${userConfig.server.port}`);
defines[`${NAME}_VITE_NAME`] = JSON.stringify(name);
}
return defines;
}

async getBuildConfig(watch = false): Promise<UserConfig[]> {
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<Promise<UserConfig>>(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,
erickzhao marked this conversation as resolved.
Show resolved Hide resolved
},
clearScreen: false,
define,
plugins,
};
if (config) {
const loadResult = await this.resolveConfig(config);
return mergeConfig(defaultConfig, loadResult?.config ?? {});
}
return defaultConfig;
});

return await Promise.all(configs);
}

async getRendererConfig(): Promise<UserConfig[]> {
if (!Array.isArray(this.pluginConfig.renderer)) {
throw new Error('"config.renderer" must be an Array');
}

let port = 5173;
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: [] };
loadResult.config.server ??= {};
loadResult.config.server.port ??= port++;
return mergeConfig(defaultConfig, loadResult.config);
}));

return await Promise.all(configs);
}
}
Loading