Compare commits

...

210 Commits
v1.0.0 ... main

Author SHA1 Message Date
草鞋没号 d51d45b38c refactor: reintegrate `tailwindcss` #178, #180 2023-10-12 10:00:25 +08:00
草鞋没号 767cde8f25 refactor: remove update-tailwind 2023-10-12 09:49:24 +08:00
阿菜 Cai b1f19196df
chore: change build scripts(#175) 2023-09-28 16:12:09 +08:00
阿菜 Cai d78dcf8822
feat(update): use `tailwindcss` (#174)
* feat(update): use `tailwindcss`

* chore: clean up code specifications
2023-09-28 09:52:30 +08:00
阿菜 Cai aea7cc5b31
refactor: using `css` instead of `scss` (#168)
* refactor: using `css` instead of `scss`

 remove dependency `scss`

* fix: progress bar display

* fix: `className` error
2023-09-19 16:20:29 +08:00
阿菜 Cai 766b9fb206
chore: bump dependencies (#164) 2023-08-22 16:44:05 +08:00
草鞋没号 d548009325 chore: update types 2023-08-02 11:01:49 +08:00
CommandMaker 4bb103c014
fix: Rename PUBLIC environment variable to avoid problems with child_process (#158)
* fix: Rename PUBLIC environment variable to avoid problems with child_process

* chore: rename

---------

Co-authored-by: 草鞋没号 <308487730@qq.com>
2023-08-02 10:54:09 +08:00
草鞋没号 c9e3c81550 docs: update 2023-08-02 09:59:37 +08:00
草鞋没号 3ac78785bf feat: logo v2 2023-05-19 10:16:44 +08:00
草鞋没号 f729d13582 chore: cleanup assets 2023-04-23 10:19:58 +08:00
草鞋没号 5efc8b08c7 feat: icon for linux 2023-04-17 12:44:01 +08:00
草鞋没号 66e4eee2c0 docs: update 2023-04-17 10:48:37 +08:00
草鞋没号 4edbadf077 chore: bump vite-plugin-electron to 0.11.1, vite-plugin-electron-renderer to 0.13.14 2023-04-17 10:48:26 +08:00
Jimmy 1b5b326aa6
fix : tsconfig include electron (#134) (#135) 2023-04-11 11:37:51 +08:00
草鞋没号 6ef956d5ef chore: bump vite-plugin-electron-renderer to 0.13.14 2023-03-31 10:03:07 +08:00
草鞋没号 b6e4df4603 feat: better LOGO animate 2023-03-30 20:02:54 +08:00
草鞋没号 dbe0730fd8 v2.2.0 2023-03-30 19:42:41 +08:00
草鞋没号 e93d649340 refactor: `vite-plugin-electron` instead `vite-electron-plugin` 2023-03-30 19:39:42 +08:00
草鞋没号 1c707b40bb chore: bump vite-plugin-electron-renderer to 0.13.13 2023-03-30 19:38:53 +08:00
草鞋没号 8fd0e00046 chore: update deps 2023-03-28 13:02:50 +08:00
草鞋没号 1edfdac585 chore: bump vite-plugin-electron-renderer to 0.13.11 2023-03-27 16:16:24 +08:00
草鞋没号 f33167d754 chore: bump vite-plugin-electron-renderer to 0.13.10 2023-03-26 22:19:55 +08:00
草鞋没号 79acebe7a4 Merge branch 'main' of github.com:caoxiemeihao/vite-react-electron into main 2023-03-26 22:02:03 +08:00
草鞋没号 8fa2c831a7 chore: bump vite-plugin-electron-renderer to 0.13.9 #132 2023-03-26 22:00:15 +08:00
Cuvii 6432b5275c
fix: typo (#131) 2023-03-25 17:31:24 +08:00
草鞋没号 6ff0dc59ed chore: bump deps 2023-03-24 12:00:43 +08:00
Jimmy 48a6b0682e
docs : add `electron-auto-update` docs (#125)
Co-authored-by: 草鞋没号 <308487730@qq.com>
2023-03-15 09:24:13 +08:00
草鞋没号 2fc312870c Squashed commit of the following:
commit 78748a44d4c75da489517fd6ce09397530b37fdb
Author: 草鞋没号 <308487730@qq.com>
Date:   Wed Mar 15 09:16:10 2023 +0800

    chore: cleanup

commit dd5ff0674d
Author: Jimmy <jimmyrss1102@gmail.com>
Date:   Tue Mar 14 21:12:33 2023 +0800

    docs : add `electron-auto-update` docs
2023-03-15 09:20:30 +08:00
草鞋没号 2f2880a9f1
feat: add electron-builder (#123)
# feat :  add electron auto update

# feat : add some components url : https://github.com/RSS1101/electron-vite-react

# * feat : Add electron auto update function

# * chore : use css module conduct style isolation

# * refactor: cleanup

# * chore : electron-auto-update refinement

# * chore: cleanup

# * chore : update electron-auto-update

# * chore: typo

# * feat: add `mac.target.dmg` for electron-updater

---------

Co-authored-by: 任帅 <1064425721@qq.com>
2023-03-12 09:35:20 +08:00
草鞋没号 29d5fa95a8 chore: bump deps 2023-02-23 10:51:40 +08:00
草鞋没号 281aad281c feat: legacy config #115 2023-02-23 09:08:45 +08:00
草鞋没号 53b1425f4e chore: cleanup 2023-02-23 09:05:33 +08:00
草鞋没号 5063fa8bd9 chore(deps): bum vite-electron-plugin to 0.8.2, add vite-plugin-electron 2023-02-23 09:05:18 +08:00
草鞋没号 891751624a Merge branch 'lifeiscontent-feat/playwright' into main 2023-02-14 19:40:13 +08:00
草鞋没号 6651c5e3de chroe: bump vite-plugin-electron-renderer to 0.12.1 2023-02-14 09:46:49 +08:00
草鞋没号 7d92423cca
Merge pull request #108 from KevinsBobo/main
fix: incorrect debounce call
2023-01-30 09:23:00 +08:00
KevinsBobo eaa77855b2 fix incorrect debounce call 2023-01-29 20:11:02 +08:00
草鞋没号 57da1121e7
Merge pull request #104 from xhayper/patch-1
feat: update package + pull changes from upstream
2023-01-20 08:08:58 +08:00
xhayper cd319c5a62
feat: update package + pull changes from upstream 2023-01-19 12:54:54 +07:00
草鞋没号 bd1fe91070 chore: cleanup 2023-01-14 08:47:31 +08:00
草鞋没号 ab634d24f9 chore: bump deps 2023-01-14 08:47:16 +08:00
草鞋没号 ac07c369e2 chore: cleanup 2023-01-14 08:46:00 +08:00
草鞋没号 e8adba821a chore: bump deps 2023-01-14 08:45:43 +08:00
草鞋没号 df9e023ba4 Merge branch 'feat/playwright' of https://github.com/lifeiscontent/electron-vite-react into lifeiscontent-feat/playwright 2023-01-03 18:28:33 +08:00
草鞋没号 bfffd06646
Merge pull request #99 from RSS1102/main
fix : alias invalid
2022-12-31 08:37:05 +08:00
Aaron Reisman 28e8d8b808
feat: add playwright and example test 2022-12-30 13:52:48 -08:00
Jimmy 70e8b39774 fix : alias invalid 2022-12-30 10:52:30 +08:00
草鞋没号 dfa51dd155
Merge pull request #97 from xhayper/patch-1
fix: icon being too small
2022-12-29 14:37:04 +08:00
xhayper 6db5de853c
fix: icon being too small 2022-12-29 11:59:30 +07:00
草鞋没号 fb5555c1f7
Merge pull request #96 from xhayper/patch-1
feat: properly update logo
2022-12-29 12:21:34 +08:00
xhayper 6bd40b2399
fix: electron file:// problem 2022-12-29 11:17:08 +07:00
xhayper 84b3617ed5
feat: properly update logo 2022-12-28 22:20:23 +07:00
草鞋没号 3a6ba28e78 feat: update logo 2022-12-28 20:26:49 +08:00
草鞋没号 98e10011db chore: bump vite-electron-plugin to 0.6.4 2022-12-28 09:14:23 +08:00
草鞋没号 9f414cef12
Merge pull request #93 from xhayper/patch-1
feat: improvement to template
2022-12-27 11:28:20 +08:00
xhayper 0b463ba8c3
feat: shamefully hoist 2022-12-27 09:26:46 +07:00
xhayper 93a4cd74f1
chore: update dependencies 2022-12-27 08:58:46 +07:00
草鞋没号 4b03aac9fa
Merge pull request #93 from xhayper/patch-1
feat: improvement to template
2022-12-27 08:30:31 +08:00
xhayper 7cbc3ded05
feat: improvement to template 2022-12-23 23:39:53 +07:00
草鞋没号 2889ab3ac8
Merge pull request #89 from cijiugechu/main
chore(deps): bump vite and corresponding react-plugin
2022-12-12 07:10:29 +08:00
阿良仔 87cccc51ab
chore(deps): bump vite and react-plugin 2022-12-11 17:43:22 +08:00
草鞋没号 3953b84329 docs: correct link 2022-12-09 09:12:30 +08:00
草鞋没号 45f9205eac chore: bump deps 2022-11-25 09:00:04 +08:00
草鞋没号 1b29cac508 chore: bump vite-electron-plugin to 0.5.2 2022-11-22 08:15:24 +08:00
草鞋没号 a9240837be chore: VITE_DEV_SERVER_URL instead `app.isPackaged` 2022-11-22 08:15:04 +08:00
草鞋没号 4a83703608 docs: update 2022-11-19 08:36:32 +08:00
草鞋没号 e6fbffc7b7 chore: bump vite-plugin-electron-renderer to 0.11.3 2022-11-19 08:36:16 +08:00
草鞋没号 07abc2078f chore: bump vite-electron-plugin to 0.5.1 2022-11-19 08:35:13 +08:00
草鞋没号 055b3eca39 Merge branch 'main' of github.com:caoxiemeihao/vite-react-electron into main 2022-11-06 18:07:40 +08:00
草鞋没号 a82f0828a8 fix: use VITE_DEV_SERVER_URL instead `app.isPackaged` 2022-11-06 18:07:09 +08:00
草鞋没号 a70714c6ae
Merge pull request #81 from jaw52/build/skip_files_when_debug
Build/skip files when debug
2022-11-05 11:49:54 +08:00
糠帅傅 31ffc67ca2
build(yarn): delect yarnrc 2022-11-05 10:29:37 +08:00
jaw52 643d0ffcb6 build(yarn):add ELECTRON_MIRROR 2022-11-04 22:07:08 +08:00
jaw52 5f8b6041ac build(vscode_debug): add skipFiles 2022-11-04 22:06:17 +08:00
草鞋没号 c711938f70 feat: Allow use `import.meta.env.VITE_SOME_KEY` in Electron-Main 2022-11-04 09:59:03 +08:00
草鞋没号 a8d24cb084 chore(deps): bump vite to 3.2.3, vite-plugin-electron-renderer to 0.10.2 2022-11-04 09:57:26 +08:00
草鞋没号 6fda9e5723 chore: bump vite-electron-plugin to 0.5.0 2022-11-01 07:50:36 +08:00
草鞋没号 71dd5078d9 fix(#78): correct image src 2022-10-30 08:38:02 +08:00
草鞋没号 3ab8a85a02 fix: incorrect problemMatcher patterns 2022-10-30 07:38:14 +08:00
草鞋没号 4e3a9e3a1b
Merge pull request #77 from jaw52/fix/open_child_window
fix(example): fix open childWindow error
2022-10-21 17:18:12 +08:00
jaw52 50b91b9b02 fix(example): fix open childWindow error 2022-10-21 16:27:23 +08:00
草鞋没号 0566305c79 feat: use Node.js in Renderer process 2022-10-19 19:11:36 +08:00
草鞋没号 e2cedd24cf fix(🐞): correct entry path #76 2022-10-19 19:10:58 +08:00
草鞋没号 d6f989c4f5 chore: bump vite-electron-plugin to 0.4.6 2022-10-13 20:37:41 +08:00
草鞋没号 9c278ffe18 chore: bump deps 2022-10-06 10:35:26 +08:00
草鞋没号 5e839b2f6d
Merge pull request #70 from electron-vite/v2.1.0
v2.1.0: use `vite-electron-plugin` instead `vite-plugin-electron`
2022-10-04 07:18:22 +08:00
草鞋没号 1754306625 v2.1.0: use `vite-electron-plugin` instead `vite-plugin-electron` 2022-10-03 10:43:13 +08:00
Paul b3e144ad04
Merge pull request #67 from ernesto-glz/fix-linux-icon
fix: Linux icon not working
2022-09-21 10:56:52 +03:00
kik0 6e35fbd27c fix: Linux icon not working 2022-09-21 03:31:42 -04:00
草鞋没号 b2a073cc8d feat: hoist `process.env` 2022-09-17 08:23:23 +08:00
草鞋没号 cac23a138c feat: `process.env.DIST`, `process.env.PUBLIC` 2022-09-13 14:41:02 +08:00
草鞋没号 68a41e3b5a update types 2022-09-13 14:40:17 +08:00
草鞋没号 10cf0405f7 chore: update include 2022-08-29 09:26:32 +08:00
草鞋没号 d9a4ad8c61 `VITE_DEV_SERVER_HOST` -> `VITE_DEV_SERVER_HOSTNAME` 2022-08-29 09:17:51 +08:00
草鞋没号 fae8222245 bump vite-plugin-electron to 0.9.2 2022-08-29 09:17:17 +08:00
草鞋没号 5fa875a495 chore: update types 2022-08-27 06:39:40 +08:00
草鞋没号 79f98c8792 chore: remove electron-env.d.ts 2022-08-27 06:39:29 +08:00
草鞋没号 ff15fa45d5 chore: update tsconfig 2022-08-25 08:27:57 +08:00
草鞋没号 9b5a3a9c61 reactor: better `debug.env` 2022-08-25 08:20:26 +08:00
草鞋没号 d5f251f5d1 chore: include electron 2022-08-25 08:17:01 +08:00
草鞋没号 bf761fc687 chore: comments 2022-08-24 20:07:08 +08:00
草鞋没号 c84a4d8194 fix(🐞): Debug 2022-08-24 19:57:19 +08:00
草鞋没号 05cdb82d15 refactor: better Debug config 🐞 2022-08-24 19:34:02 +08:00
草鞋没号 3d0948c801 bump vite-plugin-electron to 0.9.1 2022-08-24 19:32:06 +08:00
草鞋没号 3130ab2998 docs: update 2022-08-16 08:16:55 +08:00
草鞋没号 e66f6adf7e chore: update node version 2022-08-16 08:12:54 +08:00
草鞋没号 26429ae7bf
Merge pull request #59 from electron-vite/dev
bump devpendencies
2022-08-15 10:07:35 +08:00
younglei 4fd36df90b remove renderBUiltUrl 2022-08-15 10:02:50 +08:00
younglei d427a7a9aa chore:bump devpendencies 2022-08-15 10:01:17 +08:00
草鞋没号 63cef88299
Merge pull request #57 from Yusfuu/main
replace url with the VITE_DEV_SERVER_URL env key in vite
2022-08-13 07:54:16 +08:00
Youssef Hajjari 009e39319c replace url with the VITE_DEV_SERVER_URL env key in vite 2022-08-12 14:54:11 +00:00
草鞋没号 4d129d0c5c
docs: `renderer` comments 2022-08-11 09:26:08 +08:00
草鞋没号 ae877666f4
Merge pull request #55 from electron-vite/fix/220806-#52
fix(Vite@.3x): Invalid URL #52
2022-08-07 06:34:55 +08:00
草鞋没号 3c719118a7 fix(Vite@.3x): Invalid URL #52 2022-08-06 11:40:46 +08:00
草鞋没号 0584fc4f30
Update README.zh-CN.md 2022-08-03 08:19:59 +08:00
草鞋没号 44b342f481
Update README.md 2022-08-03 08:19:29 +08:00
草鞋没号 3efcb1a27d
Merge pull request #54 from electron-vite/fix/220801-debug
The task 'start .debug.script.mjs' cannot be tracked | Cannot connect to the target at localhost:9229
2022-08-01 16:53:12 +08:00
草鞋没号 b8eaa24047 fix(Debug): `Cannot connect to the target at localhost:9229` 2022-08-01 11:28:14 +08:00
草鞋没号 034f89cec1 fix(Debug): `The task 'start .debug.script.mjs' cannot be tracked` 2022-08-01 11:27:56 +08:00
草鞋没号 cfc586acbc fix: electron-vite-vue/issues/189 2022-07-31 07:44:37 +08:00
草鞋没号 c705314a96 bump vite-plugin-electron to 0.8.3 2022-07-28 15:41:10 +08:00
Paul 055994279b
chore: bump vite-plugin-electron 2022-07-25 11:54:00 +03:00
草鞋没号 4bcb4e99bb
Merge pull request #51 from electron-vite/chore/220723
Chore/220723
2022-07-23 17:20:10 +08:00
草鞋没号 a6b1fe3455 chore: update comments 2022-07-23 10:22:57 +08:00
草鞋没号 f9571ab94a refactor: better Debug logic 2022-07-23 07:31:47 +08:00
草鞋没号 58e568506a
Merge pull request #49 from electron-vite/feture/debug
Feture/debug
2022-07-22 17:41:53 +08:00
Paul 0ab99a990c chore: update & remove 2022-07-22 12:11:16 +03:00
草鞋没号 d72cbb39b5 Merge branch 'main' of github.com:caoxiemeihao/vite-react-electron into main 2022-07-22 15:28:35 +08:00
草鞋没号 fe103943f2 feat(🌱): support Debug in VSCode 2022-07-22 15:28:23 +08:00
草鞋没号 1c3614081d chore: bump vite-plugin-electron to 0.8.1 2022-07-22 15:27:51 +08:00
草鞋没号 ad1096433e chore: use reference `electron-env.d.ts` type 2022-07-22 15:26:37 +08:00
Paul d20f4c909c
docs: fix typo 2022-07-21 12:19:33 +03:00
草鞋没号 c420f35805 docs: fix display BUG 2022-07-21 09:44:40 +08:00
Paul d8387de901
docs: refactor text
Decided to give it a fresh look and made a lot of stuff more understandable and user-friendly. Added debugger to the Overview. Added emojis to the
2022-07-20 18:51:53 +03:00
草鞋没号 b0876e1b2a
Merge pull request #47 from electron-vite/chore/220720
Chore/220720
2022-07-20 19:28:10 +08:00
Paul c3060c0315
docs: add heading 2022-07-20 14:16:34 +03:00
草鞋没号 c90d0b90cd
Update README.zh-CN.md 2022-07-20 19:07:54 +08:00
草鞋没号 6fc1e5fd9b docs: update 2022-07-20 08:57:24 +08:00
草鞋没号 7ca54e148f chore(deps): bump vite-plugin-electron to 0.8.0 2022-07-20 08:56:39 +08:00
草鞋没号 ec8e390718
Merge pull request #45 from electron-vite/dev
chore: bump deps
2022-07-13 10:00:59 +08:00
younglei f25a850f81 chore: bump deps 2022-07-12 22:59:25 +08:00
草鞋没号 7380421914 docs: 🚨 Node.js ESM packages 2022-07-11 08:43:06 +08:00
草鞋没号 817498e2d9 docs: 🚨 ESM packages 2022-07-04 09:19:44 +08:00
草鞋没号 49c2bf2b25 chore(deps): bump vite-plugin-electron to 0.6.2 2022-07-04 09:14:52 +08:00
草鞋没号 cc8d92c517 add electron-env.d.ts 2022-07-02 11:10:16 +08:00
草鞋没号 f84089beec remove types.d.ts 2022-07-02 11:10:02 +08:00
草鞋没号 a1525fdc60 chroe: add electron into include 2022-07-02 11:09:35 +08:00
草鞋没号 0f747c67c6 chore: remove types.d.ts in `include` 2022-07-02 11:09:17 +08:00
草鞋没号 69397edfc0 Merge branch 'main' of github.com:caoxiemeihao/vite-react-electron into main 2022-06-29 16:08:13 +08:00
草鞋没号 55b4aa4dd6 docs: update 2022-06-29 16:08:04 +08:00
草鞋没号 56ab746c6a
Merge pull request #43 from xlboy/main
chore(tsconfig-node): allow import `package.json`
2022-06-29 13:26:57 +08:00
xlboy b7d71e960e chore(tsconfig-node): allow import `package.json` 2022-06-29 13:12:34 +08:00
草鞋没号 7374a44e96 docs: update 2022-06-29 07:40:54 +08:00
草鞋没号 60f28a2a9e chore: update 2022-06-29 07:40:47 +08:00
草鞋没号 c4304b61e6 add `samples/node-api.ts` 2022-06-29 07:40:35 +08:00
草鞋没号 aa89677048 remove `global.d.ts` 2022-06-29 07:40:12 +08:00
草鞋没号 6dcb6643b1 chore: optimize code 2022-06-29 07:39:53 +08:00
草鞋没号 0ab15c65f1 `preload/splash.ts` -> `preload/index.ts` 2022-06-29 07:39:16 +08:00
草鞋没号 bb1505d2c8 docs: update 2022-06-28 10:45:11 +08:00
草鞋没号 e2f2a0afbc docs: update 2022-06-28 10:43:17 +08:00
草鞋没号 8e5e2da2f1 bump vite-plugin-electron to 0.6.1 2022-06-28 10:41:50 +08:00
草鞋没号 a25e73558c docs: `dependencies` vs `devDependencies` 2022-06-28 10:41:23 +08:00
草鞋没号 5a9d817643 docs: updatae 2022-06-27 10:17:20 +08:00
草鞋没号 ff5371477b docs: update 2022-06-27 10:15:29 +08:00
草鞋没号 2dcd3b6a88 chore: update config of vite-plugin-electron 2022-06-27 10:05:40 +08:00
草鞋没号 29e0782ccb chore: bump vite-plugin-electron to 0.6.0 2022-06-27 10:04:34 +08:00
草鞋没号 5107781fd1 bump vite-plugin-electron to 0.4.9 2022-06-14 08:21:13 +08:00
草鞋没号 4d9836d165 docs: update 2022-06-13 09:54:41 +08:00
草鞋没号 458694315d docs: v2.0.0 2022-06-10 09:16:43 +08:00
草鞋没号 dcaca724a1
Merge pull request #36 from kasbah/patch-1
Improve artifact names in electron-builder.json5
2022-06-08 20:50:07 +08:00
Kaspar Emanuel 9770dd133a
Improve artifact names in electron-builder.json5
- Add platform name 
- Remove "Installer" from the AppImage (AppImages are executables)
2022-06-08 13:26:25 +01:00
草鞋没号 99d473948b
Merge pull request #34 from electron-vite/v2.0.0
V2.0.0
2022-06-07 19:08:56 +08:00
Paul 31669f5d2b chore: bump vite to 2.9.10 2022-06-07 12:46:08 +03:00
草鞋没号 1183e49fd2 fix(🐞): set `build.outDir` explicitly 2022-06-07 11:01:32 +08:00
草鞋没号 43bea9fb0b feat: config server option by package.json 2022-06-07 09:51:11 +08:00
草鞋没号 4d636614ce fix: debug bootstrap logic 2022-06-07 09:49:42 +08:00
草鞋没号 d949120836
Merge pull request #35 from PAXANDDOS/fix/v2.0.0
v2.0.0 improved
2022-06-07 07:24:19 +08:00
草鞋没号 f8677670ef
fix: `index.cjs` -> `index.js` 2022-06-07 07:23:08 +08:00
草鞋没号 9359140dbe
Update README.md 2022-06-07 07:22:07 +08:00
Paul ddf949f98b doc: (CHANGES NEEDED) update readme 2022-06-06 21:24:14 +03:00
Paul eb8b69966d refactor: minor changes 2022-06-06 21:23:25 +03:00
Paul 0edc38fc9d feat: use path aliases, improve TS 2022-06-06 21:23:07 +03:00
Paul aff8ccb7c9 refactor: move styles to assets 2022-06-06 21:22:29 +03:00
Paul bcb61bcebb feat: improve json5 2022-06-06 21:21:10 +03:00
Paul b0320cab5d feat: vscode recommended extensions 2022-06-06 21:19:47 +03:00
草鞋没号 3e6abba80e chore: update `buildResources` option 2022-06-06 20:31:09 +08:00
草鞋没号 396afdb6c9 move `resources/` to `electron/resources/` 2022-06-06 20:30:01 +08:00
草鞋没号 9150036761 fix: `win.loadFile()` path 2022-06-06 20:27:23 +08:00
草鞋没号 23a98a26b4 chore: update `electron/*` entry 2022-06-06 20:22:38 +08:00
草鞋没号 ab9e5bf3c2 refactor: move `electron-*` to `electron/*` 2022-06-06 20:22:13 +08:00
草鞋没号 9bab724711 bump vite-plugin-electron from 0.4.6 to 0.4.7 2022-06-06 20:21:21 +08:00
草鞋没号 a04955f468 rename 2022-06-06 19:14:45 +08:00
Paul 3664cd2a9b 📦 refactor: package, static, editorconfig 2022-06-06 12:42:38 +03:00
草鞋没号 fca655ecc3 fix: correct public path 2022-06-06 09:58:56 +08:00
草鞋没号 0011c249f0 feat: integrate vite-plugin-electron 2022-06-05 08:33:10 +08:00
草鞋没号 ec17b09cb5 template-react-ts/src/ 2022-06-05 08:32:53 +08:00
草鞋没号 95d901d11f add public/ 2022-06-05 08:32:32 +08:00
草鞋没号 8a8dd62b96 add electron-preload 2022-06-05 08:32:15 +08:00
草鞋没号 d479a00b9a add electron-main 2022-06-05 08:32:09 +08:00
草鞋没号 05d4a2a35f remove paths.json 2022-06-05 08:31:47 +08:00
草鞋没号 909af6e451 add types.d.ts 2022-06-05 08:31:37 +08:00
草鞋没号 d2c9340b05 template-react-ts/index.html 2022-06-05 08:30:46 +08:00
草鞋没号 9fa015fb08 v2.0.0 2022-06-05 08:14:55 +08:00
草鞋没号 85a7919787 vite.config.ts 2022-06-05 08:14:45 +08:00
草鞋没号 ad2bbaca24 template-react-ts/tsconfig.json 2022-06-05 08:08:12 +08:00
草鞋没号 a1bfdfba8d remove(v1.0.0) scripts 2022-06-05 08:06:30 +08:00
草鞋没号 31f487d860 remove(v1.0.0) packages 2022-06-05 08:05:54 +08:00
草鞋没号 c75e1c150e git rm package-lock.json 2022-06-05 08:02:54 +08:00
草鞋没号 c2dcf94775 update 2022-06-05 08:02:20 +08:00
81 changed files with 1427 additions and 12002 deletions

102
.gitignore vendored
View File

@ -4,86 +4,30 @@ logs
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Runtime data node_modules
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.debug.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# ----
dist dist
**/.tmp
release
.DS_Store
dist-ssr dist-ssr
dist-electron
release
*.local *.local
# Editor directories and files
.vscode/.debug.env
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
#lockfile
package-lock.json
pnpm-lock.yaml
yarn.lock
/test-results/
/playwright-report/
/playwright/.cache/

1
.npmrc Normal file
View File

@ -0,0 +1 @@
shamefully-hoist=true

View File

@ -1,14 +1,23 @@
import fs from 'fs' import fs from 'node:fs'
import path from 'path' import path from 'node:path'
import { fileURLToPath } from 'url' import { fileURLToPath } from 'node:url'
import { createRequire } from 'module' import { createRequire } from 'node:module'
import { spawn } from 'node:child_process'
const pkg = createRequire(import.meta.url)('../package.json') const pkg = createRequire(import.meta.url)('../package.json')
const __dirname = path.dirname(fileURLToPath(import.meta.url)) const __dirname = path.dirname(fileURLToPath(import.meta.url))
// write .debug.env // write .debug.env
const envContent = Object.entries(pkg.env).map(([key, val]) => `${key}=${val}`) const envContent = Object.entries(pkg.debug.env).map(([key, val]) => `${key}=${val}`)
fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n')) fs.writeFileSync(path.join(__dirname, '.debug.env'), envContent.join('\n'))
// bootstrap // bootstrap
import('../scripts/watch.mjs?debug=vscode') spawn(
// TODO: terminate `npm run dev` when Debug exits.
process.platform === 'win32' ? 'npm.cmd' : 'npm',
['run', 'dev'],
{
stdio: 'inherit',
env: Object.assign(process.env, { VSCODE_DEBUG: 'true' }),
},
)

7
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"mrmlnc.vscode-json5"
]
}

20
.vscode/launch.json vendored
View File

@ -6,7 +6,7 @@
"compounds": [ "compounds": [
{ {
"name": "Debug App", "name": "Debug App",
"preLaunchTask": "start .debug.script.mjs", "preLaunchTask": "Before Debug",
"configurations": [ "configurations": [
"Debug Main Process", "Debug Main Process",
"Debug Renderer Process" "Debug Renderer Process"
@ -22,23 +22,33 @@
"configurations": [ "configurations": [
{ {
"name": "Debug Main Process", "name": "Debug Main Process",
"type": "pwa-node", "type": "node",
"request": "launch", "request": "launch",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron", "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"windows": { "windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd" "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
}, },
"runtimeArgs": [ "runtimeArgs": [
"--no-sandbox",
"--remote-debugging-port=9229", "--remote-debugging-port=9229",
"${workspaceRoot}/dist/main/index.cjs" "."
], ],
"envFile": "${workspaceFolder}/.vscode/.debug.env" "envFile": "${workspaceFolder}/.vscode/.debug.env",
"console": "integratedTerminal"
}, },
{ {
"name": "Debug Renderer Process", "name": "Debug Renderer Process",
"port": 9229, "port": 9229,
"request": "attach", "request": "attach",
"type": "pwa-chrome" "type": "chrome",
"timeout": 60000,
"skipFiles": [
"<node_internals>/**",
"${workspaceRoot}/node_modules/**",
"${workspaceRoot}/dist-electron/**",
// Skip files in host(VITE_DEV_SERVER_URL)
"http://127.0.0.1:7777/**"
]
}, },
] ]
} }

13
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,13 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.tsc.autoDetect": "off",
"json.schemas": [
{
"fileMatch": [
"/*electron-builder.json5",
"/*electron-builder.json"
],
"url": "https://json.schemastore.org/electron-builder"
}
]
}

25
.vscode/tasks.json vendored
View File

@ -4,15 +4,28 @@
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "start .debug.script.mjs", "label": "Before Debug",
"type": "shell", "type": "shell",
"command": "node .vscode/.debug.script.mjs", "command": "node .vscode/.debug.script.mjs",
"isBackground": true, "isBackground": true,
"problemMatcher": [] "problemMatcher": {
"owner": "typescript",
"fileLocation": "relative",
"pattern": {
// TODO: correct "regexp"
"regexp": "^([a-zA-Z]\\:\/?([\\w\\-]\/?)+\\.\\w+):(\\d+):(\\d+): (ERROR|WARNING)\\: (.*)$",
"file": 1,
"line": 3,
"column": 4,
"code": 5,
"message": 6
},
"background": {
"activeOnStart": true,
"beginsPattern": "^.*VITE v.* ready in \\d* ms.*$",
"endsPattern": "^.*\\[startup\\] Electron App.*$"
}
}
} }
] ]
} }
// https://code.visualstudio.com/docs/editor/tasks#_operating-system-specific-properties
// https://code.visualstudio.com/docs/editor/tasks#_background-watching-tasks
// https://code.visualstudio.com/docs/editor/tasks#_can-a-background-task-be-used-as-a-prelaunchtask-in-launchjson

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2021 草鞋没号 Copyright (c) 2023 草鞋没号
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

201
README.md
View File

@ -1,156 +1,91 @@
# vite-react-electron # electron-vite-react
![GitHub stars](https://img.shields.io/github/stars/caoxiemeihao/vite-react-electron?color=fa6470&style=flat) [![awesome-vite](https://awesome.re/mentioned-badge.svg)](https://github.com/vitejs/awesome-vite)
![GitHub issues](https://img.shields.io/github/issues/caoxiemeihao/vite-react-electron?color=d8b22d&style=flat) ![GitHub stars](https://img.shields.io/github/stars/caoxiemeihao/vite-react-electron?color=fa6470)
![GitHub license](https://img.shields.io/github/license/caoxiemeihao/vite-react-electron?style=flat) ![GitHub issues](https://img.shields.io/github/issues/caoxiemeihao/vite-react-electron?color=d8b22d)
[![Required Node.JS >= v14.17.0](https://img.shields.io/static/v1?label=node&message=%3E=14.17.0&logo=node.js&color=3f893e&style=flat)](https://nodejs.org/about/releases) ![GitHub license](https://img.shields.io/github/license/caoxiemeihao/vite-react-electron)
[![Required Node.JS >= 14.18.0 || >=16.0.0](https://img.shields.io/static/v1?label=node&message=14.18.0%20||%20%3E=16.0.0&logo=node.js&color=3f893e)](https://nodejs.org/about/releases)
**English | [简体中文](README.zh-CN.md)** English | [简体中文](README.zh-CN.md)
## Overview ## 👀 Overview
This is a `Vite`-integrated `Electron` template built with simplification in mind. 📦 Ready out of the box
🎯 Based on the official [template-react-ts](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts), project structure will be familiar to you
🌱 Easily extendable and customizable
💪 Supports Node.js API in the renderer process
🔩 Supports C/C++ native addons
🐞 Debugger configuration included
🖥 Easy to implement multiple windows
The repo contains only the most basic files, dependencies and functionalities to ensure flexibility for various scenarios. ## 🛫 Quick Setup
You need a basic understanding of `Electron` and `Vite` to get started. But that's not mandatory - you can learn almost all the details by reading through the source code. Trust me, this repo is not that complex. 😋
## Quick start
```sh
npm create electron-vite
```
![electron-vite-react.gif](https://github.com/electron-vite/electron-vite-react/blob/main/packages/renderer/public/electron-vite-react.gif?raw=true)
## Debug
![electron-vite-react-debug.gif](https://github.com/electron-vite/electron-vite-react/blob/main/packages/renderer/public/electron-vite-react-debug.gif?raw=true)
<!--
```sh ```sh
# clone the project # clone the project
git clone https://github.com/caoxiemeihao/vite-react-electron.git git clone https://github.com/electron-vite/electron-vite-react.git
# open the project directory # enter the project directory
cd vite-react-electron cd electron-vite-react
# install dependencies # install dependency
npm install npm install
# start the application # develop
npm run dev npm run dev
# make a production build
npm run build
``` ```
-->
## Directory structure ## 🐞 Debug
Once `dev` or `build` npm-script is executed, the `dist` folder will be generated. It has the same structure as the `packages` folder, the purpose of this design is to ensure the correct path calculation. ![electron-vite-react-debug.gif](/electron-vite-react-debug.gif)
## 📂 Directory structure
Familiar React application structure, just with `electron` folder on the top :wink:
*Files in this folder will be separated from your React application and built into `dist-electron`*
```tree ```tree
├── build Resources for the production build ├── electron Electron-related code
| ├── icon.icns Icon for the application on macOS │ ├── main Main-process source code
| ├── icon.ico Icon for the application │ └── preload Preload-scripts source code
| ├── installerIcon.ico Icon for the application installer
| └── uninstallerIcon.ico Icon for the application uninstaller ├── release Generated after production build, contains executables
| │ └── {version}
├── dist Generated after build according to the "packages" directory │ ├── {os}-{os_arch} Contains unpacked application executable
| ├── main │ └── {app_name}_{version}.{ext} Installer for the application
| ├── preload
| └── renderer ├── public Static assets
| └── src Renderer source code, your React application
├── release Generated after production build, contains executables
| └──{version}
| ├── win-unpacked Contains unpacked application executable
| └── Setup.exe Installer for the application
|
├── scripts
| ├── build.mjs Develop script -> npm run build
| └── watch.mjs Develop script -> npm run dev
|
├── packages
| ├── main Main-process source code
| | └── vite.config.ts
| ├── preload Preload-script source code
| | └── vite.config.ts
| └── renderer Renderer-process source code
| └── vite.config.ts
``` ```
## Use Electron and NodeJS API
> 🚧 By default, Electron doesn't support the use of API related to Electron and NodeJS in the Renderer process, but someone might need to use it. If so, you can see the template 👉 **[electron-vite-boilerplate](https://github.com/caoxiemeihao/electron-vite-boilerplate)**
#### Invoke Electron and NodeJS API in `Preload-script`
- **packages/preload/index.ts**
```typescript
import fs from "fs"
import { contextBridge, ipcRenderer } from "electron"
// --------- Expose some API to Renderer-process. ---------
contextBridge.exposeInMainWorld("fs", fs)
contextBridge.exposeInMainWorld("ipcRenderer", ipcRenderer)
```
- **packages/renderer/src/global.d.ts**
```typescript
// Defined in the window
interface Window {
fs: typeof import("fs")
ipcRenderer: import("electron").IpcRenderer
}
```
- **packages/renderer/src/main.ts**
```typescript
// Use Electron and NodeJS API in the Renderer-process
console.log("fs", window.fs)
console.log("ipcRenderer", window.ipcRenderer)
```
## Use SerialPort, SQLite3, or other node-native addons in the Main-process
- First, you need to make sure that the dependencies in the `package.json` are NOT in the "devDependencies". Because the project will need them after packaged.
- Main-process, Preload-script are also built with Vite, and they're built as [build.lib](https://vitejs.dev/config/#build-lib).
So they just need to configure Rollup.
**Click to see more** 👉 [packages/main/vite.config.ts](https://github.com/caoxiemeihao/vite-react-electron/blob/main/packages/main/vite.config.ts)
```js
export default {
build: {
// built lib for Main-process, Preload-script
lib: {
entry: "index.ts",
formats: ["cjs"],
fileName: () => "[name].js",
},
rollupOptions: {
// configuration here
external: ["serialport", "sqlite3"],
},
},
}
```
## `dependencies` vs `devDependencies`
- First, you need to know if your dependencies are needed after the application is packaged.
- Like [serialport](https://www.npmjs.com/package/serialport), [sqlite3](https://www.npmjs.com/package/sqlite3) they are node-native modules and should be placed in `dependencies`. In addition, Vite will not build them, but treat them as external modules.
- Dependencies like [Vue](https://www.npmjs.com/package/vue) and [React](https://www.npmjs.com/package/react), which are pure javascript modules that can be built with Vite, can be placed in `devDependencies`. This reduces the size of the application.
<!-- <!--
## Result ## 🚨 Be aware
<img width="400px" src="https://raw.githubusercontent.com/caoxiemeihao/blog/main/vite-react-electron/react-win.png" /> This template integrates Node.js API to the renderer process by default. If you want to follow **Electron Security Concerns** you might want to disable this feature. You will have to expose needed API by yourself.
To get started, remove the option as shown below. This will [modify the Vite configuration and disable this feature](https://github.com/electron-vite/vite-plugin-electron-renderer#config-presets-opinionated).
```diff
# vite.config.ts
export default {
plugins: [
...
- // Use Node.js API in the Renderer-process
- renderer({
- nodeIntegration: true,
- }),
...
],
}
```
--> -->
## 🔧 Additional features
1. electron-updater 👉 [see docs](src/components/update/README.md)
1. playwright
## ❔ FAQ
- [C/C++ addons, Node.js modules - Pre-Bundling](https://github.com/electron-vite/vite-plugin-electron-renderer#dependency-pre-bundling)
- [dependencies vs devDependencies](https://github.com/electron-vite/vite-plugin-electron-renderer#dependencies-vs-devdependencies)

View File

@ -1,43 +1,30 @@
# vite-react-electron # vite-react-electron
![GitHub stars](https://img.shields.io/github/stars/caoxiemeihao/vite-react-electron?color=fa6470&style=flat) [![awesome-vite](https://awesome.re/mentioned-badge.svg)](https://github.com/vitejs/awesome-vite)
![GitHub issues](https://img.shields.io/github/issues/caoxiemeihao/vite-react-electron?color=d8b22d&style=flat) ![GitHub stars](https://img.shields.io/github/stars/caoxiemeihao/vite-react-electron?color=fa6470)
![GitHub license](https://img.shields.io/github/license/caoxiemeihao/vite-react-electron?style=flat) ![GitHub issues](https://img.shields.io/github/issues/caoxiemeihao/vite-react-electron?color=d8b22d)
[![Required Node.JS >= v14.17.0](https://img.shields.io/static/v1?label=node&message=%3E=14.17.0&logo=node.js&color=3f893e&style=flat)](https://nodejs.org/about/releases) ![GitHub license](https://img.shields.io/github/license/caoxiemeihao/vite-react-electron)
[![Required Node.JS >= 14.18.0 || >=16.0.0](https://img.shields.io/static/v1?label=node&message=14.18.0%20||%20%3E=16.0.0&logo=node.js&color=3f893e)](https://nodejs.org/about/releases)
**[English](README.md) | 简体中文** [English](README.md) | 简体中文
## 概述 ## 概述
&emsp;&emsp;这是一个追求精简的`Electron`类整合模板,只保持最基本的文件、最基本的依赖、最基本的功能;而不是大而全的、臃肿的设计。这样做的目的是能确保模板足够灵活。 📦 开箱即用
🎯 基于官方的 [template-react-ts](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts), 低侵入性
所以说如果你是对 -- 工程模板追求精简的 Coder或者刚入世的小白想弄明白`Electron`整合类模板最基础的工作原理,亦或者你是大神只是想偷懒少干点活;那么这个模板最合适你不过了。 🌱 结构清晰,可塑性强
💪 支持在渲染进程中使用 Electron、Node.js API
尽管如此,我还是希望你对`Electron` `Vite`有一定的基础;因为除了项目结构简单外,这份`README`也显得 “精简” 。 🔩 支持 C/C++ 模块
🖥 很容易实现多窗口
模板的具体实现细节我相信你看两遍源码就能把它吃透了 😋
## 快速开始 ## 快速开始
```sh
npm create electron-vite
```
![electron-vite-react.gif](https://github.com/electron-vite/electron-vite-react/blob/main/packages/renderer/public/electron-vite-react.gif?raw=true)
## 调试
![electron-vite-react-debug.gif](https://github.com/electron-vite/electron-vite-react/blob/main/packages/renderer/public/electron-vite-react-debug.gif?raw=true)
<!--
clone 该仓库
```sh ```sh
# clone the project # clone the project
git clone https://github.com/caoxiemeihao/vite-react-electron.git git clone https://github.com/electron-vite/electron-vite-react.git
# enter the project directory # enter the project directory
cd vite-react-electron cd electron-vite-react
# install dependency # install dependency
npm install npm install
@ -45,104 +32,60 @@ npm install
# develop # develop
npm run dev npm run dev
``` ```
-->
## 调试
![electron-vite-react-debug.gif](/electron-vite-react-debug.gif)
## 目录 ## 目录
一旦启动或打包脚本执行过,会在根目录产生 **`dist` 文件夹,里面的文件夹同 `packages` 一模一样**;在使用一些路径计算时,尤其是相对路径计算;`dist` 与 `packages` 里面保持相同的目录结构能避开好多问题 *🚨 默认情况下, `electron` 文件夹下的文件将会被构建到 `dist-electron`*
```tree ```tree
├── build 用于生产构建的资源 ├── electron Electron 源码文件夹
| ├── icon.icns 应用图标(macOS) │ ├── main Main-process 源码
| ├── icon.ico 应用图标 │ └── preload Preload-scripts 源码
| ├── installerIcon.ico 安装图标
| └── uninstallerIcon.ico 卸载图标 ├── release 构建后生成程序目录
| │ └── {version}
├── dist 构建后,根据 packages 目录生成 │ ├── {os}-{os_arch} 未打包的程序(绿色运行版)
| ├── main │ └── {app_name}_{version}.{ext} 应用安装文件
| ├── preload
| └── renderer ├── public 同 Vite 模板的 public
| └── src 渲染进程源码、React代码
├── release 在生产构建后生成,包含可执行文件
| └── {version}
| ├── win-unpacked 包含未打包的应用程序可执行文件
| └── Setup.exe 应用程序的安装程序
|
├── scripts
| ├── build.mjs 项目开发脚本 npm run build
| └── watch.mjs 项目开发脚本 npm run dev
|
├── packages
| ├── main 主进程源码
| | └── vite.config.ts
| ├── preload 预加载脚本源码
| | └── vite.config.ts
| └── renderer 渲染进程源码
| └── vite.config.ts
``` ```
## 依赖放到 dependencies 还是 devDependencies
&emsp;&emsp;对待 **Electron-Main、Preload-Script** 时 vite 会以 lib 形式打包 commonjs 格式代码;
如果碰 node 环境的包可以直接放到 dependencies 中vite 会解析为 require('xxxx')
electron-builder 打包时候会将 dependencies 中的包打包到 app.asar 里面
&emsp;&emsp;对待 **Electron-Renderer** 时 vite 会以 ESM 格式解析代码;
像 vue、react 这种前端用的包可以直接被 vite 构建,所以不需要 vue、react 源码;
现实情况 vue、react 放到 dependencies 或 devDependencies 中都可以被正确构建;
但是放到 dependencies 会被 electron-builder 打包到 app.asar 里面导致包体变大;
所以放到 devDependencies 既能被正确构建还可以减小 app.asar 体积,一举两得
## 渲染进程使用 NodeJs API
> 🚧 因为安全的原因 Electron 默认不支持在 渲染进程 中使用 NodeJs API但是有些小沙雕就是想这么干拦都拦不住实在想那么干的话用另一个模板更方便 👉 **[electron-vite-boilerplate](https://github.com/caoxiemeihao/electron-vite-boilerplate)**
**推荐所有的 NodeJs、Electron API 通过 `Preload-script` 注入到 渲染进程中,例如:**
* **packages/preload/index.ts**
```typescript
import fs from 'fs'
import { contextBridge, ipcRenderer } from 'electron'
// --------- Expose some API to Renderer-process. ---------
contextBridge.exposeInMainWorld('fs', fs)
contextBridge.exposeInMainWorld('ipcRenderer', ipcRenderer)
```
* **packages/renderer/src/global.d.ts**
```typescript
// Defined on the window
interface Window {
fs: typeof import('fs')
ipcRenderer: import('electron').IpcRenderer
}
```
* **packages/renderer/main.ts**
```typescript
// Use Electron, NodeJs API in Renderer-process
console.log('fs', window.fs)
console.log('ipcRenderer', window.ipcRenderer)
```
**如果你真的在这个模板中开启了 `nodeIntegration: true` `contextIsolation: false` 我不拦着
🚧 但是要提醒你做两件事儿**
1. `preload/index.ts` 中的 `exposeInMainWorld` 删掉,已经没有用了
```diff
- contextBridge.exposeInMainWorld('fs', fs)
- contextBridge.exposeInMainWorld('ipcRenderer', ipcRenderer)
```
2. `configs/vite-renderer.config` 中有个 `resolveElectron` **最好了解下**
👉 这里有个 `issues` [请教一下vite-renderer.config中的resolveElectron函数](https://github.com/caoxiemeihao/electron-vue-vite/issues/52)
<!-- <!--
## 效果 ## 🚨 这需要留神
<img width="400px" src="https://raw.githubusercontent.com/caoxiemeihao/blog/main/vite-react-electron/react-win.png" /> 默认情况下,该模板在渲染进程中集成了 Node.js如果你不需要它你只需要删除下面的选项. [因为它会修改 Vite 默认的配置](https://github.com/electron-vite/vite-plugin-electron-renderer#config-presets-opinionated).
```diff
# vite.config.ts
export default {
plugins: [
...
- // Use Node.js API in the Renderer-process
- renderer({
- nodeIntegration: true,
- }),
...
],
}
```
--> -->
## 🔧 额外的功能
1. Electron 自动更新 👉 [阅读文档](src/components/update/README.zh-CN.md)
2. Playwright 测试
## ❔ FAQ
- [C/C++ addons, Node.js modules - Pre-Bundling](https://github.com/electron-vite/vite-plugin-electron-renderer#dependency-pre-bundling)
- [dependencies vs devDependencies](https://github.com/electron-vite/vite-plugin-electron-renderer#dependencies-vs-devdependencies)
## 🍵 🍰 🍣 🍟
<img width="270" src="https://github.com/caoxiemeihao/blog/blob/main/assets/$qrcode/$.png?raw=true">

BIN
build/icon.icns Normal file

Binary file not shown.

BIN
build/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
build/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

8
e2e/example.spec.ts Normal file
View File

@ -0,0 +1,8 @@
import { test, expect, _electron as electron } from "@playwright/test";
test("homepage has title and links to intro page", async () => {
const app = await electron.launch({ args: [".", "--no-sandbox"] });
const page = await app.firstWindow();
expect(await page.title()).toBe("Electron + Vite + React");
await page.screenshot({ path: "e2e/screenshots/example.png" });
});

BIN
e2e/screenshots/example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View File

@ -3,22 +3,31 @@
*/ */
{ {
"appId": "YourAppID", "appId": "YourAppID",
"productName": "YourAppName",
"copyright": "Copyright © 2022 ${author}",
"asar": true, "asar": true,
"directories": { "directories": {
"output": "release/${version}", "output": "release/${version}"
"buildResources": "resources" },
"files": [
"dist-electron",
"dist"
],
"mac": {
"artifactName": "${productName}_${version}.${ext}",
"target": [
"dmg",
"zip"
]
}, },
"files": ["dist"],
"win": { "win": {
"target": [ "target": [
{ {
"target": "nsis", "target": "nsis",
"arch": ["x64"] "arch": [
"x64"
]
} }
], ],
"artifactName": "${productName}-${version}-Setup.${ext}" "artifactName": "${productName}_${version}.${ext}"
}, },
"nsis": { "nsis": {
"oneClick": false, "oneClick": false,
@ -26,12 +35,9 @@
"allowToChangeInstallationDirectory": true, "allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": false "deleteAppDataOnUninstall": false
}, },
"mac": { "publish": {
"target": ["dmg"], "provider": "generic",
"artifactName": "${productName}-${version}-Installer.${ext}" "channel": "latest",
}, "url": "https://github.com/electron-vite/electron-vite-react/releases/download/v0.9.9/"
"linux": {
"target": ["AppImage"],
"artifactName": "${productName}-${version}-Installer.${ext}"
} }
} }

View File

Before

Width:  |  Height:  |  Size: 9.6 MiB

After

Width:  |  Height:  |  Size: 9.6 MiB

View File

Before

Width:  |  Height:  |  Size: 3.4 MiB

After

Width:  |  Height:  |  Size: 3.4 MiB

11
electron/electron-env.d.ts vendored Normal file
View File

@ -0,0 +1,11 @@
/// <reference types="vite-electron-plugin/electron-env" />
declare namespace NodeJS {
interface ProcessEnv {
VSCODE_DEBUG?: 'true'
DIST_ELECTRON: string
DIST: string
/** /dist/ or /public/ */
VITE_PUBLIC: string
}
}

121
electron/main/index.ts Normal file
View File

@ -0,0 +1,121 @@
import { app, BrowserWindow, shell, ipcMain } from 'electron'
import { release } from 'node:os'
import { join } from 'node:path'
import { update } from './update'
// The built directory structure
//
// ├─┬ dist-electron
// │ ├─┬ main
// │ │ └── index.js > Electron-Main
// │ └─┬ preload
// │ └── index.js > Preload-Scripts
// ├─┬ dist
// │ └── index.html > Electron-Renderer
//
process.env.DIST_ELECTRON = join(__dirname, '../')
process.env.DIST = join(process.env.DIST_ELECTRON, '../dist')
process.env.VITE_PUBLIC = process.env.VITE_DEV_SERVER_URL
? join(process.env.DIST_ELECTRON, '../public')
: process.env.DIST
// Disable GPU Acceleration for Windows 7
if (release().startsWith('6.1')) app.disableHardwareAcceleration()
// Set application name for Windows 10+ notifications
if (process.platform === 'win32') app.setAppUserModelId(app.getName())
if (!app.requestSingleInstanceLock()) {
app.quit()
process.exit(0)
}
// Remove electron security warnings
// This warning only shows in development mode
// Read more on https://www.electronjs.org/docs/latest/tutorial/security
// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
let win: BrowserWindow | null = null
// Here, you can also use other preload
const preload = join(__dirname, '../preload/index.js')
const url = process.env.VITE_DEV_SERVER_URL
const indexHtml = join(process.env.DIST, 'index.html')
async function createWindow() {
win = new BrowserWindow({
title: 'Main window',
icon: join(process.env.VITE_PUBLIC, 'favicon.ico'),
webPreferences: {
preload,
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
// Consider using contextBridge.exposeInMainWorld
// Read more on https://www.electronjs.org/docs/latest/tutorial/context-isolation
nodeIntegration: true,
contextIsolation: false,
},
})
if (url) { // electron-vite-vue#298
win.loadURL(url)
// Open devTool if the app is not packaged
win.webContents.openDevTools()
} else {
win.loadFile(indexHtml)
}
// Test actively push message to the Electron-Renderer
win.webContents.on('did-finish-load', () => {
win?.webContents.send('main-process-message', new Date().toLocaleString())
})
// Make all links open with the browser, not with the application
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https:')) shell.openExternal(url)
return { action: 'deny' }
})
// Apply electron-updater
update(win)
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
win = null
if (process.platform !== 'darwin') app.quit()
})
app.on('second-instance', () => {
if (win) {
// Focus on the main window if the user tried to open another
if (win.isMinimized()) win.restore()
win.focus()
}
})
app.on('activate', () => {
const allWindows = BrowserWindow.getAllWindows()
if (allWindows.length) {
allWindows[0].focus()
} else {
createWindow()
}
})
// New window example arg: new windows url
ipcMain.handle('open-win', (_, arg) => {
const childWindow = new BrowserWindow({
webPreferences: {
preload,
nodeIntegration: true,
contextIsolation: false,
},
})
if (process.env.VITE_DEV_SERVER_URL) {
childWindow.loadURL(`${url}#${arg}`)
} else {
childWindow.loadFile(indexHtml, { hash: arg })
}
})

73
electron/main/update.ts Normal file
View File

@ -0,0 +1,73 @@
import { app, ipcMain } from 'electron'
import {
type ProgressInfo,
type UpdateDownloadedEvent,
autoUpdater
} from 'electron-updater'
export function update(win: Electron.BrowserWindow) {
// When set to false, the update download will be triggered through the API
autoUpdater.autoDownload = false
autoUpdater.disableWebInstaller = false
autoUpdater.allowDowngrade = false
// start check
autoUpdater.on('checking-for-update', function () { })
// update available
autoUpdater.on('update-available', (arg) => {
win.webContents.send('update-can-available', { update: true, version: app.getVersion(), newVersion: arg?.version })
})
// update not available
autoUpdater.on('update-not-available', (arg) => {
win.webContents.send('update-can-available', { update: false, version: app.getVersion(), newVersion: arg?.version })
})
// Checking for updates
ipcMain.handle('check-update', async () => {
if (!app.isPackaged) {
const error = new Error('The update feature is only available after the package.')
return { message: error.message, error }
}
try {
return await autoUpdater.checkForUpdatesAndNotify()
} catch (error) {
return { message: 'Network error', error }
}
})
// Start downloading and feedback on progress
ipcMain.handle('start-download', (event) => {
startDownload(
(error, progressInfo) => {
if (error) {
// feedback download error message
event.sender.send('update-error', { message: error.message, error })
} else {
// feedback update progress message
event.sender.send('download-progress', progressInfo)
}
},
() => {
// feedback update downloaded message
event.sender.send('update-downloaded')
}
)
})
// Install now
ipcMain.handle('quit-and-install', () => {
autoUpdater.quitAndInstall(false, true)
})
}
function startDownload(
callback: (error: Error | null, info: ProgressInfo | null) => void,
complete: (event: UpdateDownloadedEvent) => void,
) {
autoUpdater.on('download-progress', info => callback(null, info))
autoUpdater.on('error', error => callback(error, null))
autoUpdater.on('update-downloaded', complete)
autoUpdater.downloadUpdate()
}

View File

@ -1,10 +1,37 @@
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://tobiasahlin.com/spinkit
* https://connoratherton.com/loaders * https://connoratherton.com/loaders
* https://projects.lukehaas.me/css-loaders * https://projects.lukehaas.me/css-loaders
* https://matejkustec.github.io/SpinThatShit * https://matejkustec.github.io/SpinThatShit
*/ */
export function useLoading() { function useLoading() {
const className = `loaders-css__square-spin` const className = `loaders-css__square-spin`
const styleContent = ` const styleContent = `
@keyframes square-spin { @keyframes square-spin {
@ -43,25 +70,23 @@ export function useLoading() {
return { return {
appendLoading() { appendLoading() {
safe.append(document.head, oStyle) safeDOM.append(document.head, oStyle)
safe.append(document.body, oDiv) safeDOM.append(document.body, oDiv)
}, },
removeLoading() { removeLoading() {
safe.remove(document.head, oStyle) safeDOM.remove(document.head, oStyle)
safe.remove(document.body, oDiv) safeDOM.remove(document.body, oDiv)
}, },
} }
} }
const safe = { // ----------------------------------------------------------------------
append(parent: HTMLElement, child: HTMLElement) {
if (!Array.from(parent.children).find(e => e === child)) { const { appendLoading, removeLoading } = useLoading()
return parent.appendChild(child) domReady().then(appendLoading)
}
}, window.onmessage = (ev) => {
remove(parent: HTMLElement, child: HTMLElement) { ev.data.payload === 'removeLoading' && removeLoading()
if (Array.from(parent.children).find(e => e === child)) {
return parent.removeChild(child)
}
},
} }
setTimeout(removeLoading, 4999)

View File

@ -2,13 +2,10 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/assets/favicon.svg" /> <link rel="icon" type="image/x-icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
http-equiv="Content-Security-Policy" <title>Electron + Vite + React</title>
content="script-src 'self' 'unsafe-inline';"
/>
<title>Vite App</title>
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>

10854
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,40 +1,44 @@
{ {
"name": "vite-react-electron", "name": "electron-vite-react",
"productName": "Electron", "version": "2.2.0",
"private": true, "main": "dist-electron/main/index.js",
"version": "1.0.0", "description": "Electron Vite React boilerplate.",
"description": "Vite React Electron boilerplate.",
"author": "草鞋没号 <308487730@qq.com>", "author": "草鞋没号 <308487730@qq.com>",
"license": "MIT", "license": "MIT",
"main": "dist/main/index.cjs", "private": true,
"scripts": { "debug": {
"dev": "node scripts/watch.mjs", "env": {
"build": "tsc --noEmit -p packages/renderer/tsconfig.json && node scripts/build.mjs && electron-builder" "VITE_DEV_SERVER_URL": "http://127.0.0.1:7777/"
}
}, },
"engines": { "scripts": {
"node": ">=14.17.0" "dev": "vite",
"build": "tsc && vite build && electron-builder",
"preview": "vite preview",
"pree2e": "vite build --mode=test",
"e2e": "playwright test"
}, },
"dependencies": { "dependencies": {
"electron-store": "^8.0.1" "electron-updater": "^6.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.0.9", "@playwright/test": "^1.37.1",
"@types/react-dom": "^18.0.4", "@types/react": "^18.2.20",
"@vitejs/plugin-react": "^1.3.2", "@types/react-dom": "^18.2.7",
"electron": "^18.2.4", "@vitejs/plugin-react": "^4.0.4",
"electron-builder": "^23.0.3", "autoprefixer": "^10.4.16",
"execa": "^6.1.0", "electron": "^26.0.0",
"react": "^18.1.0", "electron-builder": "^24.6.3",
"react-dom": "^18.1.0", "postcss": "^8.4.31",
"sass": "^1.51.0", "react": "^18.2.0",
"typescript": "^4.6.4", "react-dom": "^18.2.0",
"vite": "^2.9.9", "tailwindcss": "^3.3.3",
"vite-plugin-esmodule": "^1.2.5", "typescript": "^5.1.6",
"vite-plugin-optimizer": "^1.3.3", "vite": "^4.4.9",
"vite-plugin-resolve": "^2.1.1" "vite-plugin-electron": "^0.13.0-beta.3",
"vite-plugin-electron-renderer": "^0.14.5"
}, },
"env": { "engines": {
"VITE_DEV_SERVER_HOST": "127.0.0.1", "node": "^14.18.0 || >=16.0.0"
"VITE_DEV_SERVER_PORT": 7777
} }
} }

View File

@ -1,72 +0,0 @@
import { app, BrowserWindow, shell } from 'electron'
import { release } from 'os'
import { join } from 'path'
import './samples/electron-store'
import './samples/npm-esm-packages'
// Disable GPU Acceleration for Windows 7
if (release().startsWith('6.1')) app.disableHardwareAcceleration()
// Set application name for Windows 10+ notifications
if (process.platform === 'win32') app.setAppUserModelId(app.getName())
if (!app.requestSingleInstanceLock()) {
app.quit()
process.exit(0)
}
let win: BrowserWindow | null = null
async function createWindow() {
win = new BrowserWindow({
title: 'Main window',
webPreferences: {
preload: join(__dirname, '../preload/index.cjs')
},
})
if (app.isPackaged) {
win.loadFile(join(__dirname, '../renderer/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()
}
// Test active push message to Renderer-process
win.webContents.on('did-finish-load', () => {
win?.webContents.send('main-process-message', (new Date).toLocaleString())
})
// Make all links open with the browser, not with the application
win.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https:')) shell.openExternal(url)
return { action: 'deny' }
})
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
win = null
if (process.platform !== 'darwin') app.quit()
})
app.on('second-instance', () => {
if (win) {
// Focus on the main window if the user tried to open another
if (win.isMinimized()) win.restore()
win.focus()
}
})
app.on('activate', () => {
const allWindows = BrowserWindow.getAllWindows()
if (allWindows.length) {
allWindows[0].focus()
} else {
createWindow()
}
})

View File

@ -1,19 +0,0 @@
/**
* Example of 'electron-store' usage.
*/
import { ipcMain } from 'electron'
import Store from 'electron-store'
/**
* Expose 'electron-store' to Renderer-process through 'ipcMain.handle'
*/
const store = new Store()
ipcMain.handle(
'electron-store',
async (_event, methodSign: string, ...args: any[]) => {
if (typeof (store as any)[methodSign] === 'function') {
return (store as any)[methodSign](...args)
}
return (store as any)[methodSign]
}
)

View File

@ -1,7 +0,0 @@
import { execa } from 'execa'
(async () => {
const { stdout } = await execa('echo', ['unicorns'])
// console.log(stdout) // unicorns
})()

View File

@ -1,31 +0,0 @@
import { builtinModules } from 'module'
import { defineConfig } from 'vite'
import esmodule from 'vite-plugin-esmodule'
import pkg from '../../package.json'
export default defineConfig({
root: __dirname,
plugins: [
esmodule([
'execa',
]),
],
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,
...Object.keys(pkg.dependencies || {}),
],
},
},
})

View File

@ -1,36 +0,0 @@
import fs from 'fs'
import { contextBridge, ipcRenderer } from 'electron'
import { domReady } from './utils'
import { useLoading } from './loading'
const { appendLoading, removeLoading } = useLoading()
;(async () => {
await domReady()
appendLoading()
})()
// --------- Expose some API to the Renderer process. ---------
contextBridge.exposeInMainWorld('fs', fs)
contextBridge.exposeInMainWorld('removeLoading', removeLoading)
contextBridge.exposeInMainWorld('ipcRenderer', withPrototype(ipcRenderer))
// `exposeInMainWorld` can't detect attributes and methods of `prototype`, manually patching it.
function withPrototype(obj: Record<string, any>) {
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
}

View File

@ -1,16 +0,0 @@
/** Document ready */
export const 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,31 +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,
...Object.keys(pkg.dependencies || {}),
],
},
},
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,72 +0,0 @@
import electron from '@/assets/electron.png'
import react from '@/assets/react.svg'
import vite from '@/assets/vite.svg'
import styles from '@/styles/app.module.scss'
import { useState } from 'react'
const App = () => {
const [count, setCount] = useState(0)
return (
<div className={styles.app}>
<header className={styles.appHeader}>
<div className={styles.logos}>
<div className={styles.imgBox}>
<img
src={electron}
style={{ height: '24vw' }}
className={styles.appLogo}
alt="electron"
/>
</div>
<div className={styles.imgBox}>
<img src={vite} style={{ height: '19vw' }} alt="vite" />
</div>
<div className={styles.imgBox}>
<img
src={react}
style={{ maxWidth: '100%' }}
className={styles.appLogo}
alt="logo"
/>
</div>
</div>
<p>Hello Electron + Vite + React!</p>
<p>
<button onClick={() => setCount((count) => count + 1)}>
count is: {count}
</button>
</p>
<p>
Edit <code>App.tsx</code> and save to test HMR updates.
</p>
<div>
<a
className={styles.appLink}
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
{' | '}
<a
className={styles.appLink}
href="https://vitejs.dev/guide/features.html"
target="_blank"
rel="noopener noreferrer"
>
Vite Docs
</a>
<div className={styles.staticPublic}>
Place static files into the{' '}
<code>src/renderer/public</code> folder
<img style={{ width: 90 }} src="./images/node.png" />
</div>
</div>
</header>
</div>
)
}
export default App

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

View File

@ -1,15 +0,0 @@
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
<stop stop-color="#41D1FF"/>
<stop offset="1" stop-color="#BD34FE"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA83"/>
<stop offset="0.0833333" stop-color="#FFDD35"/>
<stop offset="1" stop-color="#FFA800"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -1,15 +0,0 @@
<svg width="410" height="404" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M399.641 59.5246L215.643 388.545C211.844 395.338 202.084 395.378 198.228 388.618L10.5817 59.5563C6.38087 52.1896 12.6802 43.2665 21.0281 44.7586L205.223 77.6824C206.398 77.8924 207.601 77.8904 208.776 77.6763L389.119 44.8058C397.439 43.2894 403.768 52.1434 399.641 59.5246Z" fill="url(#paint0_linear)"/>
<path d="M292.965 1.5744L156.801 28.2552C154.563 28.6937 152.906 30.5903 152.771 32.8664L144.395 174.33C144.198 177.662 147.258 180.248 150.51 179.498L188.42 170.749C191.967 169.931 195.172 173.055 194.443 176.622L183.18 231.775C182.422 235.487 185.907 238.661 189.532 237.56L212.947 230.446C216.577 229.344 220.065 232.527 219.297 236.242L201.398 322.875C200.278 328.294 207.486 331.249 210.492 326.603L212.5 323.5L323.454 102.072C325.312 98.3645 322.108 94.137 318.036 94.9228L279.014 102.454C275.347 103.161 272.227 99.746 273.262 96.1583L298.731 7.86689C299.767 4.27314 296.636 0.855181 292.965 1.5744Z" fill="url(#paint1_linear)"/>
<defs>
<linearGradient id="paint0_linear" x1="6.00017" y1="32.9999" x2="235" y2="344" gradientUnits="userSpaceOnUse">
<stop stop-color="#41D1FF"/>
<stop offset="1" stop-color="#BD34FE"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="194.651" y1="8.81818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA83"/>
<stop offset="0.0833333" stop-color="#FFDD35"/>
<stop offset="1" stop-color="#FFA800"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -1,11 +0,0 @@
export { }
declare global {
interface Window {
// Expose some Api through preload script
fs: typeof import('fs')
ipcRenderer: import('electron').IpcRenderer
removeLoading: () => void
}
}

View File

@ -1,16 +0,0 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
import './samples/electron-store'
import './samples/preload-module'
import './styles/index.css'
const root = createRoot(document.getElementById('root')!)
root.render(
<StrictMode>
<App />
</StrictMode>
)
window.removeLoading()

View File

@ -1,31 +0,0 @@
// Usage of 'electron-store'
const store = {
async get(key: string) {
const { invoke } = window.ipcRenderer
let value = await invoke('electron-store', 'get', key)
try {
value = JSON.parse(value)
} finally {
return value
}
},
async set(key: string, value: any) {
const { invoke } = window.ipcRenderer
let val = value
try {
if (value && typeof value === 'object') {
val = JSON.stringify(value)
}
} finally {
await invoke('electron-store', 'set', key, val)
}
},
};
(async () => {
await store.set('Date.now', Date.now())
console.log('electron-store ->', 'Date.now:', await store.get('Date.now'))
console.log('electron-store ->', 'path:', await window.ipcRenderer.invoke('electron-store', 'path'))
})();
export { }

View File

@ -1,9 +0,0 @@
console.log('fs', window.fs)
console.log('ipcRenderer', window.ipcRenderer)
// Usage of ipcRenderer.on
window.ipcRenderer.on('main-process-message', (_event, ...args) => {
console.log('[Receive Main-process message]:', ...args)
})
export default {}

View File

@ -1,65 +0,0 @@
.app {
text-align: center;
.appHeader {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
.logos {
display: flex;
box-sizing: border-box;
align-items: center;
padding: 0 5vw;
width: 100%;
.imgBox {
width: 33.33%;
.appLogo {
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.appLogo {
animation: App-logo-spin infinite 20s linear;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
}
}
}
button {
font-size: calc(10px + 2vmin);
}
.appLink {
color: #61dafb;
}
.staticPublic {
display: flex;
align-items: center;
code {
padding: 4px 7px;
margin: 0 4px;
border-radius: 4px;
background-color: rgb(30, 30, 30, .7);
font-size: 13px;
}
}
}
}

View File

@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

View File

@ -1,21 +0,0 @@
{
"extends": "../../paths.json",
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"]
}

View File

@ -1,144 +0,0 @@
import { join } from 'path'
import { builtinModules } from 'module'
import { defineConfig, Plugin } from 'vite'
import react from '@vitejs/plugin-react'
import optimizer from 'vite-plugin-optimizer'
import resolve, { lib2esm } from 'vite-plugin-resolve'
import pkg from '../../package.json'
/**
* @see https://vitejs.dev/config/
*/
export default defineConfig({
mode: process.env.NODE_ENV,
root: __dirname,
plugins: [
react(),
electron(),
resolve({
/**
* Here you can resolve some CommonJs module.
* Or some Node.js native modules they may not be built correctly by vite.
* At the same time, these modules should be put in `dependencies`,
* because they will not be built by vite, but will be packaged into `app.asar` by electron-builder
*/
// ESM format code snippets
'electron-store': 'export default require("electron-store");',
/**
* Node.js native module
* Use lib2esm() to easy to convert ESM
* Equivalent to
*
* ```js
* 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,
},
resolve: {
alias: {
'@': join(__dirname, 'src'),
},
},
server: {
host: pkg.env.VITE_DEV_SERVER_HOST,
port: pkg.env.VITE_DEV_SERVER_PORT,
},
})
/**
* For usage of Electron and NodeJS APIs in the Renderer process
* @see https://github.com/caoxiemeihao/electron-vue-vite/issues/52
*/
export function electron(
entries: Parameters<typeof optimizer>[0] = {}
): Plugin {
const builtins = builtinModules.filter((t) => !t.startsWith('_'))
/**
* @see https://github.com/caoxiemeihao/vite-plugins/tree/main/packages/resolve#readme
*/
return optimizer({
electron: electronExport(),
...builtinModulesExport(builtins),
...entries,
})
function electronExport() {
return `
/**
* For all exported modules see https://www.electronjs.org/docs/latest/api/clipboard -> Renderer Process Modules
*/
const electron = require("electron");
const {
clipboard,
nativeImage,
shell,
contextBridge,
crashReporter,
ipcRenderer,
webFrame,
desktopCapturer,
deprecate,
} = electron;
export {
electron as default,
clipboard,
nativeImage,
shell,
contextBridge,
crashReporter,
ipcRenderer,
webFrame,
desktopCapturer,
deprecate,
}
`
}
function builtinModulesExport(modules: string[]) {
return modules
.map((moduleId) => {
const nodeModule = require(moduleId)
const requireModule = `const M = require("${moduleId}");`
const exportDefault = `export default M;`
const exportMembers =
Object.keys(nodeModule)
.map((attr) => `export const ${attr} = M.${attr}`)
.join(';\n') + ';'
const nodeModuleCode = `
${requireModule}
${exportDefault}
${exportMembers}
`
return { [moduleId]: nodeModuleCode }
})
.reduce((memo, item) => Object.assign(memo, item), {})
}
}

View File

@ -1,9 +0,0 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["packages/renderer/src/*"]
}
}
}

54
playwright.config.ts Normal file
View File

@ -0,0 +1,54 @@
import type { PlaywrightTestConfig } from "@playwright/test";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// require('dotenv').config();
/**
* See https://playwright.dev/docs/test-configuration.
*/
const config: PlaywrightTestConfig = {
testDir: "./e2e",
/* Maximum time one test can run for. */
timeout: 30 * 1000,
expect: {
/**
* Maximum time expect() should wait for the condition to be met.
* For example in `await expect(locator).toHaveText();`
*/
timeout: 5000,
},
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
actionTimeout: 0,
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://localhost:3000',
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
// outputDir: 'test-results/',
/* Run your local dev server before starting the tests */
// webServer: {
// command: 'npm run start',
// port: 3000,
// },
};
export default config;

8
postcss.config.cjs Normal file
View File

@ -0,0 +1,8 @@
module.exports = {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

1
public/node.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="216" height="216" viewBox="0 0 216 216"><path fill="#80bd01" d="M104.6 180.7c-2 0-3.9-.5-5.7-1.5l-18.1-10.7c-2.7-1.5-1.4-2-.5-2.4 3.6-1.2 4.3-1.5 8.2-3.7.4-.2.9-.1 1.3.1l13.9 8.2c.5.3 1.2.3 1.7 0l54.1-31.2c.5-.3.8-.9.8-1.5V75.7c0-.6-.3-1.2-.8-1.5l-54-31.2c-.5-.3-1.2-.3-1.7 0l-54 31.2c-.5.3-.9.9-.9 1.5v62.4c0 .6.3 1.2.9 1.4l14.8 8.6c8 4 13-.7 13-5.5V81c0-.9.7-1.6 1.6-1.6h6.9c.9 0 1.6.7 1.6 1.6v61.6c0 10.7-5.8 16.9-16 16.9-3.1 0-5.6 0-12.5-3.4L44.8 148c-3.5-2-5.7-5.8-5.7-9.9V75.7c0-4.1 2.2-7.8 5.7-9.9l54.1-31.2c3.4-1.9 8-1.9 11.4 0l54.1 31.2c3.5 2 5.7 5.8 5.7 9.9v62.4c0 4.1-2.2 7.8-5.7 9.9l-54.1 31.2c-1.8 1-3.7 1.5-5.7 1.5zm43.6-61.5c0-11.7-7.9-14.8-24.5-17-16.8-2.2-18.5-3.4-18.5-7.3 0-3.2 1.4-7.6 13.9-7.6 11.1 0 15.2 2.4 16.9 9.9.1.7.8 1.2 1.5 1.2h7c.4 0 .8-.2 1.1-.5.3-.3.5-.8.4-1.2-1.1-12.9-9.7-18.9-27-18.9-15.4 0-24.6 6.5-24.6 17.4 0 11.8 9.1 15.1 23.9 16.6 17.7 1.7 19.1 4.3 19.1 7.8 0 6-4.8 8.6-16.2 8.6-14.3 0-17.5-3.6-18.5-10.7-.1-.8-.8-1.3-1.6-1.3h-7c-.9 0-1.6.7-1.6 1.6 0 9.1 5 20 28.6 20 17.3-.1 27.1-6.8 27.1-18.6zM172 55.9V57h3v8h1.2v-8h3.1v-1.1H172zm8.4 9.1h1.2v-7.6l2.6 7.6h1.2l2.6-7.6V65h1.2v-9h-1.7l-2.6 7.6-2.6-7.6h-1.8v9z"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 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,70 +0,0 @@
import { spawn } from 'child_process'
import { createServer, build } from 'vite'
import electron from 'electron'
const query = new URLSearchParams(import.meta.url.split('?')[1])
const debug = query.has('debug')
/**
* @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() {
if (electronProcess) {
electronProcess.removeAllListeners()
electronProcess.kill()
}
electronProcess = spawn(electron, ['.'], { stdio: 'inherit', env })
electronProcess.once('exit', process.exit)
},
}
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() {
server.ws.send({ type: 'full-reload' })
},
}],
build: {
watch: {},
},
})
}
// bootstrap
const server = await createServer({ configFile: 'packages/renderer/vite.config.ts' })
await server.listen()
await watchPreload(server)
await watchMain(server)

52
src/App.css Normal file
View File

@ -0,0 +1,52 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo-box {
position: relative;
height: 9em;
}
.logo {
position: absolute;
left: calc(50% - 4.5em);
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: no-preference) {
.logo.electron {
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}

40
src/App.tsx Normal file
View File

@ -0,0 +1,40 @@
import { useState } from 'react'
import UpdateElectron from '@/components/update'
import logoVite from './assets/logo-vite.svg'
import logoElectron from './assets/logo-electron.svg'
import './App.css'
console.log('[App.tsx]', `Hello world from Electron ${process.versions.electron}!`)
function App() {
const [count, setCount] = useState(0)
return (
<div className='App'>
<div className='logo-box'>
<a href='https://github.com/electron-vite/electron-vite-react' target='_blank'>
<img src={logoVite} className='logo vite' alt='Electron + Vite logo' />
<img src={logoElectron} className='logo electron' alt='Electron + Vite logo' />
</a>
</div>
<h1>Electron + Vite + React</h1>
<div className='card'>
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className='read-the-docs'>
Click on the Electron + Vite logo to learn more
</p>
<div className='flex-center'>
Place static files into the<code>/public</code> folder <img style={{ width: '5em' }} src='./node.svg' alt='Node logo' />
</div>
<UpdateElectron />
</div>
)
}
export default App

View File

@ -0,0 +1,8 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M51.3954 39.5028C52.3733 39.6812 53.3108 39.033 53.4892 38.055C53.6676 37.0771 53.0194 36.1396 52.0414 35.9612L51.3954 39.5028ZM28.9393 60.9358C29.4332 61.7985 30.5329 62.0976 31.3957 61.6037C32.2585 61.1098 32.5575 60.0101 32.0636 59.1473L28.9393 60.9358ZM37.6935 66.7457C37.025 66.01 35.8866 65.9554 35.1508 66.6239C34.415 67.2924 34.3605 68.4308 35.029 69.1666L37.6935 66.7457ZM96.9206 89.515C97.7416 88.9544 97.9526 87.8344 97.3919 87.0135C96.8313 86.1925 95.7113 85.9815 94.8904 86.5422L96.9206 89.515ZM52.0414 35.9612C46.4712 34.9451 41.2848 34.8966 36.9738 35.9376C32.6548 36.9806 29.0841 39.1576 27.0559 42.6762L30.1748 44.4741C31.5693 42.0549 34.1448 40.3243 37.8188 39.4371C41.5009 38.5479 46.1547 38.5468 51.3954 39.5028L52.0414 35.9612ZM27.0559 42.6762C24.043 47.9029 25.2781 54.5399 28.9393 60.9358L32.0636 59.1473C28.6579 53.1977 28.1088 48.0581 30.1748 44.4741L27.0559 42.6762ZM35.029 69.1666C39.6385 74.24 45.7158 79.1355 52.8478 83.2597L54.6499 80.1432C47.8081 76.1868 42.0298 71.5185 37.6935 66.7457L35.029 69.1666ZM52.8478 83.2597C61.344 88.1726 70.0465 91.2445 77.7351 92.3608C85.359 93.4677 92.2744 92.6881 96.9206 89.515L94.8904 86.5422C91.3255 88.9767 85.4902 89.849 78.2524 88.7982C71.0793 87.7567 62.809 84.8612 54.6499 80.1432L52.8478 83.2597ZM105.359 84.9077C105.359 81.4337 102.546 78.6127 99.071 78.6127V82.2127C100.553 82.2127 101.759 83.4166 101.759 84.9077H105.359ZM99.071 78.6127C95.5956 78.6127 92.7831 81.4337 92.7831 84.9077H96.3831C96.3831 83.4166 97.5892 82.2127 99.071 82.2127V78.6127ZM92.7831 84.9077C92.7831 88.3817 95.5956 91.2027 99.071 91.2027V87.6027C97.5892 87.6027 96.3831 86.3988 96.3831 84.9077H92.7831ZM99.071 91.2027C102.546 91.2027 105.359 88.3817 105.359 84.9077H101.759C101.759 86.3988 100.553 87.6027 99.071 87.6027V91.2027Z" fill="#A2ECFB"/>
<path d="M91.4873 65.382C90.8456 66.1412 90.9409 67.2769 91.7002 67.9186C92.4594 68.5603 93.5951 68.465 94.2368 67.7058L91.4873 65.382ZM84.507 35.2412C83.513 35.2282 82.6967 36.0236 82.6838 37.0176C82.6708 38.0116 83.4661 38.8279 84.4602 38.8409L84.507 35.2412ZM74.9407 39.8801C75.9127 39.6716 76.5315 38.7145 76.323 37.7425C76.1144 36.7706 75.1573 36.1517 74.1854 36.3603L74.9407 39.8801ZM25.5491 80.9047C25.6932 81.8883 26.6074 82.5688 27.5911 82.4247C28.5747 82.2806 29.2552 81.3664 29.1111 80.3828L25.5491 80.9047ZM94.2368 67.7058C97.8838 63.3907 100.505 58.927 101.752 54.678C103.001 50.4213 102.9 46.2472 100.876 42.7365L97.7574 44.5344C99.1494 46.9491 99.3603 50.0419 98.2974 53.6644C97.2323 57.2945 94.9184 61.3223 91.4873 65.382L94.2368 67.7058ZM100.876 42.7365C97.9119 37.5938 91.7082 35.335 84.507 35.2412L84.4602 38.8409C91.1328 38.9278 95.7262 41.0106 97.7574 44.5344L100.876 42.7365ZM74.1854 36.3603C67.4362 37.8086 60.0878 40.648 52.8826 44.8146L54.6847 47.931C61.5972 43.9338 68.5948 41.2419 74.9407 39.8801L74.1854 36.3603ZM52.8826 44.8146C44.1366 49.872 36.9669 56.0954 32.1491 62.3927C27.3774 68.63 24.7148 75.2115 25.5491 80.9047L29.1111 80.3828C28.4839 76.1026 30.4747 70.5062 35.0084 64.5802C39.496 58.7143 46.2839 52.7889 54.6847 47.931L52.8826 44.8146Z" fill="#A2ECFB"/>
<path d="M49.0825 87.2295C48.7478 86.2934 47.7176 85.8059 46.7816 86.1406C45.8455 86.4753 45.358 87.5055 45.6927 88.4416L49.0825 87.2295ZM78.5635 96.4256C79.075 95.5732 78.7988 94.4675 77.9464 93.9559C77.0941 93.4443 75.9884 93.7205 75.4768 94.5729L78.5635 96.4256ZM79.5703 85.1795C79.2738 86.1284 79.8027 87.1379 80.7516 87.4344C81.7004 87.7308 82.71 87.2019 83.0064 86.2531L79.5703 85.1795ZM69.156 22.5301C68.2477 22.1261 67.1838 22.535 66.7799 23.4433C66.3759 24.3517 66.7848 25.4155 67.6931 25.8194L69.156 22.5301ZM45.6927 88.4416C47.5994 93.7741 50.1496 98.2905 53.2032 101.505C56.2623 104.724 59.9279 106.731 63.9835 106.731V103.131C61.1984 103.131 58.4165 101.765 55.8131 99.0249C53.2042 96.279 50.8768 92.2477 49.0825 87.2295L45.6927 88.4416ZM63.9835 106.731C69.8694 106.731 74.8921 102.542 78.5635 96.4256L75.4768 94.5729C72.0781 100.235 68.0122 103.131 63.9835 103.131V106.731ZM83.0064 86.2531C85.0269 79.7864 86.1832 72.1831 86.1832 64.0673H82.5832C82.5832 71.8536 81.4723 79.0919 79.5703 85.1795L83.0064 86.2531ZM86.1832 64.0673C86.1832 54.1144 84.4439 44.922 81.4961 37.6502C78.5748 30.4436 74.3436 24.8371 69.156 22.5301L67.6931 25.8194C71.6364 27.5731 75.3846 32.1564 78.1598 39.0026C80.9086 45.7836 82.5832 54.507 82.5832 64.0673H86.1832Z" fill="#A2ECFB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M103.559 84.9077C103.559 82.4252 101.55 80.4127 99.071 80.4127C96.5924 80.4127 94.5831 82.4252 94.5831 84.9077C94.5831 87.3902 96.5924 89.4027 99.071 89.4027C101.55 89.4027 103.559 87.3902 103.559 84.9077Z" stroke="#A2ECFB" stroke-width="3.6" stroke-linecap="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M28.8143 89.4027C31.2929 89.4027 33.3023 87.3902 33.3023 84.9077C33.3023 82.4252 31.2929 80.4127 28.8143 80.4127C26.3357 80.4127 24.3264 82.4252 24.3264 84.9077C24.3264 87.3902 26.3357 89.4027 28.8143 89.4027Z" stroke="#A2ECFB" stroke-width="3.6" stroke-linecap="round"/>
<path d="M63.9835 27.6986C66.4621 27.6986 68.4714 25.6861 68.4714 23.2036C68.4714 20.7211 66.4621 18.7086 63.9835 18.7086C61.5049 18.7086 59.4956 20.7211 59.4956 23.2036C59.4956 25.6861 61.5049 27.6986 63.9835 27.6986Z" stroke="#A2ECFB" stroke-width="3.6" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

1
src/assets/logo-v1.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.6 KiB

20
src/assets/logo-vite.svg Normal file
View File

@ -0,0 +1,20 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_103_2)">
<path d="M63.9202 127.84C99.2223 127.84 127.84 99.2223 127.84 63.9202C127.84 28.6181 99.2223 0 63.9202 0C28.6181 0 0 28.6181 0 63.9202C0 99.2223 28.6181 127.84 63.9202 127.84Z" fill="url(#paint0_linear_103_2)"/>
<path d="M70.7175 48.0096L56.3133 50.676C56.0766 50.7199 55.9013 50.9094 55.887 51.1369L55.001 65.2742C54.9801 65.6072 55.3038 65.8656 55.6478 65.7907L59.6582 64.9163C60.0334 64.8346 60.3724 65.1468 60.2953 65.5033L59.1038 71.0151C59.0237 71.386 59.3923 71.7032 59.7758 71.5932L62.2528 70.8822C62.6368 70.7721 63.0057 71.0902 62.9245 71.4615L61.031 80.1193C60.9126 80.6608 61.6751 80.9561 61.9931 80.4918L62.2055 80.1817L73.9428 58.053C74.1393 57.6825 73.8004 57.26 73.3696 57.3385L69.2417 58.0912C68.8538 58.1618 68.5237 57.8206 68.6332 57.462L71.3274 48.6385C71.437 48.2794 71.1058 47.9378 70.7175 48.0096Z" fill="url(#paint1_linear_103_2)"/>
</g>
<defs>
<linearGradient id="paint0_linear_103_2" x1="1.43824" y1="7.91009" x2="56.3296" y2="82.4569" gradientUnits="userSpaceOnUse">
<stop stop-color="#41D1FF"/>
<stop offset="1" stop-color="#BD34FE"/>
</linearGradient>
<linearGradient id="paint1_linear_103_2" x1="60.3173" y1="48.7336" x2="64.237" y2="77.1962" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA83"/>
<stop offset="0.0833333" stop-color="#FFDD35"/>
<stop offset="1" stop-color="#FFA800"/>
</linearGradient>
<clipPath id="clip0_103_2">
<rect width="128" height="128" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,67 @@
import React, { ReactNode } from 'react'
import { createPortal } from 'react-dom'
import './modal.css'
const ModalTemplate: React.FC<React.PropsWithChildren<{
title?: ReactNode
footer?: ReactNode
cancelText?: string
okText?: string
onCancel?: () => void
onOk?: () => void
width?: number
}>> = props => {
const {
title,
children,
footer,
cancelText = 'Cancel',
okText = 'OK',
onCancel,
onOk,
width = 530,
} = props
return (
<div className='update-modal'>
<div className='update-modal__mask' />
<div className='update-modal__warp'>
<div className='update-modal__content' style={{ width }}>
<div className='content__header'>
<div className='content__header-text'>{title}</div>
<span
className='update-modal--close'
onClick={onCancel}
>
<svg
viewBox="0 0 1024 1024"
version="1.1" xmlns="http://www.w3.org/2000/svg"
>
<path d="M557.312 513.248l265.28-263.904c12.544-12.48 12.608-32.704 0.128-45.248-12.512-12.576-32.704-12.608-45.248-0.128l-265.344 263.936-263.04-263.84C236.64 191.584 216.384 191.52 203.84 204 191.328 216.48 191.296 236.736 203.776 249.28l262.976 263.776L201.6 776.8c-12.544 12.48-12.608 32.704-0.128 45.248 6.24 6.272 14.464 9.44 22.688 9.44 8.16 0 16.32-3.104 22.56-9.312l265.216-263.808 265.44 266.24c6.24 6.272 14.432 9.408 22.656 9.408 8.192 0 16.352-3.136 22.592-9.344 12.512-12.48 12.544-32.704 0.064-45.248L557.312 513.248z" p-id="2764" fill="currentColor">
</path>
</svg>
</span>
</div>
<div className='content__body'>{children}</div>
{typeof footer !== 'undefined' ? (
<div className='content__footer'>
<button onClick={onCancel}>{cancelText}</button>
<button onClick={onOk}>{okText}</button>
</div>
) : footer}
</div>
</div>
</div>
)
}
const Modal = (props: Parameters<typeof ModalTemplate>[0] & { open: boolean }) => {
const { open, ...omit } = props
return createPortal(
open ? ModalTemplate(omit) : null,
document.body,
)
}
export default Modal

View File

@ -0,0 +1,87 @@
.update-modal {
--primary-color: rgb(224, 30, 90);
.update-modal__mask {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
z-index: 9;
background: rgba(0, 0, 0, 0.45);
}
.update-modal__warp {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 19;
}
.update-modal__content {
box-shadow: 0 0 10px -4px rgb(130, 86, 208);
overflow: hidden;
border-radius: 4px;
.content__header {
display: flex;
line-height: 38px;
background-color: var(--primary-color);
.content__header-text {
font-weight: bold;
width: 0;
flex-grow: 1;
}
}
.update-modal--close {
width: 30px;
height: 30px;
margin: 4px;
line-height: 34px;
text-align: center;
cursor: pointer;
svg {
width: 17px;
height: 17px;
}
}
.content__body {
padding: 10px;
background-color: #fff;
color: #333;
}
.content__footer {
padding: 10px;
background-color: #fff;
display: flex;
justify-content: flex-end;
button {
padding: 7px 11px;
background-color: var(--primary-color);
font-size: 14px;
margin-left: 10px;
&:first-child {
margin-left: 0;
}
}
}
}
.icon {
padding: 0 15px;
width: 20px;
fill: currentColor;
&:hover {
color: rgba(0, 0, 0, 0.4);
}
}
}

View File

@ -0,0 +1,22 @@
import React from 'react'
import './progress.css'
const Progress: React.FC<React.PropsWithChildren<{
percent?: number
}>> = props => {
const { percent = 0 } = props
return (
<div className='update-progress'>
<div className='update-progress-pr'>
<div
className='update-progress-rate'
style={{ width: `${3 * percent}px` }}
/>
</div>
<span className='update-progress-num'>{(percent ?? 0).toString().substring(0, 4)}%</span>
</div>
)
}
export default Progress

View File

@ -0,0 +1,21 @@
.update-progress {
display: flex;
align-items: center;
.update-progress-pr {
border: 1px solid #000;
border-radius: 3px;
height: 6px;
width: 300px;
}
.update-progress-rate {
height: 6px;
border-radius: 3px;
background-image: linear-gradient(to right, rgb(130, 86, 208) 0%, var(--primary-color) 100%)
}
.update-progress-num {
margin: 0 10px;
}
}

View File

@ -0,0 +1,49 @@
# electron-updater
English | [简体中文](README.zh-CN.md)
> Use `electron-updater` to realize the update detection, download and installation of the electric program.
```sh
npm i electron-updater
```
### Main logic
1. ##### Configuration of the update the service address and update information script:
Add a `publish` field to `electron-builder.json5` for configuring the update address and which strategy to use as the update service.
``` json5
{
"publish": {
"provider": "generic",
"channel": "latest",
"url": "https://foo.com/"
}
}
```
For more information, please refer to : [electron-builder.json5...](https://github.com/electron-vite/electron-vite-react/blob/2f2880a9f19de50ff14a0785b32a4d5427477e55/electron-builder.json5#L38)
2. ##### The update logic of Electron:
- Checking if an update is available;
- Checking the version of the software on the server;
- Checking if an update is available;
- Downloading the new version of the software from the server (when an update is available);
- Installation method;
For more information, please refer to : [update...](https://github.com/electron-vite/electron-vite-react/blob/main/electron/main/update.ts)
3. ##### Updating UI pages in Electron:
The main function is to provide a UI page for users to trigger the update logic mentioned in (2.) above. Users can click on the page to trigger different update functions in Electron.
For more information, please refer to : [components/update...](https://github.com/electron-vite/electron-vite-react/blob/main/src/components/update/index.tsx)
---
Here it is recommended to trigger updates through user actions (in this project, Electron update function is triggered after the user clicks on the "Check for updates" button).
For more information on using `electron-updater` for Electron updates, please refer to the documentation : [auto-update](https://www.electron.build/.html)

View File

@ -0,0 +1,51 @@
# electron-auto-update
[English](README.md) | 简体中文
使用`electron-updater`实现electron程序的更新检测、下载和安装等功能。
```sh
npm i electron-updater
```
### 主要逻辑
1. ##### 更新地址、更新信息脚本的配置
在`electron-builder.json5`添加`publish`字段,用来配置更新地址和使用哪种策略作为更新服务
``` json5
{
"publish": {
"provider": "generic", // 提供者、提供商
"channel": "latest", // 生成yml文件的名称
"url": "https://foo.com/" //更新地址
}
}
```
更多见 : [electron-builder.json5...](xxx)
2. ##### Electron更新逻辑
- 检测更新是否可用;
- 检测服务端的软件版本;
- 检测更新是否可用;
- 下载服务端新版软件(当更新可用);
- 安装方式;
更多见 : [update...](https://github.com/electron-vite/electron-vite-react/blob/main/electron/main/update.ts)
3. ##### Electron更新UI页面
主要功能是:用户触发上述(2.)更新逻辑的UI页面。用户可以通过点击页面触发electron更新的不同功能。
更多见 : [components/update.ts...](https://github.com/electron-vite/electron-vite-react/tree/main/src/components/update/index.tsx)
---
这里建议更新触发以用户操作触发(本项目的以用户点击 **更新检测** 后触发electron更新功能
关于更多使用`electron-updater`进行electron更新见文档[auto-update](https://www.electron.build/.html)

View File

@ -0,0 +1,133 @@
import { ipcRenderer } from 'electron'
import type { ProgressInfo } from 'electron-updater'
import { useCallback, useEffect, useState } from 'react'
import Modal from '@/components/update/Modal'
import Progress from '@/components/update/Progress'
import './update.css'
const Update = () => {
const [checking, setChecking] = useState(false)
const [updateAvailable, setUpdateAvailable] = useState(false)
const [versionInfo, setVersionInfo] = useState<VersionInfo>()
const [updateError, setUpdateError] = useState<ErrorType>()
const [progressInfo, setProgressInfo] = useState<Partial<ProgressInfo>>()
const [modalOpen, setModalOpen] = useState<boolean>(false)
const [modalBtn, setModalBtn] = useState<{
cancelText?: string
okText?: string
onCancel?: () => void
onOk?: () => void
}>({
onCancel: () => setModalOpen(false),
onOk: () => ipcRenderer.invoke('start-download'),
})
const checkUpdate = async () => {
setChecking(true)
/**
* @type {import('electron-updater').UpdateCheckResult | null | { message: string, error: Error }}
*/
const result = await ipcRenderer.invoke('check-update')
setProgressInfo({ percent: 0 })
setChecking(false)
setModalOpen(true)
if (result?.error) {
setUpdateAvailable(false)
setUpdateError(result?.error)
}
}
const onUpdateCanAvailable = useCallback((_event: Electron.IpcRendererEvent, arg1: VersionInfo) => {
setVersionInfo(arg1)
setUpdateError(undefined)
// Can be update
if (arg1.update) {
setModalBtn(state => ({
...state,
cancelText: 'Cancel',
okText: 'Update',
onOk: () => ipcRenderer.invoke('start-download'),
}))
setUpdateAvailable(true)
} else {
setUpdateAvailable(false)
}
}, [])
const onUpdateError = useCallback((_event: Electron.IpcRendererEvent, arg1: ErrorType) => {
setUpdateAvailable(false)
setUpdateError(arg1)
}, [])
const onDownloadProgress = useCallback((_event: Electron.IpcRendererEvent, arg1: ProgressInfo) => {
setProgressInfo(arg1)
}, [])
const onUpdateDownloaded = useCallback((_event: Electron.IpcRendererEvent, ...args: any[]) => {
setProgressInfo({ percent: 100 })
setModalBtn(state => ({
...state,
cancelText: 'Later',
okText: 'Install now',
onOk: () => ipcRenderer.invoke('quit-and-install'),
}))
}, [])
useEffect(() => {
// Get version information and whether to update
ipcRenderer.on('update-can-available', onUpdateCanAvailable)
ipcRenderer.on('update-error', onUpdateError)
ipcRenderer.on('download-progress', onDownloadProgress)
ipcRenderer.on('update-downloaded', onUpdateDownloaded)
return () => {
ipcRenderer.off('update-can-available', onUpdateCanAvailable)
ipcRenderer.off('update-error', onUpdateError)
ipcRenderer.off('download-progress', onDownloadProgress)
ipcRenderer.off('update-downloaded', onUpdateDownloaded)
}
}, [])
return (
<>
<Modal
open={modalOpen}
cancelText={modalBtn?.cancelText}
okText={modalBtn?.okText}
onCancel={modalBtn?.onCancel}
onOk={modalBtn?.onOk}
footer={updateAvailable ? /* hide footer */null : undefined}
>
<div className='modal-slot'>
{updateError
? (
<div>
<p>Error downloading the latest version.</p>
<p>{updateError.message}</p>
</div>
) : updateAvailable
? (
<div>
<div>The last version is: v{versionInfo?.newVersion}</div>
<div className='new-version__target'>v{versionInfo?.version} -&gt; v{versionInfo?.newVersion}</div>
<div className='update__progress'>
<div className='progress__title'>Update progress:</div>
<div className='progress__bar'>
<Progress percent={progressInfo?.percent} ></Progress>
</div>
</div>
</div>
)
: (
<div className='can-not-available'>{JSON.stringify(versionInfo ?? {}, null, 2)}</div>
)}
</div>
</Modal>
<button disabled={checking} onClick={checkUpdate}>
{checking ? 'Checking...' : 'Check update'}
</button>
</>
)
}
export default Update

View File

@ -0,0 +1,24 @@
.modal-slot {
.update-progress {
display: flex;
}
.new-version__target,
.update__progress {
margin-left: 40px;
}
.progress__title {
margin-right: 10px;
}
.progress__bar {
width: 0;
flex-grow: 1;
}
.can-not-available {
padding: 20px;
text-align: center;
}
}

94
src/index.css Normal file
View File

@ -0,0 +1,94 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
code {
background-color: #1a1a1a;
padding: 2px 4px;
margin: 0 4px;
border-radius: 4px;
}
.card {
padding: 2em;
}
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
code {
background-color: #f9f9f9;
}
}

13
src/main.tsx Normal file
View File

@ -0,0 +1,13 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './samples/node-api'
import './index.css'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
postMessage({ payload: 'removeLoading' }, '*')

13
src/samples/node-api.ts Normal file
View File

@ -0,0 +1,13 @@
import { lstat } from 'node:fs/promises'
import { cwd } from 'node:process'
import { ipcRenderer } from 'electron'
ipcRenderer.on('main-process-message', (_event, ...args) => {
console.log('[Receive Main-process message]:', ...args)
})
lstat(cwd()).then(stats => {
console.log('[fs.lstat]', stats)
}).catch(err => {
console.error(err)
})

10
src/type/electron-updater.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
interface VersionInfo {
update: boolean
version: string
newVersion?: string
}
interface ErrorType {
message: string
error: Error
}

14
tailwind.config.js Normal file
View File

@ -0,0 +1,14 @@
/** @type {import('tailwindcss').Config} */
export default {
content: [
'./index.html',
'./src/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {},
},
corePlugins: {
preflight: false,
},
plugins: [],
}

View File

@ -1,15 +1,27 @@
{ {
"extends": "./paths.json",
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"module": "ESNext", "useDefineForClassFields": true,
"allowJs": true, "lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true, "skipLibCheck": true,
"skipDefaultLibCheck": true, "esModuleInterop": false,
"esModuleInterop": true, "allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node", "moduleResolution": "Node",
"resolveJsonModule": true, "resolveJsonModule": true,
"strict": true, "isolatedModules": true,
"jsx": "react-jsx" "noEmit": true,
} "jsx": "react-jsx",
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
},
},
"include": ["src", "electron"],
"references": [{ "path": "./tsconfig.node.json" }]
} }

10
tsconfig.node.json Normal file
View File

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

8
types.d.ts vendored
View File

@ -1,8 +0,0 @@
declare namespace NodeJS {
interface ProcessEnv {
NODE_ENV: 'development' | 'production'
readonly VITE_DEV_SERVER_HOST: string
readonly VITE_DEV_SERVER_PORT: string
}
}

78
vite.config.ts Normal file
View File

@ -0,0 +1,78 @@
import { rmSync } from 'node:fs'
import path from 'node:path'
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import electron from 'vite-plugin-electron'
import renderer from 'vite-plugin-electron-renderer'
import pkg from './package.json'
// https://vitejs.dev/config/
export default defineConfig(({ command }) => {
rmSync('dist-electron', { recursive: true, force: true })
const isServe = command === 'serve'
const isBuild = command === 'build'
const sourcemap = isServe || !!process.env.VSCODE_DEBUG
return {
resolve: {
alias: {
'@': path.join(__dirname, 'src')
},
},
plugins: [
react(),
electron([
{
// Main-Process entry file of the Electron App.
entry: 'electron/main/index.ts',
onstart(options) {
if (process.env.VSCODE_DEBUG) {
console.log(/* For `.vscode/.debug.script.mjs` */'[startup] Electron App')
} else {
options.startup()
}
},
vite: {
build: {
sourcemap,
minify: isBuild,
outDir: 'dist-electron/main',
rollupOptions: {
external: Object.keys('dependencies' in pkg ? pkg.dependencies : {}),
},
},
},
},
{
entry: 'electron/preload/index.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()
},
vite: {
build: {
sourcemap: sourcemap ? 'inline' : undefined, // #332
minify: isBuild,
outDir: 'dist-electron/preload',
rollupOptions: {
external: Object.keys('dependencies' in pkg ? pkg.dependencies : {}),
},
},
},
}
]),
// Use Node.js API in the Renderer-process
renderer(),
],
server: process.env.VSCODE_DEBUG && (() => {
const url = new URL(pkg.debug.env.VITE_DEV_SERVER_URL)
return {
host: url.hostname,
port: +url.port,
}
})(),
clearScreen: false,
}
})