Skip to content

Commit bab2b93

Browse files
committed
docs(recipes): translate deno desktop guide to indonesian
- Add backend dan distribusi page - Add bindings dan jembatan HTTP page - Add jendela, menu, tray dan dialog page - Add membangun aplikasi page - Add menyajikan UI page - Add notifikasi, auto-update dan pelaporan error page - Add ringkasan deno desktop page
1 parent 6119178 commit bab2b93

7 files changed

Lines changed: 889 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
description: 'Mengapa win.bind dan proxy bindings tidak bertahan pada jalur serve Deserve, serta pola API HTTP plus executeJs yang membawa data antara halaman dan sisi Deno di kedua arah.'
3+
---
4+
5+
# Bindings dan Jembatan HTTP
6+
7+
> **Referensi**: [Bindings Deno Desktop](https://docs.deno.com/runtime/desktop/bindings/)
8+
9+
Runtime `deno desktop` membawa sebuah kanal binding. [`win.bind()`](https://docs.deno.com/api/deno/~/Deno.BrowserWindow.bind) mendaftarkan fungsi Deno, dan halaman memanggilnya lewat proxy `bindings.<name>()` seakan fungsi itu lokal, tanpa lompatan HTTP. Ini satu-satunya bagian permukaan desktop yang tidak bekerja di balik server Deserve, jadi halaman ini menjelaskan perilakunya dan pola yang menggantikannya.
10+
11+
## Apa yang Dijanjikan Kanal
12+
13+
Di luar Deserve, sebuah binding terlihat rapi. Sisi Deno mendaftarkan handler, halaman memanggilnya, dan panggilan meresolusi melintasi batas:
14+
15+
```typescript twoslash
16+
// deno-lint-ignore no-explicit-any
17+
const win = {} as any
18+
// ---cut---
19+
// Sisi Deno, mendaftarkan handler
20+
win.bind('saveNote', async (text: string) => {
21+
await Deno.writeTextFile('./note.txt', text)
22+
return { ok: true }
23+
})
24+
```
25+
26+
```typescript twoslash
27+
// Sisi halaman, panggil seperti fungsi lokal
28+
// deno-lint-ignore no-explicit-any
29+
declare const bindings: any
30+
// ---cut---
31+
const result = await bindings.saveNote('hello')
32+
```
33+
34+
## Mengapa Rusak di Balik Deserve
35+
36+
Jembatan binding menempel ke webview saat runtime menegakkan servernya sendiri. Deserve menjalankan jalur serve-nya lewat panggilan internal `Deno.serve` yang dibungkus logika framework, dan pembungkus itu melepas jembatan dari webview yang terlihat. Proxy tetap menjawab di halaman, `typeof bindings.saveNote` terbaca `function`, karena proxy membangun fungsi saat diakses. Panggilannya sendiri lalu ditolak:
37+
38+
```
39+
Error: No callback bound for: saveNote
40+
```
41+
42+
Kegagalan tidak bergantung pada waktu. Bind sebelum serve, bind setelah server mulai, memuat ulang jendela, atau mengonstruksi jendela belakangan semua ditolak dengan cara yang sama. `Deno.serve` mentah plus `win.bind` bekerja, dan `win.bind` yang sama di balik `router.serve()` tidak, yang menempatkan penyebab pada jalur serve alih-alih panggilan binding.
43+
44+
Intinya singkat. Perlakukan bindings sebagai tak tersedia di aplikasi desktop Deserve dan bawa data lewat HTTP.
45+
46+
## Penggantinya: Dua Arah
47+
48+
Aplikasi desktop butuh lalu lintas dua arah, halaman ke Deno dan Deno ke halaman. Dua transport sudah mencakup keduanya, dan tak satu pun menyentuh kanal binding.
49+
50+
### Halaman ke Deno Lewat HTTP
51+
52+
Halaman memanggil route API, dan route berjalan dengan izin Deno. Ini bentuk panggilan yang sama dari [Menyajikan UI](/id/recipes/desktop/serving#berbicara-kembali-ke-server), kini dibingkai sebagai pengganti binding:
53+
54+
```typescript twoslash
55+
// Sisi halaman, mengganti panggilan bindings
56+
async function saveNote(text: string): Promise<{ path: string }> {
57+
// Post ke route API lokal sebagai gantinya
58+
const response = await fetch('/api/note', {
59+
method: 'POST',
60+
headers: { 'content-type': 'application/json' },
61+
body: JSON.stringify({ text })
62+
})
63+
return await response.json()
64+
}
65+
```
66+
67+
```typescript twoslash
68+
import type { Context } from '@neabyte/deserve'
69+
70+
// routes/api/note.ts
71+
export async function POST(ctx: Context): Promise<Response> {
72+
// Baca body request JSON bertipe
73+
const requestBody = await ctx.get.body<{ text?: string }>()
74+
const homeDir = Deno.env.get('HOME') ?? '.'
75+
const path = `${homeDir}/.note.txt`
76+
// Tulis catatan dengan izin Deno
77+
await Deno.writeTextFile(path, requestBody?.text ?? '')
78+
return ctx.send.json({ path })
79+
}
80+
```
81+
82+
Route memiliki akses disk, jadi satu handler melayani halaman di jendela dan browser di host tanpa percabangan.
83+
84+
### Deno ke Halaman dengan executeJs
85+
86+
Arah lainnya menjalankan potongan di dalam halaman dari sisi Deno dengan `executeJs()`, panggilan yang sama yang dipakai [handler menu](/id/recipes/desktop/native-apis#menu-aplikasi). Halaman menaruh fungsi `saveNote` dari atas ke `window`, dan sisi native memanggilnya berdasarkan nama:
87+
88+
```typescript twoslash
89+
// deno-lint-ignore no-explicit-any
90+
async function saveNote(text: string): Promise<{ path: string }> {
91+
return { path: '' }
92+
}
93+
// ---cut---
94+
// Baca textarea, lalu pakai ulang saveNote
95+
function saveNoteFromPage(): Promise<{ path: string }> {
96+
const field = document.querySelector('textarea')
97+
return saveNote(field?.value ?? '')
98+
}
99+
// Paparkan untuk menu native
100+
// deno-lint-ignore no-explicit-any
101+
;(window as any).saveNote = saveNoteFromPage
102+
```
103+
104+
```typescript twoslash
105+
// deno-lint-ignore no-explicit-any
106+
const win = {} as any
107+
// ---cut---
108+
// Jalankan handler halaman jika ada
109+
win.executeJs('if (window.saveNote) window.saveNote()')
110+
```
111+
112+
Pintasan menu dan tombol di halaman kini berbagi satu jalur simpan. Menu memanggil `executeJs`, tombol memanggil `saveNote` langsung, dan keduanya mendarat di route API yang sama. Penjaga penting karena `executeJs` bisa berjalan sebelum halaman selesai dimuat, saat `window.saveNote` masih tak terdefinisi.
113+
114+
## Membaca Hasil
115+
116+
Halaman yang butuh nilai dari Deno, seperti status berjalan atau info sistem, membacanya dari route JSON alih-alih nilai kembalian binding. Pemeriksaan desktop dari [Menyajikan UI](/id/recipes/desktop/serving#mendeteksi-mode-desktop) mengikuti bentuk persis ini, di mana `Deno.desktopVersion` melintas lewat API alih-alih lewat `bindings`.
117+
118+
## Biaya dan Imbalan
119+
120+
Lompatan HTTP menambah satu perjalanan loopback bolak-balik yang akan dilewati sebuah binding. Pada koneksi lokal, biayanya di bawah persepsi manusia untuk laju request yang dihasilkan UI desktop, jadi tukar-tambahnya berpihak pada model yang lebih sederhana. Imbalannya adalah satu server yang berperilaku identik di host dan di jendela, tanpa lapisan binding terpisah untuk didaftarkan, di-debug, atau dijaga tetap selaras.
121+
122+
Dengan data mengalir dua arah, bagian yang tersisa adalah layanan runtime yang duduk di sisi Deno: [Notifikasi, Auto-update dan Pelaporan Error](/id/recipes/desktop/notifications-updates).
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
description: 'Memilih backend rendering untuk aplikasi desktop Deserve, membangun bundle platform seperti app, dmg, msi, dan AppImage, mengompilasi-silang ke target lain dari satu host, serta menandatangani kode bundle macOS.'
3+
---
4+
5+
# Backend dan Distribusi
6+
7+
> **Referensi**: [Backend Deno Desktop](https://docs.deno.com/runtime/desktop/backends/)
8+
9+
Langkah terakhir mengubah proyek menjadi bundle siap kirim. Pilihan backend menentukan cara halaman dirender dan apakah DevTools tersedia, ekstensi keluaran menentukan format paket, dan satu host bisa mengompilasi-silang untuk tiap target. Server Deserve tetap sama di sepanjang itu, karena distribusi adalah urusan pengemasan.
10+
11+
## Memilih Backend
12+
13+
Field `backend`, atau flag `--backend`, memilih engine rendering yang dipanggang ke bundle. Tiga opsi ada, dan hanya dua yang cocok untuk aplikasi Deserve:
14+
15+
| Backend | Rendering | Ukuran | DevTools | Cocok Deserve |
16+
| --------- | ---------------------------------- | --------------- | -------- | ------------- |
17+
| `webview` | Webview OS, default | Kecil | Tidak | Ya |
18+
| `cef` | Chromium terbundel | Besar, ~150 MB | Ya | Ya |
19+
| `raw` | Tanpa engine web | Terkecil | Tidak | Tidak |
20+
21+
Backend `webview` memakai engine OS, WKWebView di macOS, WebView2 di Windows, WebKitGTK di Linux. Ia menjaga bundle kecil dan merender halaman Deserve dengan baik, dengan harga perbedaan rendering antar platform.
22+
23+
Backend `cef` membundel Chromium untuk rendering identik di mana-mana dan DevTools penuh, sebagai gantinya unduhan jauh lebih besar. Binary framework diunduh sekali dan tercache.
24+
25+
Backend `raw` tidak punya webview sama sekali, jadi UI Deserve yang disajikan lewat HTTP tak punya apa pun untuk merendernya. Build berhasil dan server tetap berjalan, tetapi tak ada halaman muncul. Sisihkan `raw` untuk aplikasi yang menggambar permukaannya sendiri, bukan untuk UI web.
26+
27+
```json
28+
{
29+
"desktop": {
30+
"backend": "webview"
31+
}
32+
}
33+
```
34+
35+
Flag `--backend` menimpa field untuk satu build dan hanya menerima `cef` serta `webview`. Memilih `raw` terjadi lewat field. Beralih antara `cef` dan `webview` tak butuh perubahan kode, karena API jendela, menu, dan event yang sama bekerja di keduanya.
36+
37+
## DevTools
38+
39+
DevTools menempel ke halaman untuk memeriksa elemen, konsol, dan panel jaringan. Ia hanya tersedia pada backend `cef`. Backend `webview` default berbicara protokol inspektor berbeda yang belum dituju DevTools terpadu, jadi [`win.openDevtools()`](https://docs.deno.com/api/deno/~/Deno.BrowserWindow.openDevtools) tak berefek di sana.
40+
41+
Build yang butuh DevTools beralih ke `cef` untuk pengembangan, lalu mengirim pada backend mana pun yang cocok untuk rilis:
42+
43+
```bash
44+
# Jalankan dengan Chromium untuk DevTools
45+
deno desktop --backend cef --include routes --include views main.ts
46+
```
47+
48+
Sisi Deno menjalankan inspektor di bawah `--inspect` apa pun backend-nya, jadi debugging sisi server tetap tersedia bahkan di `webview`. Alur inspektor lengkap ada di [referensi DevTools](https://docs.deno.com/runtime/desktop/devtools/).
49+
50+
## Format Keluaran
51+
52+
Ekstensi keluaran menentukan paket yang dihasilkan build. Blok `output` mengatur jalur per platform, dan flag [`--output`](https://docs.deno.com/runtime/desktop/distribution/) menimpanya untuk satu build:
53+
54+
```json
55+
{
56+
"desktop": {
57+
"output": {
58+
"macos": "./dist/DeserveDesktop.app",
59+
"windows": "./dist/DeserveDesktop",
60+
"linux": "./dist/deserve-desktop"
61+
}
62+
}
63+
}
64+
```
65+
66+
Tiap platform menerima beberapa ekstensi:
67+
68+
| Platform | Ekstensi | Menghasilkan |
69+
| -------- | ------------- | ---------------------------------- |
70+
| macOS | `.app` | Bundle aplikasi, default |
71+
| macOS | `.dmg` | Image disk seret-ke-Applications |
72+
| Windows | direktori | Folder aplikasi dengan peluncur |
73+
| Windows | `.msi` | Paket Windows Installer |
74+
| Linux | direktori | Folder aplikasi dengan peluncur |
75+
| Linux | `.AppImage` | Bundle portabel file tunggal |
76+
| Linux | `.deb` | Paket Debian atau Ubuntu |
77+
| Linux | `.rpm` | Paket Fedora atau RHEL |
78+
79+
`.dmg` memanggil `hdiutil`, jadi ia harus dibangun di host macOS. Sisanya dirakit dalam Rust murni dan dibangun dari host mana pun:
80+
81+
```bash
82+
# Bangun image disk seret-ke-Applications
83+
deno desktop --include routes --include views --output ./dist/DeserveDesktop.dmg main.ts
84+
```
85+
86+
## Kompilasi-Silang
87+
88+
Satu host membangun untuk tiap target yang didukung. `--target` menamai satu triple, dan `--all-targets` mencakup semuanya. CLI mengunduh runtime dan arsip backend yang cocok untuk target, tanpa toolchain platform di host:
89+
90+
```bash
91+
# Bangun untuk macOS Intel dari host mana pun
92+
deno desktop --target x86_64-apple-darwin --include routes --include views main.ts
93+
```
94+
95+
Triple yang didukung adalah `aarch64-apple-darwin`, `x86_64-apple-darwin`, `x86_64-pc-windows-msvc`, `aarch64-unknown-linux-gnu`, dan `x86_64-unknown-linux-gnu`. Satu-satunya pengecualian untuk pembangunan-silang bebas-host adalah `.dmg` macOS, yang butuh `hdiutil` dan karenanya host macOS. Matriks lengkap dan contoh CI ada di [referensi distribusi](https://docs.deno.com/runtime/desktop/distribution/).
96+
97+
## Mengompresi Bundle
98+
99+
`--compress` mengirim bundle swa-ekstrak. Muatan runtime berat dikompresi di aplikasi terdistribusi dan dibongkar ke folder per-pengguna saat jalan pertama, yang mengecilkan unduhan sebagai ganti satu kali dekompresi:
100+
101+
```bash
102+
# Unduhan lebih kecil, bongkar saat jalan pertama
103+
deno desktop --compress --include routes --include views main.ts
104+
```
105+
106+
Codec default ke pengaturan artefak-lebih-kecil dan bisa dipilih dengan `--compress=xz` atau `--compress=zstd`, di mana `zstd` menukar sebagian ukuran demi jalan pertama lebih cepat.
107+
108+
## Penandatanganan Kode
109+
110+
Di macOS, `deno desktop` menandatangani bundle dengan sendirinya. Default-nya adalah tanda tangan ad-hoc, ditulis sebagai `-`, yang memberi aplikasi identitas kode stabil, cukup agar OS memberi [izin notifikasi](/id/recipes/desktop/notifications-updates#syarat-di-macos), tetapi tidak cukup untuk didistribusikan tanpa peringatan Gatekeeper:
111+
112+
```json
113+
{
114+
"desktop": {
115+
"macos": {
116+
"codesignIdentity": "-"
117+
}
118+
}
119+
}
120+
```
121+
122+
Identitas Developer ID asli menggantikan `-` dan menghasilkan bundle yang dapat dinotarisasi, ditandatangani dengan Hardened Runtime. Notarisasi tetap langkah terpisah yang dijalankan dengan `xcrun notarytool`. Penandatanganan berjalan di host macOS, karena ia memanggil `codesign`. Detail penandatanganan dan notarisasi ada di [referensi distribusi](https://docs.deno.com/runtime/desktop/distribution/#code-signing).
123+
124+
## Kembali ke Peta
125+
126+
Itu menutup lingkaran dari build pertama menuju bundle terkirim. [Ringkasan](/id/recipes/desktop/overview#kompatibilitas-fitur) menyimpan peta kompatibilitas untuk seluruh permukaan, dan server Deserve produksi di luar konteks desktop dibahas di [Deploy Produksi](/id/recipes/production-deploy).
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
---
2+
description: 'Menyiapkan blok desktop di deno.json, mengompilasi server Deserve menjadi bundle native, menyematkan route dan view, serta meresolusi jalur template terhadap bundle alih-alih direktori kerja.'
3+
---
4+
5+
# Membangun Aplikasi
6+
7+
> **Referensi**: [Deno Desktop CLI](https://docs.deno.com/runtime/desktop/)
8+
9+
Sebuah build desktop berangkat dari proyek Deserve biasa, jenis yang dari [Mulai Cepat](/id/getting-started/quick-start), lalu menambahkan blok `desktop` ke `deno.json` plus beberapa flag build. Kode server tetap sama. Langkah kompilasi memanggang server itu, route, view, dan backend rendering menjadi satu bundle aplikasi.
10+
11+
## Blok Desktop
12+
13+
Konfigurasi untuk `deno desktop` tinggal di blok `desktop` di dalam `deno.json`. Blok minimal menamai aplikasi dan memilih backend rendering, sementara field `name` dan `version` di akar memberi metadata bundle:
14+
15+
```json
16+
{
17+
"name": "deserve-desktop",
18+
"version": "0.1.0",
19+
"imports": {
20+
"@neabyte/deserve": "jsr:@neabyte/deserve@0.15.0"
21+
},
22+
"desktop": {
23+
"app": {
24+
"name": "Deserve Desktop",
25+
"identifier": "com.example.deservedesktop"
26+
},
27+
"backend": "webview"
28+
}
29+
}
30+
```
31+
32+
`app.identifier` adalah string reverse-DNS. Ia memberi id bundle macOS, entri desktop Linux, dan id aplikasi Windows, dan nilai stabil di sini adalah yang membuat [notifikasi](/id/recipes/desktop/notifications-updates#notifikasi) bisa meminta izin. Pilihan `backend` dan sisa blok dibahas di [Backend dan Distribusi](/id/recipes/desktop/distribution).
33+
34+
## Mendefinisikan Task
35+
36+
Sebuah [`deno task`](https://docs.deno.com/runtime/reference/cli/task/) menyimpan perintah build yang panjang. Flag `--include` paling penting, karena folder route dan view dibaca saat runtime dan harus ikut di dalam bundle:
37+
38+
```json
39+
{
40+
"tasks": {
41+
"desktop": "deno desktop --allow-net --allow-read --allow-env --allow-write --include routes --include views main.ts"
42+
}
43+
}
44+
```
45+
46+
Tiap flag izin terbawa ke dalam bundle, himpunan yang sama dengan yang dipakai [deploy produksi](/id/recipes/production-deploy#daftar-periksa-permission). Menjalankan `deno task desktop` lalu mengompilasi aplikasi untuk platform host.
47+
48+
## Menyematkan Route dan View
49+
50+
Tanpa `--include`, langkah kompilasi memanggang `main.ts` dan modul yang diimpornya, tetapi bukan folder route dan view yang dibaca Deserve dari disk saat request. Keluaran build menampilkan apa yang masuk:
51+
52+
```
53+
Embedded Files
54+
DeserveDesktop.dylib
55+
├── main.ts
56+
├── routes/*
57+
└── views/*
58+
```
59+
60+
Saat route dan view tidak ada di daftar itu, aplikasi yang berjalan menjawab tiap request dengan 404, karena router memindai folder kosong. Menambahkan `--include routes --include views` menaruh kedua folder di filesystem virtual yang disematkan, tempat router menemukannya saat runtime.
61+
62+
## Jebakan Direktori Kerja
63+
64+
Bundle terkompilasi berjalan dengan direktori kerja diatur ke tempat pengguna meluncurkannya, bukan folder yang menampung binary. Jalur relatif seperti `./routes` lalu meresolusi terhadap lokasi pengguna dan menunjuk ke ketiadaan. Halaman merender 404 meski folder sudah disematkan.
65+
66+
Perbaikannya menambatkan jalur ke modul alih-alih ke direktori kerja. [`import.meta.dirname`](https://docs.deno.com/api/web/~/ImportMeta) menyimpan folder absolut dari modul saat ini, jadi menggabungkan folder route dan view ke sana meresolusi dengan cara yang sama di host maupun di dalam bundle:
67+
68+
```typescript twoslash
69+
import { Router } from '@neabyte/deserve'
70+
71+
// Tambatkan jalur ke folder modul ini
72+
const base = import.meta.dirname
73+
74+
const router = new Router({
75+
routes: { directory: `${base}/routes` },
76+
views: { directory: `${base}/views` }
77+
})
78+
79+
await router.serve(8000, '127.0.0.1')
80+
```
81+
82+
Mengikat `127.0.0.1` menjaga server pada loopback, satu-satunya antarmuka yang dibutuhkan aplikasi desktop. Argumen port adalah titik awal, karena runtime desktop memberi server port miliknya sendiri, detail yang dibahas di [Menyajikan UI](/id/recipes/desktop/serving#menemukan-port).
83+
84+
## Jalan Pertama
85+
86+
Setelah `deno task desktop` selesai, bundle mendarat di samping proyek. Meluncurkannya membuka jendela dan halaman dimuat dari server yang disematkan:
87+
88+
```bash
89+
# Buka bundle yang baru dibangun
90+
open "Deserve Desktop.app"
91+
```
92+
93+
File entry yang sama juga berjalan di host dengan `deno run`, karena bagian native tetap diam saat tidak ada jendela. Jalur ganda itulah yang diandalkan [penjaga API native](/id/recipes/desktop/native-apis#tetap-dwi-mode), dan itu menjaga pengembangan berbasis browser tetap cepat sementara build desktop tinggal satu perintah saja.

0 commit comments

Comments
 (0)