astrobit 0.1.1 → 0.1.3
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.md +146 -0
- package/bin/astrobit.js +60 -0
- package/package.json +5 -1
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# astrobit
|
|
2
|
+
|
|
3
|
+
A thin framework for running [MoonBit](https://www.moonbitlang.com/) components as [Astro](https://astro.build/) islands.
|
|
4
|
+
|
|
5
|
+
Write your UI logic in MoonBit, use it directly in `.astro` files — SSR and client-side hydration included.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- [Astro](https://astro.build/) 6+
|
|
10
|
+
- [MoonBit toolchain](https://www.moonbitlang.com/download/) (`moon` CLI)
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
npm install astrobit
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Add the integration to your `astro.config.mjs`:
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
import { defineConfig } from 'astro/config'
|
|
22
|
+
import astrobit from 'astrobit'
|
|
23
|
+
|
|
24
|
+
export default defineConfig({
|
|
25
|
+
integrations: [astrobit()],
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Project Setup
|
|
30
|
+
|
|
31
|
+
Place a `moon.mod.json` at the root of your Astro project:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"name": "yourname/your-project",
|
|
36
|
+
"deps": {
|
|
37
|
+
"SouichiroTsujimoto/astrobit": "0.1.1",
|
|
38
|
+
"mizchi/signals": "0.6.4"
|
|
39
|
+
},
|
|
40
|
+
"preferred-target": "js"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Then install the MoonBit dependencies:
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
moon install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Writing a Component
|
|
51
|
+
|
|
52
|
+
Each component lives in its own directory with a `moon.pkg` file.
|
|
53
|
+
|
|
54
|
+
**`src/components/counter/moon.pkg`**
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"import": [
|
|
58
|
+
"SouichiroTsujimoto/astrobit" @a,
|
|
59
|
+
"SouichiroTsujimoto/astrobit/dom",
|
|
60
|
+
"mizchi/signals"
|
|
61
|
+
],
|
|
62
|
+
"options": {
|
|
63
|
+
"link": { "js": { "exports": ["mount", "render", "hydrate"], "format": "esm" } }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**`src/components/counter/counter.mbt`**
|
|
69
|
+
```moonbit
|
|
70
|
+
fn counter(props : @dom.Props) -> @a.Node {
|
|
71
|
+
let initial = props.get_int("initial")
|
|
72
|
+
let count = @signals.signal(initial)
|
|
73
|
+
@a.div([
|
|
74
|
+
@a.p(@a.dyn_text(fn() { "Count: " + count.get().to_string() })),
|
|
75
|
+
@a.button("-") |> @a.on_click(fn(_) { count.update(fn(n) { n - 1 }) }),
|
|
76
|
+
@a.button("+") |> @a.on_click(fn(_) { count.update(fn(n) { n + 1 }) }),
|
|
77
|
+
])
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pub fn mount(element : @dom.Element, props : @dom.Props) -> Unit {
|
|
81
|
+
@a.mount_dom(element, counter(props))
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pub fn render(props : @dom.Props) -> String {
|
|
85
|
+
@a.render_to_html(counter(props))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub fn hydrate(element : @dom.Element, props : @dom.Props) -> Unit {
|
|
89
|
+
@a.hydrate_dom(element, counter(props))
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Props are received as `@dom.Props` and extracted with typed accessors:
|
|
94
|
+
|
|
95
|
+
```moonbit
|
|
96
|
+
props.get_int("key") // Int (default: 0)
|
|
97
|
+
props.get_string("key") // String (default: "")
|
|
98
|
+
props.get_bool("key") // Bool (default: false)
|
|
99
|
+
|
|
100
|
+
props.get_int("key", default=10) // with explicit default
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Using in Astro
|
|
104
|
+
|
|
105
|
+
Import the `.mbt` file directly. The Vite plugin handles the rest.
|
|
106
|
+
|
|
107
|
+
```astro
|
|
108
|
+
---
|
|
109
|
+
import Counter from '../components/counter/counter.mbt'
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
<!-- client:only — mount on the client, no SSR -->
|
|
113
|
+
<Counter client:only="astrobit" initial={0} />
|
|
114
|
+
|
|
115
|
+
<!-- client:load — SSR + hydration -->
|
|
116
|
+
<Counter client:load initial={0} />
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
TypeScript types for `*.mbt` imports are injected automatically — no manual `env.d.ts` setup required.
|
|
120
|
+
|
|
121
|
+
## Build
|
|
122
|
+
|
|
123
|
+
Before running the dev server, build the MoonBit sources:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
moon build
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Then start Astro:
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
npm run dev
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
HMR is supported — saving a `.mbt` file triggers an automatic rebuild and page reload.
|
|
136
|
+
|
|
137
|
+
## How It Works
|
|
138
|
+
|
|
139
|
+
- **SSR**: `render(props)` returns an HTML string, rendered server-side by Astro.
|
|
140
|
+
- **Hydration** (`client:load`): `hydrate(element, props)` attaches signals and event listeners to the existing DOM without re-rendering.
|
|
141
|
+
- **Mount** (`client:only`): `mount(element, props)` builds the DOM from scratch on the client.
|
|
142
|
+
- **Reactivity**: Powered by [`mizchi/signals`](https://mooncakes.io/docs/#/mizchi/signals/).
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
package/bin/astrobit.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
3
|
+
import { platform } from "node:os";
|
|
4
|
+
|
|
5
|
+
const [, , command, ...args] = process.argv;
|
|
6
|
+
|
|
7
|
+
function run(cmd, opts = {}) {
|
|
8
|
+
const result = spawnSync(cmd, { shell: true, stdio: "inherit", ...opts });
|
|
9
|
+
if (result.status !== 0) process.exit(result.status ?? 1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function hasMoon() {
|
|
13
|
+
const result = spawnSync("moon --version", { shell: true, stdio: "pipe" });
|
|
14
|
+
return result.status === 0;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function installMoon() {
|
|
18
|
+
if (platform() === "win32") {
|
|
19
|
+
console.error(
|
|
20
|
+
"[astrobit] moon is not installed. Please install it manually: https://www.moonbitlang.com/download"
|
|
21
|
+
);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
console.log("[astrobit] moon not found, installing...");
|
|
25
|
+
run("curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash");
|
|
26
|
+
// Add moon to PATH for subsequent commands in this process
|
|
27
|
+
process.env.PATH = `${process.env.HOME}/.moon/bin:${process.env.PATH}`;
|
|
28
|
+
try {
|
|
29
|
+
const version = execSync("moon --version", { env: process.env })
|
|
30
|
+
.toString()
|
|
31
|
+
.trim();
|
|
32
|
+
console.log(`[astrobit] moon installed: ${version}`);
|
|
33
|
+
} catch {
|
|
34
|
+
// ignore version display failure
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (command === "build") {
|
|
39
|
+
if (!hasMoon()) {
|
|
40
|
+
installMoon();
|
|
41
|
+
} else {
|
|
42
|
+
try {
|
|
43
|
+
const version = execSync("moon --version").toString().trim();
|
|
44
|
+
console.log(`[astrobit] moon already available: ${version}`);
|
|
45
|
+
} catch {
|
|
46
|
+
// ignore
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
console.log("[astrobit] running moon build...");
|
|
51
|
+
run("moon build");
|
|
52
|
+
|
|
53
|
+
console.log("[astrobit] running astro build...");
|
|
54
|
+
run("astro build");
|
|
55
|
+
} else {
|
|
56
|
+
console.error(
|
|
57
|
+
`[astrobit] Unknown command: ${command ?? "(none)"}\n\nUsage:\n astrobit build`
|
|
58
|
+
);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astrobit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/integration.js",
|
|
6
6
|
"types": "./dist/integration.d.ts",
|
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
"types": "./env.d.ts"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"astrobit": "./bin/astrobit.js"
|
|
18
|
+
},
|
|
16
19
|
"files": [
|
|
17
20
|
"dist",
|
|
21
|
+
"bin",
|
|
18
22
|
"env.d.ts"
|
|
19
23
|
],
|
|
20
24
|
"scripts": {
|