quickwin 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +31 -23
- package/README.md +18 -10
- package/examples/exec_server.js +38 -0
- package/examples/exec_server.ts +35 -0
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -1,25 +1,33 @@
|
|
|
1
|
-
> [
|
|
1
|
+
> [䏿–‡æ–‡æ¡£](README.md) · **English**
|
|
2
2
|
|
|
3
3
|
# QuickWin
|
|
4
4
|
|
|
5
|
-
QuickJS
|
|
5
|
+
QuickJS runtime for Windows, with native GUI, networking, WASM, FFI and more.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
Goal: compatibility with Windows XP+ (32/64-bit) and a minimal binary size.
|
|
8
|
+
|
|
9
|
+
Currently: supports Windows 7+ (64-bit), ~1.5MB binary.
|
|
10
|
+
|
|
11
|
+
Early-stage project with known bugs.
|
|
12
|
+
|
|
13
|
+
Download directly from the GitHub Release:
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
iwr https://github.com/xna00/quickwin/releases/latest/download/qwin.exe -OutFile qwin.exe
|
|
17
|
+
iwr https://github.com/xna00/quickwin/releases/latest/download/main.js -OutFile main.js
|
|
18
|
+
.\qwin.exe main.js
|
|
10
19
|
```
|
|
11
20
|
|
|
12
21
|
## Features
|
|
13
22
|
|
|
14
|
-
- **Win32 GUI**
|
|
15
|
-
- **React renderer**
|
|
16
|
-
- **HTTP/HTTPS**
|
|
17
|
-
- **WebSocket**
|
|
18
|
-
- **WebAssembly**
|
|
19
|
-
- **FFI**
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
22
|
-
- **Dynamic import** — `import('https://esm.sh/...')`, no npm install needed
|
|
23
|
+
- **Win32 GUI** — native windows, buttons, edit boxes, list boxes, tray icons, popup menus
|
|
24
|
+
- **React renderer** — declarative GUI in JSX with `useState`/`useEffect`, diff updates ([react-qw](lib/react-qw/))
|
|
25
|
+
- **HTTP/HTTPS** — `fetch()` API, Brotli decompression, chunked transfer, conditional caching
|
|
26
|
+
- **WebSocket** — full RFC 6455 implementation, ws:// + wss://
|
|
27
|
+
- **WebAssembly** — WAMR-based, supports `WebAssembly.*` standard API
|
|
28
|
+
- **FFI** — call any DLL function via libffi
|
|
29
|
+
- **Polyfills** — `TextEncoder`, `URL`, `URLSearchParams`, `btoa`/`atob`, `crypto.subtle`, `setTimeout`
|
|
30
|
+
- **Dynamic import** — `import('https://esm.sh/...')`, no dependency installation needed
|
|
23
31
|
|
|
24
32
|
## CLI
|
|
25
33
|
|
|
@@ -42,12 +50,12 @@ quickwin -- script.js --flag # -- stops option parsing
|
|
|
42
50
|
| `-d` | Enable HTTP debug logging |
|
|
43
51
|
| `--` | Stop option parsing, remaining args passed to script |
|
|
44
52
|
|
|
45
|
-
All unknown flags are transparently forwarded to `scriptArgs`
|
|
53
|
+
All unknown flags are transparently forwarded to `scriptArgs` — no error,
|
|
46
54
|
no consumption. Script file is the first non-flag argument after option parsing.
|
|
47
55
|
|
|
48
56
|
## Embedded Script
|
|
49
57
|
|
|
50
|
-
You can embed a JS script directly into the `qwin.exe` binary
|
|
58
|
+
You can embed a JS script directly into the `qwin.exe` binary — no recompilation needed.
|
|
51
59
|
|
|
52
60
|
### Format (appended to exe)
|
|
53
61
|
|
|
@@ -89,7 +97,7 @@ When run without a script file argument, `qwin.exe` checks for embedded JS at th
|
|
|
89
97
|
| `fetch` | `import './lib/fetch.js'` | adds `fetch()`, `Response`, `Headers` to globalThis |
|
|
90
98
|
| `websocket` | `import './lib/websocket.js'` | adds `WebSocket` to globalThis |
|
|
91
99
|
| `polyfill` | `import './lib/polyfill.js'` | adds `TextEncoder`, `URL`, `btoa`/`atob`, `setTimeout` to globalThis |
|
|
92
|
-
| `preact` | `lib/preact/...` | JSX
|
|
100
|
+
| `preact` | `lib/preact/...` | JSX → Win32 renderer (`render`, `useState`, `useEffect`) |
|
|
93
101
|
| `react-qw` | `lib/react-qw/` | React Custom Renderer for Win32 GUI ([docs](lib/react-qw/)) |
|
|
94
102
|
|
|
95
103
|
## Worker
|
|
@@ -144,9 +152,9 @@ Both sides must set `onmessage = null` when communication is complete. This rele
|
|
|
144
152
|
## Examples
|
|
145
153
|
|
|
146
154
|
```bash
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
.\qwin.exe examples/preact_demo.js # counter GUI with JSX + hooks
|
|
156
|
+
.\qwin.exe examples/tray_demo.js # system tray app
|
|
157
|
+
.\qwin.exe examples/pdf_preview.js # PDF reader with mupdf
|
|
150
158
|
```
|
|
151
159
|
|
|
152
160
|
## Build from Source
|
|
@@ -178,11 +186,11 @@ cd quickwin
|
|
|
178
186
|
|--------|-------------|
|
|
179
187
|
| `make` / `make nodebug` | fast build |
|
|
180
188
|
| `make minimal` | `-Os` + LTO + `-mwindows` + UPX, no console, add `-o CON` for console |
|
|
181
|
-
| `make nowasm` | no WASM/WAMR build
|
|
182
|
-
| `make release` | `-O2` + LTO + strip, ~
|
|
189
|
+
| `make nowasm` | no WASM/WAMR build → `_build/qwin-nowasm.exe` (~1.2MB, no `WebAssembly` global) |
|
|
190
|
+
| `make release` | `-O2` + LTO + strip, ~1.5MB |
|
|
183
191
|
| `make debug` | debug build with bridge logs |
|
|
184
192
|
| `make js` | compile TypeScript via tsc |
|
|
185
|
-
| `make wasm` | compile WAT
|
|
193
|
+
| `make wasm` | compile WAT → WASM fixtures |
|
|
186
194
|
| `make test` | run all tests |
|
|
187
195
|
| `make test TEST=-net` | skip network tests (fast) |
|
|
188
196
|
| `make test TEST=wasm` | run WASM tests only |
|
package/README.md
CHANGED
|
@@ -2,11 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
# QuickWin
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Windows 平台上的 QuickJS 运行时,支持原生 GUI、网络、WASM、FFI 等能力。
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
目标:兼容 Windows XP+(32/64 位),保持最小二进制体积。
|
|
8
|
+
|
|
9
|
+
现状:当前支持 Windows 7+(64 位),体积约 1.5MB。
|
|
10
|
+
|
|
11
|
+
项目处于早期,功能待完善,包含已知 bug。
|
|
12
|
+
|
|
13
|
+
直接从 GitHub Release 下载运行:
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
iwr https://github.com/xna00/quickwin/releases/latest/download/qwin.exe -OutFile qwin.exe
|
|
17
|
+
iwr https://github.com/xna00/quickwin/releases/latest/download/main.js -OutFile main.js
|
|
18
|
+
.\qwin.exe main.js
|
|
10
19
|
```
|
|
11
20
|
|
|
12
21
|
## 特性
|
|
@@ -17,9 +26,8 @@ quickwin script.js
|
|
|
17
26
|
- **WebSocket** —— 完整的 RFC 6455 实现,支持 ws:// 与 wss://
|
|
18
27
|
- **WebAssembly** —— 基于 WAMR,支持标准 `WebAssembly.*` API
|
|
19
28
|
- **FFI** —— 通过 libffi 调用任意 DLL 函数
|
|
20
|
-
- **mupdf** —— 内嵌 PDF 渲染
|
|
21
29
|
- **Polyfills** —— `TextEncoder`、`URL`、`URLSearchParams`、`btoa`/`atob`、`crypto.subtle`、`setTimeout`
|
|
22
|
-
- **动态导入** —— `import('https://esm.sh/...')
|
|
30
|
+
- **动态导入** —— `import('https://esm.sh/...')`,无需安装任何依赖
|
|
23
31
|
|
|
24
32
|
## CLI
|
|
25
33
|
|
|
@@ -143,9 +151,9 @@ parent.onmessage = (e) => {
|
|
|
143
151
|
## 示例
|
|
144
152
|
|
|
145
153
|
```bash
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
.\qwin.exe examples/preact_demo.js # JSX + hooks 的计数器 GUI
|
|
155
|
+
.\qwin.exe examples/tray_demo.js # 系统托盘应用
|
|
156
|
+
.\qwin.exe examples/pdf_preview.js # 基于 mupdf 的 PDF 阅读器
|
|
149
157
|
```
|
|
150
158
|
|
|
151
159
|
## 从源码构建
|
|
@@ -178,7 +186,7 @@ cd quickwin
|
|
|
178
186
|
| `make` / `make nodebug` | 快速构建 |
|
|
179
187
|
| `make minimal` | `-Os` + LTO + `-mwindows` + UPX,无控制台,需要控制台时加 `-o CON` |
|
|
180
188
|
| `make nowasm` | 无 WASM/WAMR 构建 → `_build/qwin-nowasm.exe`(约 1.2MB,无 `WebAssembly` 全局) |
|
|
181
|
-
| `make release` | `-O2` + LTO + strip,约
|
|
189
|
+
| `make release` | `-O2` + LTO + strip,约 1.5MB |
|
|
182
190
|
| `make debug` | 带 bridge 日志的调试构建 |
|
|
183
191
|
| `make js` | 通过 tsc 编译 TypeScript |
|
|
184
192
|
| `make wasm` | 编译 WAT → WASM fixtures |
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createServer } from '../lib/http-server.js';
|
|
2
|
+
import * as std from 'std';
|
|
3
|
+
function readAll(file) {
|
|
4
|
+
const chunks = [];
|
|
5
|
+
const buf = new Uint8Array(4096);
|
|
6
|
+
while (true) {
|
|
7
|
+
const n = file.read(buf.buffer, 0, 4096);
|
|
8
|
+
if (n <= 0)
|
|
9
|
+
break;
|
|
10
|
+
chunks.push(buf.slice(0, n));
|
|
11
|
+
}
|
|
12
|
+
let total = 0;
|
|
13
|
+
for (const c of chunks)
|
|
14
|
+
total += c.length;
|
|
15
|
+
const out = new Uint8Array(total);
|
|
16
|
+
let offset = 0;
|
|
17
|
+
for (const c of chunks) {
|
|
18
|
+
out.set(c, offset);
|
|
19
|
+
offset += c.length;
|
|
20
|
+
}
|
|
21
|
+
return new TextDecoder().decode(out);
|
|
22
|
+
}
|
|
23
|
+
const server = createServer(async (req) => {
|
|
24
|
+
if (req.method === 'POST' && new URL(req.url).pathname === '/exec') {
|
|
25
|
+
const body = await req.json();
|
|
26
|
+
const file = std.popen(body.cmd, 'r');
|
|
27
|
+
if (!file)
|
|
28
|
+
return new Response('popen failed', { status: 500 });
|
|
29
|
+
const output = readAll(file);
|
|
30
|
+
file.close();
|
|
31
|
+
return new Response(output, {
|
|
32
|
+
headers: { 'Content-Type': 'application/octet-stream' }
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return new Response('Not Found', { status: 404 });
|
|
36
|
+
});
|
|
37
|
+
server.listen(8080);
|
|
38
|
+
console.log('listening on http://localhost:8080');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createServer } from '../lib/http-server.js'
|
|
2
|
+
import * as std from 'std'
|
|
3
|
+
|
|
4
|
+
function readAll(file: std.FILE): string {
|
|
5
|
+
const chunks: Uint8Array[] = []
|
|
6
|
+
const buf = new Uint8Array(4096)
|
|
7
|
+
while (true) {
|
|
8
|
+
const n = file.read(buf.buffer, 0, 4096)
|
|
9
|
+
if (n <= 0) break
|
|
10
|
+
chunks.push(buf.slice(0, n))
|
|
11
|
+
}
|
|
12
|
+
let total = 0
|
|
13
|
+
for (const c of chunks) total += c.length
|
|
14
|
+
const out = new Uint8Array(total)
|
|
15
|
+
let offset = 0
|
|
16
|
+
for (const c of chunks) { out.set(c, offset); offset += c.length }
|
|
17
|
+
return new TextDecoder().decode(out)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const server = createServer(async (req) => {
|
|
21
|
+
if (req.method === 'POST' && new URL(req.url).pathname === '/exec') {
|
|
22
|
+
const body = await req.json() as { cmd: string }
|
|
23
|
+
const file = std.popen(body.cmd, 'r')
|
|
24
|
+
if (!file) return new Response('popen failed', { status: 500 })
|
|
25
|
+
const output = readAll(file)
|
|
26
|
+
file.close()
|
|
27
|
+
return new Response(output, {
|
|
28
|
+
headers: { 'Content-Type': 'application/octet-stream' }
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
return new Response('Not Found', { status: 404 })
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
server.listen(8080)
|
|
35
|
+
console.log('listening on http://localhost:8080')
|