Skip to content

Commit

Permalink
feat: support vite template
Browse files Browse the repository at this point in the history
  • Loading branch information
caoxiemeihao committed Nov 14, 2022
1 parent 344a0af commit eb6d4af
Show file tree
Hide file tree
Showing 18 changed files with 816 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"source-map-support": "^0.5.13",
"sudo-prompt": "^9.1.1",
"username": "^5.1.0",
"vite": "^3.2.3",
"webpack": "^5.69.1",
"webpack-dev-server": "^4.0.0",
"webpack-merge": "^5.7.3",
Expand Down
30 changes: 30 additions & 0 deletions packages/plugin/vite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## 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.

```
// forge.config.js
module.exports = {
plugins: [
{
name: '@electron-forge/plugin-vite',
config: {
mainConfig: './vite.main.config.js',
renderer: {
config: './vite.renderer.config.js',
entryPoints: [
{
html: './src/index.html',
name: 'main_window',
preload: {
js: './src/preload.js',
},
},
],
},
},
}
]
}
```
31 changes: 31 additions & 0 deletions packages/plugin/vite/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "@electron-forge/plugin-vite",
"version": "0.0.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": {},
"devDependencies": {
"@types/node": "^18.0.3"
},
"engines": {
"node": ">= 14.18.0"
},
"dependencies": {
"@electron-forge/core-utils": "6.0.1",
"@electron-forge/plugin-base": "6.0.1",
"@electron-forge/shared-types": "6.0.1",
"@electron-forge/web-multi-logger": "6.0.1",
"chalk": "^4.0.0",
"debug": "^4.3.1",
"fs-extra": "^10.0.0",
"vite": "^3.2.3"
}
}
50 changes: 50 additions & 0 deletions packages/plugin/vite/src/Config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export interface VitePreloadEntryPoint {
/**
* Relative or absolute path to the preload JS file.
*/
js: string;
/**
* The optional vite config for your preload process.
* Defaults to the renderer vite config if blank.
*/
config?: string;
}

export interface VitePluginEntryPointBase {
/**
* Human friendly name of your entry point
*/
name: string;
}

export interface VitePluginEntryPoint extends VitePluginEntryPointBase {
/**
* Relative or absolute path to the HTML template file for this entry point.
*/
html: string;
/**
* Information about the preload script for this entry point. If you don't use
* preload scripts, you don't need to set this.
*/
preload?: VitePreloadEntryPoint;
}

export interface VitePluginRendererConfig {
/**
* The vite config for your renderer process
*/
config: string;
/**
* Array of entry points, these should map to the windows your app needs to
* open. Each window requires it's own entry point
*/
entryPoints: VitePluginEntryPoint[];
}

export interface VitePluginConfig {
/**
* The vite config for your main process
*/
mainConfig: string;
renderer: VitePluginRendererConfig;
}
83 changes: 83 additions & 0 deletions packages/plugin/vite/src/ViteConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import path from 'node:path';

import debug from 'debug';

import { VitePluginConfig, VitePluginEntryPoint } from './Config';

type ViteMode = 'production' | 'development';

const d = debug('electron-forge:plugin:webpack:webpackconfig');

export default class ViteConfigGenerator {
private isProd: boolean;

private pluginConfig: VitePluginConfig;

private port: number;

private projectDir!: string;

private baseDir!: string;

constructor(pluginConfig: VitePluginConfig, projectDir: string, isProd: boolean, port: number) {
this.pluginConfig = pluginConfig;
this.projectDir = projectDir;
this.baseDir = path.resolve(projectDir, '.vite');
this.isProd = isProd;
this.port = port;

d('Config mode:', this.mode);
}

get mode(): ViteMode {
return this.isProd ? 'production' : 'development';
}

private rendererEntryPoint(entryPoint: VitePluginEntryPoint, inRendererDir: boolean, basename: string): string {
if (this.isProd) {
return `\`file://$\{require('path').resolve(__dirname, '..', '${inRendererDir ? 'renderer' : '.'}', '${entryPoint.name}', '${basename}')}\``;
}
const baseUrl = `http://localhost:${this.port}/${entryPoint.name}`;
if (basename !== 'index.html') {
return `'${baseUrl}/${basename}'`;
}
return `'${baseUrl}'`;
}

getDefines(inRendererDir = true): Record<string, string> {
const defines: Record<string, string> = {};
if (!this.pluginConfig.renderer.entryPoints || !Array.isArray(this.pluginConfig.renderer.entryPoints)) {
throw new Error('Required config option "renderer.entryPoints" has not been defined');
}
for (const entryPoint of this.pluginConfig.renderer.entryPoints) {
const entryKey = this.toEnvironmentVariable(entryPoint);
// Vite uses html files as the entry point, so the html file is always present.
defines[entryKey] = this.rendererEntryPoint(entryPoint, inRendererDir, 'index.html');
defines[`process.env.${entryKey}`] = defines[entryKey];

const preloadDefineKey = this.toEnvironmentVariable(entryPoint, true);
defines[preloadDefineKey] = this.getPreloadDefine(entryPoint);
defines[`process.env.${preloadDefineKey}`] = defines[preloadDefineKey];
}

return defines;
}

private toEnvironmentVariable(entryPoint: VitePluginEntryPoint, preload = false): string {
const suffix = preload ? '_PRELOAD_WEBPACK_ENTRY' : '_WEBPACK_ENTRY';
return `${entryPoint.name.toUpperCase().replace(/ /g, '_')}${suffix}`;
}

private getPreloadDefine(entryPoint: VitePluginEntryPoint): string {
if (entryPoint.preload?.js) {
if (this.isProd) {
return `require('path').resolve(__dirname, '../renderer', '${entryPoint.name}', 'preload.js')`;
}
return `'${path.resolve(this.baseDir, 'renderer', entryPoint.name, 'preload.js').replace(/\\/g, '\\\\')}'`;
} else {
// If this entry-point has no configured preload script just map this constant to `undefined`
// so that any code using it still works. This makes quick-start / docs simpler.
return 'undefined';
}
}
}
Loading

0 comments on commit eb6d4af

Please sign in to comment.