Merge pull request #156 from electron-vite/dev

v2.0.0
This commit is contained in:
草鞋没号 2022-06-16 19:18:07 +08:00 committed by GitHub
commit 711599f332
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 155 additions and 8359 deletions

26
.gitignore vendored
View File

@ -1,10 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
*.local
.debug.env
tmp
**/.tmp
# Editor directories and files
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
release
.vscode/.debug.env
package-lock.json
pnpm-lock.yaml
yarn.lock

View File

@ -1,3 +0,0 @@
module.exports = {
// "pre-commit": "npx nano-staged",
};

View File

@ -11,3 +11,18 @@
```bash
Error: @vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc to be present in the dependency tree.
```
## 22-01-30
[v1.0.0](https://github.com/electron-vite/electron-vite-vue/releases/tag/v1.0.0)
- ⚡️ Main、Renderer、preload, all built with vite
## 21-06-04
v2.0.0
- 🖖 Based on the `vue-ts` template created by `npm create vite`, integrate `vite-plugin-electron`
- ⚡️ More simplify, is in line with Vite project structure

View File

@ -1,24 +0,0 @@
# use the version that corresponds to your electron version
FROM node:14.16
LABEL NAME="electron-wrapper"
LABEL RUN="docker run --rm -it electron-wrapper bash"
# install electron dependencies or more if your library has other dependencies
RUN apt-get update && apt-get install \
git libx11-xcb1 libxcb-dri3-0 libxtst6 libnss3 libatk-bridge2.0-0 libgtk-3-0 libxss1 libasound2 \
-yq --no-install-suggests --no-install-recommends \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# copy the source into /app
WORKDIR /app
COPY . .
RUN chown -R node /app
# install node modules and perform an electron rebuild
USER node
RUN npm install
RUN npm run build
USER node
CMD bash

View File

@ -1,4 +1,4 @@
import { app, BrowserWindow, shell,ipcMain } from 'electron'
import { app, BrowserWindow, shell, ipcMain } from 'electron'
import { release } from 'os'
import { join } from 'path'
@ -15,23 +15,24 @@ if (!app.requestSingleInstanceLock()) {
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
let win: BrowserWindow | null = null
// Here, you can also use other preload
const splash = join(__dirname, '../electron-preload/splash.js')
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`
async function createWindow() {
win = new BrowserWindow({
title: 'Main window',
webPreferences: {
preload: join(__dirname, '../preload/index.cjs'),
preload: splash,
nodeIntegration: true,
contextIsolation: false,
},
})
if (app.isPackaged) {
win.loadFile(join(__dirname, '../renderer/index.html'))
win.loadFile(join(__dirname, '../index.html'))
} else {
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`
win.loadURL(url)
// win.webContents.openDevTools()
}
@ -76,18 +77,16 @@ app.on('activate', () => {
ipcMain.handle("open-win", (event, arg) => {
const childWindow = new BrowserWindow({
webPreferences: {
preload: join(__dirname, "../preload/index.cjs"),
preload: splash,
},
});
})
if (app.isPackaged) {
childWindow.loadFile(join(__dirname, `../renderer/index.html`), {
hash: `${arg}`,
})
} else {
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = `http://${process.env["VITE_DEV_SERVER_HOST"]}:${process.env["VITE_DEV_SERVER_PORT"]}/#${arg}`
childWindow.loadURL(url);
childWindow.loadURL(`${url}/#${arg}`)
// childWindow.webContents.openDevTools({ mode: "undocked", activate: true })
}
});
})

View File

@ -1,10 +1,38 @@
function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
return new Promise(resolve => {
if (condition.includes(document.readyState)) {
resolve(true)
} else {
document.addEventListener('readystatechange', () => {
if (condition.includes(document.readyState)) {
resolve(true)
}
})
}
})
}
const safeDOM = {
append(parent: HTMLElement, child: HTMLElement) {
if (!Array.from(parent.children).find(e => e === child)) {
return parent.appendChild(child)
}
},
remove(parent: HTMLElement, child: HTMLElement) {
if (Array.from(parent.children).find(e => e === child)) {
return parent.removeChild(child)
}
},
}
/**
* https://tobiasahlin.com/spinkit
* https://connoratherton.com/loaders
* https://projects.lukehaas.me/css-loaders
* https://matejkustec.github.io/SpinThatShit
*/
export function useLoading() {
function useLoading() {
const className = `loaders-css__square-spin`
const styleContent = `
@keyframes square-spin {
@ -43,25 +71,18 @@ export function useLoading() {
return {
appendLoading() {
safe.append(document.head, oStyle)
safe.append(document.body, oDiv)
safeDOM.append(document.head, oStyle)
safeDOM.append(document.body, oDiv)
},
removeLoading() {
safe.remove(document.head, oStyle)
safe.remove(document.body, oDiv)
safeDOM.remove(document.head, oStyle)
safeDOM.remove(document.body, oDiv)
},
}
}
const safe = {
append(parent: HTMLElement, child: HTMLElement) {
if (!Array.from(parent.children).find(e => e === child)) {
return parent.appendChild(child)
}
},
remove(parent: HTMLElement, child: HTMLElement) {
if (Array.from(parent.children).find(e => e === child)) {
return parent.removeChild(child)
}
},
}
// ----------------------------------------------------------------------
const { appendLoading, removeLoading } = useLoading()
window.removeLoading = removeLoading
domReady().then(appendLoading)

View File

@ -1,7 +0,0 @@
export default {
// eslint
'*.{js,ts,tsx,vue}': 'eslint --cache --fix',
// typecheck
'packages/renderer/**/{*.ts,*.tsx,*.vue,tsconfig.json}': ({ filenames }) =>
'npm run typecheck',
}

7975
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,27 @@
{
"name": "electron-vue-vite",
"version": "1.0.0",
"main": "dist/main/index.cjs",
"version": "2.0.0",
"main": "dist/electron-main/index.js",
"author": "草鞋没号 <308487730@qq.com>",
"license": "MIT",
"private": true,
"scripts": {
"dev": "node scripts/watch.mjs",
"prebuild": "vue-tsc --noEmit --p packages/renderer/tsconfig.json && node scripts/build.mjs",
"build": "electron-builder",
"init": "git config core.hooksPath .git/hooks/ && rm -rf .git/hooks && npx simple-git-hooks",
"test:e2e": "npx playwright test",
"test:e2e:headless": "npx playwright test --headed"
"dev": "vite",
"build": "vue-tsc --noEmit && vite build && electron-builder"
},
"engines": {
"node": ">=14.17.0"
},
"devDependencies": {
"@playwright/test": "^1.22.2",
"@vitejs/plugin-vue": "^2.3.2",
"electron": "19.0.1",
"@vitejs/plugin-vue": "^2.3.3",
"electron": "^19.0.3",
"electron-builder": "^23.0.3",
"nano-staged": "^0.8.0",
"simple-git-hooks": "^2.8.0",
"typescript": "^4.7.2",
"vite": "^2.9.8",
"vite-plugin-electron": "^0.4.5",
"typescript": "^4.7.3",
"vite": "^2.9.9",
"vite-plugin-electron": "^0.4.6",
"vite-plugin-resolve": "^2.1.2",
"vue": "^3.2.36",
"vue-tsc": "^0.35.2"
"vue-tsc": "^0.36.0"
},
"env": {
"VITE_DEV_SERVER_HOST": "127.0.0.1",

View File

@ -1,26 +0,0 @@
import { builtinModules } from 'module'
import { defineConfig } from 'vite'
import pkg from '../../package.json'
export default defineConfig({
root: __dirname,
build: {
outDir: '../../dist/main',
emptyOutDir: true,
minify: process.env./* from mode option */NODE_ENV === 'production',
sourcemap: true,
lib: {
entry: 'index.ts',
formats: ['cjs'],
fileName: () => '[name].cjs',
},
rollupOptions: {
external: [
'electron',
...builtinModules,
// @ts-ignore
...Object.keys(pkg.dependencies || {}),
],
},
},
})

View File

@ -1,7 +0,0 @@
import { domReady } from './utils'
import { useLoading } from './loading'
const { appendLoading, removeLoading } = useLoading()
window.removeLoading = removeLoading
domReady().then(appendLoading)

View File

@ -1,15 +0,0 @@
/** docoment ready */
export function domReady(condition: DocumentReadyState[] = ['complete', 'interactive']) {
return new Promise(resolve => {
if (condition.includes(document.readyState)) {
resolve(true)
} else {
document.addEventListener('readystatechange', () => {
if (condition.includes(document.readyState)) {
resolve(true)
}
})
}
})
}

View File

@ -1,32 +0,0 @@
import { join } from 'path'
import { builtinModules } from 'module'
import { defineConfig } from 'vite'
import pkg from '../../package.json'
export default defineConfig({
root: __dirname,
build: {
outDir: '../../dist/preload',
emptyOutDir: true,
minify: process.env./* from mode option */NODE_ENV === 'production',
// https://github.com/caoxiemeihao/electron-vue-vite/issues/61
sourcemap: 'inline',
rollupOptions: {
input: {
// multiple entry
index: join(__dirname, 'index.ts'),
},
output: {
format: 'cjs',
entryFileNames: '[name].cjs',
manualChunks: {},
},
external: [
'electron',
...builtinModules,
// @ts-ignore
...Object.keys(pkg.dependencies || {}),
],
},
},
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 MiB

View File

@ -1,16 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

View File

@ -1,59 +0,0 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import resolve, { lib2esm } from 'vite-plugin-resolve'
import electron from 'vite-plugin-electron/renderer'
import pkg from '../../package.json'
// https://vitejs.dev/config/
export default defineConfig({
mode: process.env.NODE_ENV,
root: __dirname,
plugins: [
vue(),
electron(),
resolve(
/**
* Here you can specify other modules
* 🚧 You have to make sure that your module is in `dependencies` and not in the` devDependencies`,
* which will ensure that the electron-builder can package it correctly
*/
{
// If you use the following modules, the following configuration will work
// What they have in common is that they will return - ESM format code snippets
// ESM format string
'electron-store': 'export default require("electron-store");',
// Use lib2esm() to easy to convert ESM
// Equivalent to
/**
* sqlite3: () => `
* const _M_ = require('sqlite3');
* const _D_ = _M_.default || _M_;
* export { _D_ as default }
* `
*/
sqlite3: lib2esm('sqlite3', { format: 'cjs' }),
serialport: lib2esm(
// CJS lib name
'serialport',
// export memebers
[
'SerialPort',
'SerialPortMock',
],
{ format: 'cjs' },
),
}
),
],
base: './',
build: {
outDir: '../../dist/renderer',
emptyOutDir: true,
sourcemap: true,
},
server: {
host: pkg.env.VITE_DEV_SERVER_HOST,
port: pkg.env.VITE_DEV_SERVER_PORT,
},
})

View File

@ -1,16 +0,0 @@
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
use: {
trace: 'on-first-retry',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
};
export default config;

View File

Before

Width:  |  Height:  |  Size: 3.3 MiB

After

Width:  |  Height:  |  Size: 3.3 MiB

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,5 +0,0 @@
import { build } from 'vite'
await build({ configFile: 'packages/main/vite.config.ts' })
await build({ configFile: 'packages/preload/vite.config.ts' })
await build({ configFile: 'packages/renderer/vite.config.ts' })

View File

@ -1,98 +0,0 @@
import { spawn } from 'child_process'
import { createServer, build } from 'vite'
import electron from 'electron'
import readline from 'readline'
const query = new URLSearchParams(import.meta.url.split('?')[1])
const debug = query.has('debug')
/** The log will display on the next screen */
function clearConsole() {
const blank = '\n'.repeat(process.stdout.rows)
console.log(blank)
readline.cursorTo(process.stdout, 0, 0)
readline.clearScreenDown(process.stdout)
}
/**
* @type {(server: import('vite').ViteDevServer) => Promise<import('rollup').RollupWatcher>}
*/
function watchMain(server) {
/**
* @type {import('child_process').ChildProcessWithoutNullStreams | null}
*/
let electronProcess = null
const address = server.httpServer.address()
const env = Object.assign(process.env, {
VITE_DEV_SERVER_HOST: address.address,
VITE_DEV_SERVER_PORT: address.port,
})
/**
* @type {import('vite').Plugin}
*/
const startElectron = {
name: 'electron-main-watcher',
writeBundle() {
clearConsole()
if (electronProcess) {
electronProcess.removeAllListeners()
electronProcess.kill()
}
electronProcess = spawn(electron, ['.'], { env })
electronProcess.once('exit', process.exit)
// https://github.com/electron-vite/electron-vite-vue/pull/129
electronProcess.stdout.on('data', (data) => {
const str = data.toString().trim()
str && console.log(str)
})
electronProcess.stderr.on('data', (data) => {
const str = data.toString().trim()
str && console.error(str)
})
},
}
return build({
configFile: 'packages/main/vite.config.ts',
mode: 'development',
plugins: [!debug && startElectron].filter(Boolean),
build: {
watch: {},
},
})
}
/**
* @type {(server: import('vite').ViteDevServer) => Promise<import('rollup').RollupWatcher>}
*/
function watchPreload(server) {
return build({
configFile: 'packages/preload/vite.config.ts',
mode: 'development',
plugins: [{
name: 'electron-preload-watcher',
writeBundle() {
clearConsole()
server.ws.send({ type: 'full-reload' })
},
}],
build: {
watch: {},
},
})
}
// Block the CTRL + C shortcut on a Windows terminal and exit the application without displaying a query
if (process.platform === 'win32') {
readline.createInterface({ input: process.stdin, output: process.stdout }).on('SIGINT', process.exit)
}
// bootstrap
const server = await createServer({ configFile: 'packages/renderer/vite.config.ts' })
await server.listen()
await watchPreload(server)
await watchMain(server)

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue'
</script>
@ -14,8 +14,8 @@ import HelloWorld from './components/HelloWorld.vue'
</div>
<HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
<div class="static-public">
Place static files into the <code>src/renderer/public</code> folder
<img style="width:90px;" :src="'./images/node.png'" >
Place static files into the <code>/public</code> folder
<img style="width:77px;" :src="'./node.png'" >
</div>
</template>
@ -34,17 +34,14 @@ import HelloWorld from './components/HelloWorld.vue'
width: 100%;
justify-content: center;
}
.logo-box span {
width: 74px;
}
.static-public {
display: flex;
align-items: center;
justify-content: center;
}
.static-public code {
background-color: #eee;
padding: 2px 4px;

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -11,7 +11,7 @@ const count = ref(0)
<p>
Recommended IDE setup:
<a href="https://code.visualstudio.com/" target="_blank">VSCode</a>
<a href="https://code.visualstudio.com/" target="_blank">VS Code</a>
+
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
</p>

View File

@ -1,7 +1,7 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import { DefineComponent } from 'vue'
import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component

View File

@ -1,4 +1,5 @@
export { }
declare global {

View File

@ -1,16 +0,0 @@
// example.spec.ts
import { test, expect } from '@playwright/test'
import { env } from '../package.json'
const VITE_SERVER_ADDRESS = `http://127.0.0.1:${env.PORT || 3344}`
test('example test case', async ({ page }) => {
await page.goto(VITE_SERVER_ADDRESS)
// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Vite App/)
// Expect an attribute "Hello Vue 3 + TypeScript + Vite" to be visible on the page.
await expect(
page.locator('text=Hello Vue 3 + TypeScript + Vite').first(),
).toBeVisible()
})

View File

@ -13,5 +13,8 @@
"paths": {},
"allowSyntheticDefaultImports": true,
"skipLibCheck": true
}
},
"references": [
{ "path": "./tsconfig.node.json" }
]
}

8
tsconfig.node.json Normal file
View File

@ -0,0 +1,8 @@
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node"
},
"include": ["vite.config.ts"]
}

39
vite.config.ts Normal file
View File

@ -0,0 +1,39 @@
import { rmSync } from 'fs'
import { join } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import electron from 'vite-plugin-electron'
import renderer from 'vite-plugin-electron/renderer'
rmSync('dist', { recursive: true, force: true }) // v14.14.0
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
electron({
main: {
entry: 'electron-main/index.ts',
vite: {
build: {
sourcemap: false,
},
},
},
preload: {
input: {
// You can configure multiple preload here
splash: join(__dirname, 'electron-preload/splash.ts'),
},
vite: {
build: {
// For debug
sourcemap: 'inline',
}
}
},
}),
// Enable use Electron, Node.js API in Renderer-process
renderer(),
],
})