|
1 | 1 | # @ruby/3.2-wasm-wasi
|
2 | 2 |
|
3 |
| -WebAssembly port of CRuby with WASI. |
| 3 | +[](https://www.npmjs.com/package/@ruby/3.2-wasm-wasi) |
4 | 4 |
|
5 |
| -This package distributes the CRuby 3.2. |
| 5 | +This package provides WebAssembly binaries of CRuby built from the Ruby 3.2 source code targeting WASI-compatible environments. |
6 | 6 |
|
7 |
| -## Installation |
8 |
| - |
9 |
| -For installing `@ruby/3.2-wasm-wasi` family, just run this command in your shell: |
10 |
| - |
11 |
| -```console |
12 |
| -$ npm install --save @ruby/3.2-wasm-wasi@latest |
13 |
| -# or if you want the nightly snapshot |
14 |
| -$ npm install --save @ruby/3.2-wasm-wasi@next |
15 |
| -# or you can specify the exact snapshot version |
16 |
| -$ npm install --save @ruby/[email protected] |
17 |
| -``` |
18 |
| - |
19 |
| -## Quick Start (for Node.js) |
20 |
| - |
21 |
| -See [the example project](https://github.com/ruby/ruby.wasm/tree/main/packages/npm-packages/ruby-wasm-wasi/example) for more details. |
22 |
| - |
23 |
| -```javascript |
24 |
| -import fs from "fs/promises"; |
25 |
| -import { DefaultRubyVM } from "@ruby/wasm-wasi/dist/node.cjs.js"; |
26 |
| - |
27 |
| -const main = async () => { |
28 |
| - const binary = await fs.readFile( |
29 |
| - // Tips: Replace the binary with debug info if you want symbolicated stack trace. |
30 |
| - // (only nightly release for now) |
31 |
| - // "./node_modules/@ruby/3.2-wasm-wasi/dist/ruby.debug+stdlib.wasm" |
32 |
| - "./node_modules/@ruby/3.2-wasm-wasi/dist/ruby.wasm" |
33 |
| - ); |
34 |
| - const module = await WebAssembly.compile(binary); |
35 |
| - const { vm } = await DefaultRubyVM(module); |
36 |
| - |
37 |
| - vm.eval(` |
38 |
| - luckiness = ["Lucky", "Unlucky"].sample |
39 |
| - puts "You are #{luckiness}" |
40 |
| - `); |
41 |
| -}; |
42 |
| - |
43 |
| -main(); |
44 |
| -``` |
45 |
| - |
46 |
| -Then you can run the example project in your terminal: |
47 |
| - |
48 |
| -```console |
49 |
| -$ node --experimental-wasi-unstable-preview1 index.node.js |
50 |
| -``` |
51 |
| - |
52 |
| -## Quick Start (for Browser) |
53 |
| - |
54 |
| -In browser, you need a WASI polyfill. See [the example project](https://github.com/ruby/ruby.wasm/tree/main/packages/npm-packages/ruby-wasm-wasi/example) for more details. |
55 |
| - |
56 |
| -```html |
57 |
| -<html> |
58 |
| - <script src="https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@latest/dist/browser.umd.js"></script> |
59 |
| - <script> |
60 |
| - const { DefaultRubyVM } = window["ruby-wasm-wasi"]; |
61 |
| - const main = async () => { |
62 |
| - // Fetch and instantiate WebAssembly binary |
63 |
| - const response = await fetch( |
64 |
| - // Tips: Replace the binary with debug info if you want symbolicated stack trace. |
65 |
| - // (only nightly release for now) |
66 |
| - // "https://cdn.jsdelivr.net/npm/@ruby/3.2-wasm-wasi@next/dist/ruby.debug+stdlib.wasm" |
67 |
| - "https://cdn.jsdelivr.net/npm/@ruby/3.2-wasm-wasi@latest/dist/ruby.wasm" |
68 |
| - ); |
69 |
| - const buffer = await response.arrayBuffer(); |
70 |
| - const module = await WebAssembly.compile(buffer); |
71 |
| - const { vm } = await DefaultRubyVM(module); |
72 |
| -
|
73 |
| - vm.printVersion(); |
74 |
| - vm.eval(` |
75 |
| - require "js" |
76 |
| - luckiness = ["Lucky", "Unlucky"].sample |
77 |
| - JS::eval("document.body.innerText = '#{luckiness}'") |
78 |
| - `); |
79 |
| - }; |
80 |
| -
|
81 |
| - main(); |
82 |
| - </script> |
83 |
| - <body></body> |
84 |
| -</html> |
85 |
| -``` |
86 |
| - |
87 |
| -## GC limitation with JavaScript interoperability |
88 |
| - |
89 |
| -Since JavaScript's GC system and Ruby's GC system are separated and not cooperative, they cannot collect cyclic references between JavaScript and Ruby objects. |
90 |
| - |
91 |
| -The following code will cause a memory leak: |
92 |
| - |
93 |
| -```javascript |
94 |
| -class JNode { |
95 |
| - setRNode(rnode) { |
96 |
| - this.rnode = rnode; |
97 |
| - } |
98 |
| -} |
99 |
| -jnode = new JNode(); |
100 |
| - |
101 |
| -rnode = vm.eval(` |
102 |
| -class RNode |
103 |
| - def set_jnode(jnode) |
104 |
| - @jnode = jnode |
105 |
| - end |
106 |
| -end |
107 |
| -RNode.new |
108 |
| -`); |
109 |
| - |
110 |
| -rnode.call("set_jnode", vm.wrap(jnode)); |
111 |
| -jnode.setRNode(rnode); |
112 |
| -``` |
113 |
| - |
114 |
| -<!-- The APIs section was generated by `npx documentation readme ../ruby-wasm-wasi/dist/index.esm.js --section=APIs` --> |
115 |
| - |
116 |
| -## APIs |
117 |
| - |
118 |
| -<!-- Generated by documentation.js. Update this documentation by updating the source code. --> |
119 |
| - |
120 |
| -#### Table of Contents |
121 |
| - |
122 |
| -- [RubyVM](#rubyvm) |
123 |
| - - [Examples](#examples) |
124 |
| - - [initialize](#initialize) |
125 |
| - - [Parameters](#parameters) |
126 |
| - - [setInstance](#setinstance) |
127 |
| - - [Parameters](#parameters-1) |
128 |
| - - [addToImports](#addtoimports) |
129 |
| - - [Parameters](#parameters-2) |
130 |
| - - [printVersion](#printversion) |
131 |
| - - [eval](#eval) |
132 |
| - - [Parameters](#parameters-3) |
133 |
| - - [Examples](#examples-1) |
134 |
| - - [evalAsync](#evalasync) |
135 |
| - - [Parameters](#parameters-4) |
136 |
| - - [Examples](#examples-2) |
137 |
| - - [wrap](#wrap) |
138 |
| - - [Parameters](#parameters-5) |
139 |
| - - [Examples](#examples-3) |
140 |
| -- [RbValue](#rbvalue) |
141 |
| - - [call](#call) |
142 |
| - - [Parameters](#parameters-6) |
143 |
| - - [Examples](#examples-4) |
144 |
| - - [toPrimitive](#toprimitive) |
145 |
| - - [Parameters](#parameters-7) |
146 |
| - - [toString](#tostring) |
147 |
| - - [toJS](#tojs) |
148 |
| -- [RbError](#rberror) |
149 |
| - |
150 |
| -### RubyVM |
151 |
| - |
152 |
| -A Ruby VM instance |
153 |
| - |
154 |
| -#### Examples |
155 |
| - |
156 |
| -```javascript |
157 |
| -const wasi = new WASI(); |
158 |
| -const vm = new RubyVM(); |
159 |
| -const imports = { |
160 |
| - wasi_snapshot_preview1: wasi.wasiImport, |
161 |
| -}; |
162 |
| - |
163 |
| -vm.addToImports(imports); |
164 |
| - |
165 |
| -const instance = await WebAssembly.instantiate(rubyModule, imports); |
166 |
| -await vm.setInstance(instance); |
167 |
| -wasi.initialize(instance); |
168 |
| -vm.initialize(); |
169 |
| -``` |
170 |
| - |
171 |
| -#### initialize |
172 |
| - |
173 |
| -Initialize the Ruby VM with the given command line arguments |
174 |
| - |
175 |
| -##### Parameters |
176 |
| - |
177 |
| -- `args` The command line arguments to pass to Ruby. Must be |
178 |
| - an array of strings starting with the Ruby program name. (optional, default `["ruby.wasm","--disable-gems","-e_=0"]`) |
179 |
| - |
180 |
| -#### setInstance |
181 |
| - |
182 |
| -Set a given instance to interact JavaScript and Ruby's |
183 |
| -WebAssembly instance. This method must be called before calling |
184 |
| -Ruby API. |
185 |
| - |
186 |
| -##### Parameters |
187 |
| - |
188 |
| -- `instance` The WebAssembly instance to interact with. Must |
189 |
| - be instantiated from a Ruby built with JS extension, and built |
190 |
| - with Reactor ABI instead of command line. |
191 |
| - |
192 |
| -#### addToImports |
193 |
| - |
194 |
| -Add intrinsic import entries, which is necessary to interact JavaScript |
195 |
| -and Ruby's WebAssembly instance. |
196 |
| - |
197 |
| -##### Parameters |
198 |
| - |
199 |
| -- `imports` The import object to add to the WebAssembly instance |
200 |
| - |
201 |
| -#### printVersion |
202 |
| - |
203 |
| -Print the Ruby version to stdout |
204 |
| - |
205 |
| -#### eval |
206 |
| - |
207 |
| -Runs a string of Ruby code from JavaScript |
208 |
| - |
209 |
| -##### Parameters |
210 |
| - |
211 |
| -- `code` The Ruby code to run |
212 |
| - |
213 |
| -##### Examples |
214 |
| - |
215 |
| -```javascript |
216 |
| -vm.eval("puts 'hello world'"); |
217 |
| -const result = vm.eval("1 + 2"); |
218 |
| -console.log(result.toString()); // 3 |
219 |
| -``` |
220 |
| - |
221 |
| -Returns **any** the result of the last expression |
222 |
| - |
223 |
| -#### evalAsync |
224 |
| - |
225 |
| -Runs a string of Ruby code with top-level `JS::Object#await` |
226 |
| -Returns a promise that resolves when execution completes. |
227 |
| - |
228 |
| -##### Parameters |
229 |
| - |
230 |
| -- `code` The Ruby code to run |
231 |
| - |
232 |
| -##### Examples |
233 |
| - |
234 |
| -```javascript |
235 |
| -const text = await vm.evalAsync(` |
236 |
| - require 'js' |
237 |
| - response = JS.global.fetch('https://example.com').await |
238 |
| - response.text.await |
239 |
| -`); |
240 |
| -console.log(text.toString()); // <html>...</html> |
241 |
| -``` |
242 |
| - |
243 |
| -Returns **any** a promise that resolves to the result of the last expression |
244 |
| - |
245 |
| -#### wrap |
246 |
| - |
247 |
| -Wrap a JavaScript value into a Ruby JS::Object |
248 |
| - |
249 |
| -##### Parameters |
250 |
| - |
251 |
| -- `value` The value to convert to RbValue |
252 |
| - |
253 |
| -##### Examples |
254 |
| - |
255 |
| -```javascript |
256 |
| -const hash = vm.eval(`Hash.new`); |
257 |
| -hash.call("store", vm.eval(`"key1"`), vm.wrap(new Object())); |
258 |
| -``` |
259 |
| - |
260 |
| -Returns **any** the RbValue object representing the given JS value |
261 |
| - |
262 |
| -### RbValue |
263 |
| - |
264 |
| -A RbValue is an object that represents a value in Ruby |
265 |
| - |
266 |
| -#### call |
267 |
| - |
268 |
| -Call a given method with given arguments |
269 |
| - |
270 |
| -##### Parameters |
271 |
| - |
272 |
| -- `callee` name of the Ruby method to call |
273 |
| -- `args` **...any** arguments to pass to the method. Must be an array of RbValue |
274 |
| - |
275 |
| -##### Examples |
276 |
| - |
277 |
| -```javascript |
278 |
| -const ary = vm.eval("[1, 2, 3]"); |
279 |
| -ary.call("push", 4); |
280 |
| -console.log(ary.call("sample").toString()); |
281 |
| -``` |
282 |
| - |
283 |
| -#### toPrimitive |
284 |
| - |
285 |
| -- **See**: <https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive> |
286 |
| - |
287 |
| -##### Parameters |
288 |
| - |
289 |
| -- `hint` Preferred type of the result primitive value. `"number"`, `"string"`, or `"default"`. |
290 |
| - |
291 |
| -#### toString |
292 |
| - |
293 |
| -Returns a string representation of the value by calling `to_s` |
294 |
| - |
295 |
| -#### toJS |
296 |
| - |
297 |
| -Returns a JavaScript object representation of the value |
298 |
| -by calling `to_js`. |
299 |
| - |
300 |
| -Returns null if the value is not convertible to a JavaScript object. |
301 |
| - |
302 |
| -### RbError |
303 |
| - |
304 |
| -**Extends Error** |
305 |
| - |
306 |
| -Error class thrown by Ruby execution |
307 |
| - |
308 |
| -## Building the package from source |
309 |
| - |
310 |
| -The instructions for building a Ruby targeting WebAssembly are available [here](https://github.com/ruby/ruby.wasm#building-from-source). |
311 |
| - |
312 |
| -Then, you can run the following command in your shell: |
313 |
| - |
314 |
| -```console |
315 |
| -# Check the directory structure of your Ruby build |
316 |
| -$ tree -L 3 path/to/wasm32-unknown-wasi-full-js/ |
317 |
| -path/to/wasm32-unknown-wasi-full-js/ |
318 |
| -├── usr |
319 |
| -│ └── local |
320 |
| -│ ├── bin |
321 |
| -│ ├── include |
322 |
| -│ ├── lib |
323 |
| -│ └── share |
324 |
| -└── var |
325 |
| - └── lib |
326 |
| - └── gems |
327 |
| -$ ./build-package.sh path/to/wasm32-unknown-wasi-full-js/ |
328 |
| -Generating "/Users/katei/.ghq/github.com/ruby/ruby.wasm/packages/ruby-3.2-wasm-wasi/src/bindgen/intrinsics.js" |
329 |
| -Generating "/Users/katei/.ghq/github.com/ruby/ruby.wasm/packages/ruby-3.2-wasm-wasi/src/bindgen/rb-abi-guest.d.ts" |
330 |
| -Generating "/Users/katei/.ghq/github.com/ruby/ruby.wasm/packages/ruby-3.2-wasm-wasi/src/bindgen/rb-abi-guest.js" |
331 |
| -Generating "/Users/katei/.ghq/github.com/ruby/ruby.wasm/packages/ruby-3.2-wasm-wasi/src/bindgen/rb-js-abi-host.d.ts" |
332 |
| -Generating "/Users/katei/.ghq/github.com/ruby/ruby.wasm/packages/ruby-3.2-wasm-wasi/src/bindgen/rb-js-abi-host.js" |
333 |
| - |
334 |
| -src/index.ts → dist/index.umd.js, dist/index.esm.js, dist/index.cjs.js... |
335 |
| -created dist/index.umd.js, dist/index.esm.js, dist/index.cjs.js in 682ms |
336 |
| -``` |
| 7 | +See [`@ruby/wasm-wasi`](https://github.com/ruby/ruby.wasm/blob/main/packages/npm-packages/ruby-wasm-wasi/README.md) for how to use this package. |
0 commit comments