npmrun 1 month ago
commit
93f905edd9
  1. 175
      .gitignore
  2. 15
      README.md
  3. 1
      aaa.txt
  4. BIN
      assets/icon.ico
  5. BIN
      assets/icons/icon_128x128.ico
  6. BIN
      assets/icons/icon_16x16.ico
  7. BIN
      assets/icons/icon_256x256.ico
  8. BIN
      assets/icons/icon_32x32.ico
  9. BIN
      assets/icons/icon_48x48.ico
  10. BIN
      assets/icons/icon_68x68.ico
  11. 1
      bbb.txt
  12. 32
      bun.lock
  13. 23
      hidecmd.bat
  14. BIN
      icon.ico
  15. BIN
      icon.png
  16. 20
      main copy.ts
  17. 10
      main.js.map
  18. 57
      main.ts
  19. BIN
      output.ico
  20. 6
      over.ts
  21. 9
      package.json
  22. 4
      test.bat
  23. 27
      tsconfig.json
  24. 31
      ui.html
  25. 5
      worker.ts

175
.gitignore

@ -0,0 +1,175 @@
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
# Logs
logs
_.log
npm-debug.log_
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Caches
.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
# Runtime data
pids
_.pid
_.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# 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/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# IntelliJ based IDEs
.idea
# Finder (MacOS) folder config
.DS_Store

15
README.md

@ -0,0 +1,15 @@
bun build ./main.js --compile --minify --windows-hide-console --outfile myapp
bun build ./main.js --compile --minify --windows-hide-console --windows-icon=assets/icon.ico --outfile myapp
bun build --compile --minify --sourcemap --target=bun-windows-x64 --windows-hide-console ./main.ts --outfile myapp --windows-icon=./assets/icon.ico
bun build --compile --minify --sourcemap --target=bun-windows-x64 --windows-hide-console --windows-icon=output.ico ./main.ts --outfile myapp
bun build ./main.js --compile --minify --windows-icon ./assets/icon.ico --windows-hide-console --outfile myapp
https://github.com/tr1ckydev/webview-bun
https://www.xgs.cc/note/other/bun-windows-gui
.\hidecmd.bat todoapp.exe
安装了https://imagemagick.org/script/convert.php 这个工具

1
aaa.txt

@ -0,0 +1 @@
D:\@code\@demo\webview-bun-demo\main copy.ts

BIN
assets/icon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

BIN
assets/icons/icon_128x128.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
assets/icons/icon_16x16.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

BIN
assets/icons/icon_256x256.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

BIN
assets/icons/icon_32x32.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
assets/icons/icon_48x48.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
assets/icons/icon_68x68.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

1
bbb.txt

@ -0,0 +1 @@
D:\@code\@demo\webview-bun-demo

32
bun.lock

@ -0,0 +1,32 @@
{
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "webview-bun-demo",
"dependencies": {
"webview-bun": "^2.3.0",
},
"devDependencies": {
"@types/bun": "latest",
},
"peerDependencies": {
"typescript": "^5.0.0",
},
},
},
"packages": {
"@types/bun": ["@types/bun@1.2.6", "", { "dependencies": { "bun-types": "1.2.6" } }, "sha512-fY9CAmTdJH1Llx7rugB0FpgWK2RKuHCs3g2cFDYXUutIy1QGiPQxKkGY8owhfZ4MXWNfxwIbQLChgH5gDsY7vw=="],
"@types/node": ["@types/node@22.13.13", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ=="],
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
"bun-types": ["bun-types@1.2.6", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-FbCKyr5KDiPULUzN/nm5oqQs9nXCHD8dVc64BArxJadCvbNzAI6lUWGh9fSJZWeDIRD38ikceBU8Kj/Uh+53oQ=="],
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
"webview-bun": ["webview-bun@2.3.0", "", {}, "sha512-SYOksNzgjTajM+xhqdbhd1xzmCfDyqdmkLGSyZ5i30HRR5KTZJN6+cyE+OGCBFoPFBPmskUM3R99YXtQJqP7Qg=="],
}
}

23
hidecmd.bat

@ -0,0 +1,23 @@
@echo off
echo Looking for vswhere.exe...
set "vswhere=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
if not exist "%vswhere%" set "vswhere=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe"
if not exist "%vswhere%" (
echo ERROR: Failed to find vswhere.exe
exit /b 1
)
echo Found %vswhere%
echo Looking for VC...
for /f "usebackq tokens=*" %%i in (`"%vswhere%" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do (
set vc_dir=%%i
)
if not exist "%vc_dir%\Common7\Tools\vsdevcmd.bat" (
echo ERROR: Failed to find VC tools x86/x64
exit /b 1
)
echo Found %vc_dir%
call "%vc_dir%\Common7\Tools\vsdevcmd.bat" -arch=x64 -host_arch=x64
editbin /SUBSYSTEM:WINDOWS %1

BIN
icon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

BIN
icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

20
main copy.ts

@ -0,0 +1,20 @@
import { Webview, SizeHint } from "webview-bun";
import fs from "node:fs";
// 把html嵌入到单独可执行文件中,编译无需带ui.html
import html from "./ui.html" with { type: "text" };
import path from "node:path";
// 第一个参数是禁止开发者工具 SizeHint.FIXED是禁窗口最大化
const webview = new Webview(false, { height: 480, width: 640, hint: SizeHint.NONE });
let counter = 0;
// 绑定前端button(increment,decrement)的事件
webview.bind("count", (a) => counter += a);
// 绑定前端button(compute)的事件
webview.bind("compute", (a, b) => a + b);
// 软件标题
webview.title = "Bun App";
fs.writeFileSync("./aaa.txt", import.meta.path)
fs.writeFileSync("./bbb.txt", process.cwd())
const data = fs.readFileSync(path.resolve("./ui.html"), "utf-8").toString()
webview.setHTML(data);
webview.run();

10
main.js.map

@ -0,0 +1,10 @@
{
"version": 3,
"sources": ["main.ts"],
"sourcesContent": [
"import fs from \"node:fs\";\r\nimport path from \"node:path\";\r\n\r\nconst server = Bun.serve({\r\n fetch() {\r\n // return Response.json({ success: true });\r\n return new Response(\"<h1>Hello</h1>\", {\r\n headers: {\r\n \"content-type\": \"text/html; charset=utf-8\",\r\n },\r\n });\r\n },\r\n});\r\n\r\nconst worker = new Worker(\"./worker.ts\");\r\nworker.addEventListener(\"close\", () => server.stop(true));\r\n\r\nprocess.on(\"exit\", (code) => {\r\n console.log(`About to exit with code: ${code}`);\r\n // 在这里执行你的清理代码\r\n});\r\nconsole.log(\"aa\");\r\n\r\n[\"SIGINT\", \"SIGTERM\"].forEach((signal) => {\r\n process.on(signal, () => {\r\n console.log(`收到${signal}信号,程序即将退出`);\r\n fs.writeFileSync(\"./cc.txt\", `收到${signal}信号,程序即将退出`);\r\n // 清理操作\r\n process.exit(0);\r\n });\r\n});\r\n\r\nprocess.on(\"SIGINT\", () => {\r\n console.log(\"Received SIGINT\");\r\n});\r\n\r\nprocess.on(\"exit\", (code) => {\r\n console.log(`Process exited with code ${code}`);\r\n});\r\nprocess.on(\"beforeExit\", (code) => {\r\n console.log(`Event loop is empty!`);\r\n // 可以用作更新\r\n const proc = Bun.spawn([path.resolve(\"./test.bat\")], {\r\n cwd: process.cwd(),\r\n detached: true,\r\n windowsHide: true,\r\n });\r\n // const proc = Bun.spawn([\"bun\", \"over.ts\"], {\r\n // cwd: process.cwd(),\r\n // detached: true,\r\n // });\r\n proc.unref();\r\n});\r\n\r\nprocess.on(\"exit\", (code) => {\r\n console.log(`Process is exiting with code ${code}`);\r\n});\r\n"
],
"mappings": ";AAAA,kBACA,oBAEA,IAAM,EAAS,IAAI,MAAM,CACrB,KAAK,EAAG,CAEJ,OAAO,IAAI,SAAS,iBAAkB,CAClC,QAAS,CACL,eAAgB,0BACpB,CACJ,CAAC,EAET,CAAC,EAEK,EAAS,IAAI,OAAO,aAAa,EACvC,EAAO,iBAAiB,QAAS,IAAM,EAAO,KAAK,EAAI,CAAC,EAExD,QAAQ,GAAG,OAAQ,CAAC,IAAS,CACzB,QAAQ,IAAI,4BAA4B,GAAM,EAEjD,EACD,QAAQ,IAAI,IAAI,EAEhB,CAAC,SAAU,SAAS,EAAE,QAAQ,CAAC,IAAW,CACtC,QAAQ,GAAG,EAAQ,IAAM,CACrB,QAAQ,IAAI,eAAI,yDAAiB,EACjC,EAAG,cAAc,WAAY,eAAI,yDAAiB,EAElD,QAAQ,KAAK,CAAC,EACjB,EACJ,EAED,QAAQ,GAAG,SAAU,IAAM,CACvB,QAAQ,IAAI,iBAAiB,EAChC,EAED,QAAQ,GAAG,OAAQ,CAAC,IAAS,CACzB,QAAQ,IAAI,4BAA4B,GAAM,EACjD,EACD,QAAQ,GAAG,aAAc,CAAC,IAAS,CAC/B,QAAQ,IAAI,sBAAsB,EAErB,IAAI,MAAM,CAAC,EAAK,QAAQ,YAAY,CAAC,EAAG,CACjD,IAAK,QAAQ,IAAI,EACjB,SAAU,GACV,YAAa,EACjB,CAAC,EAKI,MAAM,EACd,EAED,QAAQ,GAAG,OAAQ,CAAC,IAAS,CACzB,QAAQ,IAAI,gCAAgC,GAAM,EACrD",
"debugId": "1EAC9F068E78F9B364756E2164756E21",
"names": []
}

57
main.ts

@ -0,0 +1,57 @@
import fs from "node:fs";
import path from "node:path";
const server = Bun.serve({
fetch() {
// return Response.json({ success: true });
return new Response("<h1>Hello</h1>", {
headers: {
"content-type": "text/html; charset=utf-8",
},
});
},
});
const worker = new Worker("./worker.ts");
worker.addEventListener("close", () => server.stop(true));
process.on("exit", (code) => {
console.log(`About to exit with code: ${code}`);
// 在这里执行你的清理代码
});
console.log("aa");
["SIGINT", "SIGTERM"].forEach((signal) => {
process.on(signal, () => {
console.log(`收到${signal}信号,程序即将退出`);
fs.writeFileSync("./cc.txt", `收到${signal}信号,程序即将退出`);
// 清理操作
process.exit(0);
});
});
process.on("SIGINT", () => {
console.log("Received SIGINT");
});
process.on("exit", (code) => {
console.log(`Process exited with code ${code}`);
});
process.on("beforeExit", (code) => {
console.log(`Event loop is empty!`);
// 可以用作更新
const proc = Bun.spawn([path.resolve("./test.bat")], {
cwd: process.cwd(),
detached: true,
windowsHide: true,
});
// const proc = Bun.spawn(["bun", "over.ts"], {
// cwd: process.cwd(),
// detached: true,
// });
proc.unref();
});
process.on("exit", (code) => {
console.log(`Process is exiting with code ${code}`);
});

BIN
output.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

6
over.ts

@ -0,0 +1,6 @@
import fs from "node:fs";
console.log(33);
fs.writeFileSync("D:/@code/@demo/webview-bun-demo/cc.txt", `程序即将退出`);
console.log(222);

9
package.json

@ -0,0 +1,9 @@
{
"name": "webview-bun-demo",
"type": "module",
"devDependencies": {
"@types/bun": "latest",
"webview-bun": "^2.3.0",
"typescript": "^5.0.0"
}
}

4
test.bat

@ -0,0 +1,4 @@
@echo off
timeout /t 2
@REM start "" "myapp.exe"
DEL myapp.exe

27
tsconfig.json

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}

31
ui.html

@ -0,0 +1,31 @@
<div>
<h1>你好,小怪兽</h1>
</div>
<div>
<button id="increment">+</button>
<button id="decrement"></button>
<span>Counter: <span id="counterResult">0</span></span>
</div>
<div>
<button id="compute">Compute</button>
<span>结果: <span id="computeResult">(not started)</span></span>
</div>
<script type="module">
const ui = {};
document.querySelectorAll("[id]").forEach((e) => (ui[e.id] = e));
ui.increment.addEventListener("click", async () => {
ui.counterResult.textContent = await window.count(1);
});
ui.decrement.addEventListener("click", async () => {
ui.counterResult.textContent = await window.count(-1);
});
ui.compute.addEventListener("click", async () => {
ui.compute.disabled = true;
ui.computeResult.textContent = "(pending)";
ui.computeResult.textContent = await window.compute(6, 7);
ui.compute.disabled = false;
});
// 禁用右键菜单
document.addEventListener("contextmenu", (e) => e.preventDefault());
</script>

5
worker.ts

@ -0,0 +1,5 @@
import { Webview, SizeHint } from "webview-bun";
const webview = new Webview();
webview.navigate("http://localhost:3000/");
webview.run();
Loading…
Cancel
Save