Skip to content

Commit a1bcd64

Browse files
committed
Add browser data-env support
1 parent ef0300a commit a1bcd64

6 files changed

Lines changed: 111 additions & 2 deletions

File tree

docs/cheat_sheet.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ The easiest way to run Ruby on browser is to use `browser.script.iife.js` script
4646
</html>
4747
```
4848

49+
Use `data-env` on the `browser.script.iife.js` script tag to pass environment variables when the Ruby VM starts:
50+
51+
```html
52+
<script
53+
src="https://cdn.jsdelivr.net/npm/@ruby/4.0-wasm-wasi@2.9.4/dist/browser.script.iife.js"
54+
data-env="RUBY_BOX=1 RUBY_FIBER_MACHINE_STACK_SIZE=1048576"
55+
></script>
56+
```
57+
4958
If you want to control Ruby VM from JavaScript, you can use `@ruby/wasm-wasi` package API:
5059

5160
```html

packages/npm-packages/ruby-wasm-wasi/example/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This is a simple example of how to use the `ruby-wasm-wasi` family packages
88
$ ruby -run -e httpd . -p 8000
99
$ # Open http://localhost:8000/hello.html
1010
$ # Open http://localhost:8000/lucky.html
11+
$ # Open http://localhost:8000/ruby-box.html
1112
$ # Open http://localhost:8000/script-src
1213
```
1314

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<html>
2+
<script
3+
src="https://cdn.jsdelivr.net/npm/@ruby/head-wasm-wasi@2.9.4/dist/browser.script.iife.js"
4+
data-env="RUBY_BOX=1"
5+
></script>
6+
<div id="result">
7+
<div id="enabled"></div>
8+
<div id="constant"></div>
9+
</div>
10+
<script type="text/ruby">
11+
require "js"
12+
13+
box = Ruby::Box.new
14+
box.eval <<~RUBY
15+
X = 123
16+
RUBY
17+
18+
document = JS.global[:document]
19+
document.getElementById("enabled")[:innerText] = "Ruby::Box.enabled?: #{Ruby::Box.enabled?}"
20+
document.getElementById("constant")[:innerText] = "box::X: #{box::X}"
21+
</script>
22+
</html>

packages/npm-packages/ruby-wasm-wasi/src/browser.script.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,18 @@ export const main = async (
88
pkg: { name: string; version: string },
99
options?: Parameters<typeof DefaultRubyVM>[1],
1010
) => {
11+
const scriptEnv = deriveEnv(document.currentScript);
1112
const response = fetch(
1213
`https://cdn.jsdelivr.net/npm/${pkg.name}@${pkg.version}/dist/ruby+stdlib.wasm`,
1314
);
1415
const module = await compileWebAssemblyModule(response);
15-
const { vm } = await DefaultRubyVM(module, options);
16+
const { vm } = await DefaultRubyVM(module, {
17+
...options,
18+
env: {
19+
...scriptEnv,
20+
...options?.env,
21+
},
22+
});
1623
await mainWithRubyVM(vm);
1724
};
1825

@@ -90,6 +97,34 @@ const deriveEvalStyle = (tag: Element): "async" | "sync" => {
9097
return rawEvalStyle;
9198
};
9299

100+
const deriveEnv = (tag: Element | null): Record<string, string> => {
101+
const rawEnv = tag?.getAttribute("data-env");
102+
if (!rawEnv) {
103+
return {};
104+
}
105+
106+
const trimmedEnv = rawEnv.trim();
107+
if (!trimmedEnv) {
108+
return {};
109+
}
110+
111+
return trimmedEnv
112+
.split(/\s+/)
113+
.reduce<Record<string, string>>((env, entry) => {
114+
const delimiterIndex = entry.indexOf("=");
115+
if (delimiterIndex <= 0) {
116+
console.warn(
117+
`data-env entry must be in the KEY=value format. ${entry} is ignored.`,
118+
);
119+
return env;
120+
}
121+
122+
// Only the first "=" separates key and value so values can contain "=".
123+
env[entry.slice(0, delimiterIndex)] = entry.slice(delimiterIndex + 1);
124+
return env;
125+
}, {});
126+
};
127+
93128
const loadScriptAsync = async (
94129
tag: Element,
95130
): Promise<{ scriptContent: string; evalStyle: "async" | "sync" } | null> => {

packages/npm-packages/ruby-wasm-wasi/test-e2e/examples/examples.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ test("lucky.html is healthy", async ({ page }) => {
5555
expect(result).toMatch(/(Lucky|Unlucky)/);
5656
});
5757

58+
test("ruby-box.html is healthy", async ({ page }) => {
59+
await page.goto("/ruby-box.html");
60+
await waitForRubyVM(page);
61+
await expect(page.locator("#enabled")).toHaveText("Ruby::Box.enabled?: true");
62+
await expect(page.locator("#constant")).toHaveText("box::X: 123");
63+
});
64+
5865
test("script-src/index.html is healthy", async ({ page }) => {
5966
const messages: string[] = [];
6067
page.on("console", (msg) => messages.push(msg.text()));
@@ -80,7 +87,7 @@ if (process.env.RUBY_NPM_PACKAGE_ROOT) {
8087
await page.goto("/require_relative/index.html");
8188

8289
await waitForRubyVM(page);
83-
while (!messages.some((msg) => /Hello, world\!/.test(msg))) {
90+
while (!messages.some((msg) => /Hello, world\!/.test(msg))) {
8491
await page.waitForEvent("console");
8592
}
8693
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { test, expect } from "@playwright/test";
2+
3+
import {
4+
setupDebugLog,
5+
setupProxy,
6+
setupUncaughtExceptionRejection,
7+
resolveBinding,
8+
} from "../support";
9+
10+
if (!process.env.RUBY_NPM_PACKAGE_ROOT) {
11+
test.skip("skip", () => {});
12+
} else {
13+
test.beforeEach(async ({ context, page }) => {
14+
setupDebugLog(context);
15+
setupProxy(context);
16+
setupUncaughtExceptionRejection(page);
17+
});
18+
19+
test.describe("data-env", () => {
20+
test("passes environment variables to the Ruby VM", async ({ page }) => {
21+
const resolve = await resolveBinding(page, "checkResolved");
22+
await page.setContent(`
23+
<script
24+
src="https://cdn.jsdelivr.net/npm/@ruby/head-wasm-wasi@latest/dist/browser.script.iife.js"
25+
data-env="RUBY_WASM_TEST=ok RUBY_WASM_TEST_EQUALS=a=b"
26+
></script>
27+
<script type="text/ruby" data-eval="async">
28+
require "js"
29+
JS.global.checkResolved [ENV["RUBY_WASM_TEST"], ENV["RUBY_WASM_TEST_EQUALS"]].join(",")
30+
</script>
31+
`);
32+
expect(await resolve()).toBe("ok,a=b");
33+
});
34+
});
35+
}

0 commit comments

Comments
 (0)