From 394686c453b177bfdad9c4ef3df290b389285303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=89=E9=9E=8B=E6=B2=A1=E5=8F=B7?= <308487730@qq.com> Date: Wed, 6 Sep 2023 10:15:16 +0800 Subject: [PATCH 1/5] refactor: use `vite-plugin-electron` simple API --- src/index.ts | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6290eac..afd4c2e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -272,46 +272,56 @@ function setupElectron(root: string, framework: Framework) { }) // main.ts - const snippets = `postMessage({ payload: 'removeLoading' }, '*')` + const snippets = (indent = 0) => ` +// Remove Preload scripts loading +postMessage({ payload: 'removeLoading' }, '*') + +// Use contextBridge +window.ipcRenderer.on('main-process-message', (_event, message) => { + console.log(message) +}) +`.trim() + .split('\n') + .map(line => line ? ' '.repeat(indent) + line : line) + .join('\n') if (framework === 'vue') { editFile(path.join(root, 'src/main.ts'), content => - content.replace(`mount('#app')`, `mount('#app').$nextTick(() => ${snippets})`) + content.replace(`mount('#app')`, `mount('#app').$nextTick(() => {\n${snippets(2)}\n})`) ) } else if (framework === 'react') { - editFile(path.join(root, 'src/main.tsx'), content => `${content}\n${snippets}\n`) + editFile(path.join(root, 'src/main.tsx'), content => `${content}\n${snippets()}\n`) } else if (framework === 'vanilla') { - editFile(path.join(root, 'src/main.ts'), content => `${content}\n${snippets}\n`) + editFile(path.join(root, 'src/main.ts'), content => `${content}\n${snippets()}\n`) } // vite.config.ts - const electronPlugin = `electron([ - { - // Main-Process entry file of the Electron App. + const electronPlugin = `electron({ + main: { + // Shortcut of \`build.lib.entry\`. entry: 'electron/main.ts', }, - { - entry: 'electron/preload.ts', - onstart(options) { - // Notify the Renderer-Process to reload the page when the Preload-Scripts build is complete, - // instead of restarting the entire Electron App. - options.reload() - }, + preload: { + // Shortcut of \`build.rollupOptions.input\`. + // Preload scripts may contain Web assets, so use the \`build.rollupOptions.input\` instead \`build.lib.entry\`. + input: path.join(__dirname, 'electron/preload.ts'), }, - ])` + // Ployfill the Electron and Node.js built-in modules for Renderer process. + // See 👉 https://github.com/electron-vite/vite-plugin-electron-renderer + renderer: {}, + })` if (framework === 'vue' || framework === 'react') { editFile(path.join(root, 'vite.config.ts'), content => content .split('\n') .map(line => line.includes("import { defineConfig } from 'vite'") ? `${line} -import electron from 'vite-plugin-electron' -import renderer from 'vite-plugin-electron-renderer'` +import path from 'node:path' +import electron from 'vite-plugin-electron/simple'` : line) .map(line => line.trimStart().startsWith('plugins') ? ` plugins: [ ${framework}(), ${electronPlugin}, - renderer(), ],` : line) .join('\n') @@ -321,14 +331,13 @@ import renderer from 'vite-plugin-electron-renderer'` path.join(root, 'vite.config.ts'), ` import { defineConfig } from 'vite' -import electron from 'vite-plugin-electron' -import renderer from 'vite-plugin-electron-renderer' +import path from 'node:path' +import electron from 'vite-plugin-electron/simple' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ ${electronPlugin}, - renderer(), ], }) `.trimStart() From 7114cac6611230146c21426a03043d38dba02a96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=89=E9=9E=8B=E6=B2=A1=E5=8F=B7?= <308487730@qq.com> Date: Wed, 6 Sep 2023 10:34:54 +0800 Subject: [PATCH 2/5] chore: site use `https://electron-vite.github.io` --- src/index.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index afd4c2e..f46e464 100644 --- a/src/index.ts +++ b/src/index.ts @@ -360,13 +360,20 @@ export default defineConfig({ .join('\n') ) - // electron-vite.svg + // site 👉 https://electron-vite.github.io + // logo 👉 electron-vite.svg if (framework === 'vue') { - editFile(path.join(root, 'src/App.vue'), content => content.replace('/vite.svg', '/electron-vite.svg')) + editFile(path.join(root, 'src/App.vue'), content => content + .replace('https://vitejs.dev', 'https://electron-vite.github.io') + .replace('/vite.svg', '/electron-vite.svg')) } else if (framework === 'react') { - editFile(path.join(root, 'src/App.tsx'), content => content.replace('/vite.svg', '/electron-vite.animate.svg')) + editFile(path.join(root, 'src/App.tsx'), content => content + .replace('https://vitejs.dev', 'https://electron-vite.github.io') + .replace('/vite.svg', '/electron-vite.animate.svg')) } else if (framework === 'vanilla') { - editFile(path.join(root, 'src/main.ts'), content => content.replace('/vite.svg', '/electron-vite.svg')) + editFile(path.join(root, 'src/main.ts'), content => content + .replace('https://vitejs.dev', 'https://electron-vite.github.io') + .replace('/vite.svg', '/electron-vite.svg')) } } From f5dafdfa896c88ab4fbfb49e4379cfacd92db89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=89=E9=9E=8B=E6=B2=A1=E5=8F=B7?= <308487730@qq.com> Date: Wed, 6 Sep 2023 10:49:05 +0800 Subject: [PATCH 3/5] chore: update template --- electron/electron-builder.json5 | 17 ++++++++++++----- electron/electron-env.d.ts | 7 ++++++- electron/main.ts | 20 +++++++++++++++++--- electron/package.json | 6 +++--- electron/preload.ts | 25 +++++++++++++++++++++++++ template-react-ts/.eslintrc.cjs | 8 ++++++-- template-react-ts/index.html | 2 +- template-react-ts/package.json | 18 +++++++++--------- template-react-ts/src/main.tsx | 2 +- template-vanilla-ts/index.html | 2 +- template-vanilla-ts/package.json | 4 ++-- template-vue-ts/index.html | 2 +- template-vue-ts/package.json | 10 +++++----- template-vue-ts/tsconfig.json | 2 +- 14 files changed, 90 insertions(+), 35 deletions(-) diff --git a/electron/electron-builder.json5 b/electron/electron-builder.json5 index cc2fca2..3ff2bfe 100644 --- a/electron/electron-builder.json5 +++ b/electron/electron-builder.json5 @@ -5,18 +5,19 @@ "$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json", "appId": "YourAppID", "asar": true, + "productName": "YourAppName", "directories": { "output": "release/${version}" }, "files": [ - "dist-electron", - "dist" + "dist", + "dist-electron" ], "mac": { - "artifactName": "${productName}_${version}.${ext}", "target": [ "dmg" - ] + ], + "artifactName": "${productName}-Mac-${version}-Installer.${ext}" }, "win": { "target": [ @@ -27,12 +28,18 @@ ] } ], - "artifactName": "${productName}_${version}.${ext}" + "artifactName": "${productName}-Windows-${version}-Setup.${ext}" }, "nsis": { "oneClick": false, "perMachine": false, "allowToChangeInstallationDirectory": true, "deleteAppDataOnUninstall": false + }, + "linux": { + "target": [ + "AppImage" + ], + "artifactName": "${productName}-Linux-${version}.${ext}" } } diff --git a/electron/electron-env.d.ts b/electron/electron-env.d.ts index 8b65abb..bf0cd46 100644 --- a/electron/electron-env.d.ts +++ b/electron/electron-env.d.ts @@ -17,6 +17,11 @@ declare namespace NodeJS { */ DIST: string /** /dist/ or /public/ */ - PUBLIC: string + VITE_PUBLIC: string } } + +// Used in Renderer process, expose in `preload.ts` +interface Window { + ipcRenderer: import('electron').IpcRenderer +} diff --git a/electron/main.ts b/electron/main.ts index ab5010a..b3b388b 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -11,7 +11,7 @@ import path from 'node:path' // │ │ └── preload.js // │ process.env.DIST = path.join(__dirname, '../dist') -process.env.PUBLIC = app.isPackaged ? process.env.DIST : path.join(process.env.DIST, '../public') +process.env.VITE_PUBLIC = app.isPackaged ? process.env.DIST : path.join(process.env.DIST, '../public') let win: BrowserWindow | null @@ -20,7 +20,7 @@ const VITE_DEV_SERVER_URL = process.env['VITE_DEV_SERVER_URL'] function createWindow() { win = new BrowserWindow({ - icon: path.join(process.env.PUBLIC, 'electron-vite.svg'), + icon: path.join(process.env.VITE_PUBLIC, 'electron-vite.svg'), webPreferences: { preload: path.join(__dirname, 'preload.js'), }, @@ -39,8 +39,22 @@ function createWindow() { } } +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. app.on('window-all-closed', () => { - win = null + if (process.platform !== 'darwin') { + app.quit() + win = null + } +}) + +app.on('activate', () => { + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) { + createWindow() + } }) app.whenReady().then(createWindow) diff --git a/electron/package.json b/electron/package.json index 9bdca18..5305032 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,8 +1,8 @@ { "devDependencies": { - "electron": "^24.4.0", - "electron-builder": "^23.6.0", - "vite-plugin-electron": "^0.11.2", + "electron": "^26.1.0", + "electron-builder": "^24.6.4", + "vite-plugin-electron": "^0.14.0", "vite-plugin-electron-renderer": "^0.14.5" } } \ No newline at end of file diff --git a/electron/preload.ts b/electron/preload.ts index 4a771f8..ec4ff00 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -1,3 +1,28 @@ +import { contextBridge, ipcRenderer } from 'electron' + +// --------- Expose some API to the Renderer process --------- +contextBridge.exposeInMainWorld('ipcRenderer', withPrototype(ipcRenderer)) + +// `exposeInMainWorld` can't detect attributes and methods of `prototype`, manually patching it. +function withPrototype(obj: Record) { + const protos = Object.getPrototypeOf(obj) + + for (const [key, value] of Object.entries(protos)) { + if (Object.prototype.hasOwnProperty.call(obj, key)) continue + + if (typeof value === 'function') { + // Some native APIs, like `NodeJS.EventEmitter['on']`, don't work in the Renderer process. Wrapping them into a function. + obj[key] = function (...args: any) { + return value.call(obj, ...args) + } + } else { + obj[key] = value + } + } + return obj +} + +// --------- Preload scripts loading --------- function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) { return new Promise(resolve => { if (condition.includes(document.readyState)) { diff --git a/template-react-ts/.eslintrc.cjs b/template-react-ts/.eslintrc.cjs index 4020bcb..d6c9537 100644 --- a/template-react-ts/.eslintrc.cjs +++ b/template-react-ts/.eslintrc.cjs @@ -1,14 +1,18 @@ module.exports = { + root: true, env: { browser: true, es2020: true }, extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended', ], + ignorePatterns: ['dist', '.eslintrc.cjs'], parser: '@typescript-eslint/parser', - parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, plugins: ['react-refresh'], rules: { - 'react-refresh/only-export-components': 'warn', + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], }, } diff --git a/template-react-ts/index.html b/template-react-ts/index.html index e0d1c84..e4b78ea 100644 --- a/template-react-ts/index.html +++ b/template-react-ts/index.html @@ -1,4 +1,4 @@ - + diff --git a/template-react-ts/package.json b/template-react-ts/package.json index 63bd229..978382a 100644 --- a/template-react-ts/package.json +++ b/template-react-ts/package.json @@ -14,15 +14,15 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@types/react": "^18.0.37", - "@types/react-dom": "^18.0.11", - "@typescript-eslint/eslint-plugin": "^5.59.0", - "@typescript-eslint/parser": "^5.59.0", - "@vitejs/plugin-react": "^4.0.0", - "eslint": "^8.38.0", + "@types/react": "^18.2.21", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.6.0", + "@typescript-eslint/parser": "^6.6.0", + "@vitejs/plugin-react": "^4.0.4", + "eslint": "^8.48.0", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-refresh": "^0.3.4", - "typescript": "^5.0.2", - "vite": "^4.3.2" + "eslint-plugin-react-refresh": "^0.4.3", + "typescript": "^5.2.2", + "vite": "^4.4.9" } } diff --git a/template-react-ts/src/main.tsx b/template-react-ts/src/main.tsx index 91c03f3..3d7150d 100644 --- a/template-react-ts/src/main.tsx +++ b/template-react-ts/src/main.tsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom/client' import App from './App.tsx' import './index.css' -ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( +ReactDOM.createRoot(document.getElementById('root')!).render( , diff --git a/template-vanilla-ts/index.html b/template-vanilla-ts/index.html index f86e483..44a9335 100644 --- a/template-vanilla-ts/index.html +++ b/template-vanilla-ts/index.html @@ -1,4 +1,4 @@ - + diff --git a/template-vanilla-ts/package.json b/template-vanilla-ts/package.json index 7c063e0..75f6764 100644 --- a/template-vanilla-ts/package.json +++ b/template-vanilla-ts/package.json @@ -9,7 +9,7 @@ "preview": "vite preview" }, "devDependencies": { - "typescript": "^5.0.2", - "vite": "^4.3.2" + "typescript": "^5.2.2", + "vite": "^4.4.9" } } diff --git a/template-vue-ts/index.html b/template-vue-ts/index.html index 143557b..dde16aa 100644 --- a/template-vue-ts/index.html +++ b/template-vue-ts/index.html @@ -1,4 +1,4 @@ - + diff --git a/template-vue-ts/package.json b/template-vue-ts/package.json index 6dfe106..b795f14 100644 --- a/template-vue-ts/package.json +++ b/template-vue-ts/package.json @@ -9,12 +9,12 @@ "preview": "vite preview" }, "dependencies": { - "vue": "^3.2.47" + "vue": "^3.3.4" }, "devDependencies": { - "@vitejs/plugin-vue": "^4.1.0", - "typescript": "^5.0.2", - "vite": "^4.3.2", - "vue-tsc": "^1.4.2" + "@vitejs/plugin-vue": "^4.3.4", + "typescript": "^5.2.2", + "vite": "^4.4.9", + "vue-tsc": "^1.8.8" } } diff --git a/template-vue-ts/tsconfig.json b/template-vue-ts/tsconfig.json index f82888f..9e03e60 100644 --- a/template-vue-ts/tsconfig.json +++ b/template-vue-ts/tsconfig.json @@ -20,6 +20,6 @@ "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] } From 38af79d21a5ea49b95b3436f1a57f8bfe17ad175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=89=E9=9E=8B=E6=B2=A1=E5=8F=B7?= <308487730@qq.com> Date: Wed, 6 Sep 2023 10:58:53 +0800 Subject: [PATCH 4/5] chore: test v0.4.0 --- __tests__/cli.spec.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/__tests__/cli.spec.ts b/__tests__/cli.spec.ts index 13708ef..fee6859 100644 --- a/__tests__/cli.spec.ts +++ b/__tests__/cli.spec.ts @@ -1,13 +1,13 @@ -import { join } from 'node:path' +import fs from 'node:fs' +import path from 'node:path' import type { ExecaSyncReturnValue, SyncOptions } from 'execa' import { execaCommandSync } from 'execa' -import fs from 'fs-extra' import { afterEach, beforeAll, expect, test } from 'vitest' -const CLI_PATH = join(__dirname, '..') +const CLI_PATH = path.join(__dirname, '..') const projectName = 'electron-vite-app' -const generatePath = join(__dirname, projectName) +const generatePath = path.join(__dirname, projectName) const run = ( args: string[], @@ -18,15 +18,15 @@ const run = ( const createNonEmptyDir = () => { // Create the temporary directory - fs.mkdirpSync(generatePath) + fs.mkdirSync(generatePath, { recursive: true }) // Create a package.json file - const pkgJson = join(generatePath, 'package.json') + const pkgJson = path.join(generatePath, 'package.json') fs.writeFileSync(pkgJson, '{ "foo": "bar" }') } -beforeAll(() => fs.remove(generatePath)) -afterEach(() => fs.remove(generatePath)) +beforeAll(() => fs.rmSync(generatePath, { recursive: true, force: true })) +afterEach(() => fs.rmSync(generatePath, { recursive: true, force: true })) test('prompts for the project name if none supplied', () => { const { stdout } = run([]) @@ -34,7 +34,7 @@ test('prompts for the project name if none supplied', () => { }) test('prompts for project template if none supplied when target dir is current directory', () => { - fs.mkdirpSync(generatePath) + fs.mkdirSync(generatePath, { recursive: true }) const { stdout } = run(['.'], { cwd: generatePath }) expect(stdout).toContain('Project template:') }) From cd51d752036fe2eae7d2fcffa7ea6978d74cf3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8D=89=E9=9E=8B=E6=B2=A1=E5=8F=B7?= <308487730@qq.com> Date: Wed, 6 Sep 2023 10:59:30 +0800 Subject: [PATCH 5/5] v0.4.0 --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ package.json | 4 ++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 926bfb6..a556b33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,43 @@ +## 0.4.0 (2023-09-06) + +- 38af79d chore: test v0.4.0 +- f5dafdf chore: update template +- 7114cac chore: site use `https://electron-vite.github.io` +- 394686c refactor: use `vite-plugin-electron` simple API + +#### Main Changed + +**0.4.0** use the simple API of `vite-plugin-electron` + +```ts +import electron from 'vite-plugin-electron/simple' + +electron({ + main: { + entry: 'electron/main.ts', + }, + preload: { + input: __dirname + '/electron/preload.ts', + }, + renderer: {}, +}) +``` + +**0.3.0** + +```ts +import electron from 'vite-plugin-electron' + +electron([ + { + entry: 'electron/main.ts', + }, + { + entry: 'electron/preload.ts', + }, +]) +``` + ## 0.3.0 (2023-05-27) 42dc950 refactor: use Vite instead unbuild diff --git a/package.json b/package.json index d518bc7..9b42e94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "create-electron-vite", - "version": "0.3.0", + "version": "0.4.0", "type": "module", "description": "Scaffolding Your Electron + Vite Project", "license": "MIT", @@ -33,7 +33,7 @@ "scripts": { "watch": "vite build --watch", "build": "vite build", - "prepublishOnly": "npm run build", + "prepublishOnly": "npm run build && npm run test", "lint": "eslint .", "test": "vitest run" },