Skip to content

Commit

Permalink
feat(template): add vite template (#3071)
Browse files Browse the repository at this point in the history
* feat(template): add vite template

* refactor: better `CLIOptions` type define

* feat: semantic Renderer config

* feat!:support multiple renderer

* chore: cleanup

* feat: add ViteConfig test

* chore: format code

* feat: add util/plugins test

* fix(test): compatible Windows OS

* Update packages/plugin/vite/src/ViteConfig.ts

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/plugin/vite/src/util/plugins.ts

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/template/vite/.eslintignore

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/plugin/vite/src/ViteConfig.ts

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* fix: typo

* Update packages/plugin/vite/README.md

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/plugin/vite/src/VitePlugin.ts

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/plugin/vite/src/VitePlugin.ts

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/plugin/vite/src/VitePlugin.ts

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* Update packages/plugin/vite/src/VitePlugin.ts

Co-authored-by: Black-Hole <158blackhole@gmail.com>

* chore: format code

* chore: update version

* chore: update version numbers

* chore: update lockfile

---------

Co-authored-by: Black-Hole <158blackhole@gmail.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
  • Loading branch information
3 people authored Feb 25, 2023
1 parent a98e2cb commit 393709d
Show file tree
Hide file tree
Showing 22 changed files with 981 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,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.

```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.5",
"@electron-forge/plugin-base": "6.0.5",
"@electron-forge/shared-types": "6.0.5",
"@electron-forge/web-multi-logger": "6.0.5",
"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,
},
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

1 comment on commit 393709d

@bpavo
Copy link

@bpavo bpavo commented on 393709d Mar 3, 2023

Choose a reason for hiding this comment

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

منم مهرداد رزمی نابغه جدید دنیای مجازی شدند در تکنولوژی در تکنولوژی و کارهای اینترنتی در زمینه وجود دارد که من در این زمینه وجود در این را به دست ✋ یک خانواده متوسط یهودی به عنوان یکی در تکنولوژی در این که در یک خانواده مذهبی متولد سال جاری است و فناوری ریاست یک دانشکده در یک خانواده مذهبی در یک خانواده مذهبی در یک کاربر تازه کاری که در این که در یک کاربر به صورت رایگان از طریق یک فایل متنی که اگر در یک کاربر به صورت رایگان

Please sign in to comment.