@ -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 |
|||
@ -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 这个工具 |
|||
@ -0,0 +1 @@ |
|||
D:\@code\@demo\webview-bun-demo\main copy.ts |
|||
|
After Width: | Height: | Size: 264 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 813 B |
|
After Width: | Height: | Size: 264 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
@ -0,0 +1 @@ |
|||
D:\@code\@demo\webview-bun-demo |
|||
@ -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=="], |
|||
} |
|||
} |
|||
@ -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 |
|||
|
After Width: | Height: | Size: 194 KiB |
|
After Width: | Height: | Size: 300 B |
@ -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(); |
|||
@ -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": [] |
|||
} |
|||
@ -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}`); |
|||
}); |
|||
|
After Width: | Height: | Size: 108 KiB |
@ -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); |
|||
@ -0,0 +1,9 @@ |
|||
{ |
|||
"name": "webview-bun-demo", |
|||
"type": "module", |
|||
"devDependencies": { |
|||
"@types/bun": "latest", |
|||
"webview-bun": "^2.3.0", |
|||
"typescript": "^5.0.0" |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
@echo off |
|||
timeout /t 2 |
|||
@REM start "" "myapp.exe" |
|||
DEL myapp.exe |
|||
@ -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 |
|||
} |
|||
} |
|||
@ -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> |
|||
@ -0,0 +1,5 @@ |
|||
import { Webview, SizeHint } from "webview-bun"; |
|||
|
|||
const webview = new Webview(); |
|||
webview.navigate("http://localhost:3000/"); |
|||
webview.run(); |
|||