wandsをブラウザで実行する環境を作る - @ledsun blog の続きです。 前回 wands gem をブラウザで読み込む環境を作りました。 前回の書き方では、RubyスクリプトをJavaScriptの中に書いてます。 エディタの支援が受けられず少し不便です。
ruby.wasmから「Rubyスクリプトをscriptタグから読み込む機能」を持ってきます。 https://github.com/ruby/ruby.wasm/blob/8be5074c626691d08ccc994a6f683246db51f3c3/packages/npm-packages/ruby-wasm-wasi/src/browser.script.ts#L41 にあります。 この機能は私が作ったので、どこにあるのかも知っています。 この関数をもとに「Rubyスクリプトをscriptタグから読み込むJavaScript」を作ります。
// Copy from https://github.com/ruby/ruby.wasm/blob/8be5074c626691d08ccc994a6f683246db51f3c3/packages/npm-packages/ruby-wasm-wasi/src/browser.script.ts#L41 const mainWithRubyVM = async (vm) => { vm.printVersion(); globalThis.rubyVM = vm; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", () => runRubyScriptsInHtml(vm) ); } else { runRubyScriptsInHtml(vm); } }; const runRubyScriptsInHtml = async (vm) => { const tags = document.querySelectorAll('script[type="text/ruby"]'); const promisingRubyScripts = Array.from(tags).map((tag) => loadScriptAsync(tag) ); for await (const script of promisingRubyScripts) { if (script) { const { scriptContent, evalStyle } = script; switch (evalStyle) { case "async": vm.evalAsync(scriptContent); break; case "sync": vm.eval(scriptContent); break; } } } }; const deriveEvalStyle = (tag) => { const rawEvalStyle = tag.getAttribute("data-eval") || "sync"; if (rawEvalStyle !== "async" && rawEvalStyle !== "sync") { console.warn( `data-eval attribute of script tag must be "async" or "sync". ${rawEvalStyle} is ignored and "sync" is used instead.` ); return "sync"; } return rawEvalStyle; }; const loadScriptAsync = async (tag) => { const evalStyle = deriveEvalStyle(tag); if (tag.hasAttribute("src")) { const url = tag.getAttribute("src"); const response = await fetch(url); if (response.ok) { return { scriptContent: await response.text(), evalStyle }; } return null; } return { scriptContent: tag.innerHTML, evalStyle }; }; import { DefaultRubyVM } from "https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.1/dist/browser/+esm"; const response = await fetch("/dist/ruby.wasm"); const module = await WebAssembly.compileStreaming(response); const { vm } = await DefaultRubyVM(module); await mainWithRubyVM(vm);
require "wands"
それぞれを読み込むHTMLファイルです。
<html> <body> <script type="module" src="dist/load_ruby_script.js"></script> <script type="text/ruby" data-eval="sync" src="dist/app.rb"></script> </body> </html>
これで前回と同じようにwandsを読み込んでエラーが起きるようになりました。
vm.js:739 Uncaught (in promise) J: <internal:/usr/local/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:136:in `require': cannot load such file -- socket (LoadError) <internal:/usr/local/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:136:in `require' /bundle/gems/wands-0.6.1/lib/wands/web_socket.rb:3:in `<top (required)>' /bundle/gems/wands-0.6.1/lib/wands.rb:4:in `require_relative' /bundle/gems/wands-0.6.1/lib/wands.rb:4:in `<top (required)>' <internal:/usr/local/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:136:in `require' <internal:/usr/local/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:136:in `require' eval:1:in `<main>' -e:in `eval' at j (https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.1/dist/browser/+esm:7:23748) at https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.1/dist/browser/+esm:7:24383 at x (https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.1/dist/browser/+esm:7:23866) at S (https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.1/dist/browser/+esm:7:24319) at w.eval (https://cdn.jsdelivr.net/npm/@ruby/wasm-wasi@2.7.1/dist/browser/+esm:7:20663) at runRubyScriptsInHtml (http://localhost:8000/dist/load_ruby_script.js:31:14)
あとはwandsが動くように直して行きます。