ruby.wasmでrequire_relativeしたときのリダイレクトレスポンスの扱い方 - @ledsun blog に書いたように、HTTPリクエストのリダイレクトレスポンスでURLが変わったら、変更後のURLをロード済みとして扱いたいです。
リダイレクトレスポンス対応版 require_relativeの実装
ruby.wasmのrequire_relativeではfetch APIを使います。 fetch APIからリダイレクト後のURLがとれば良いはずです。
Response.url - Web API | MDN には
url プロパティの値は、あらゆるリダイレクトの後に得られる最終的な URL になります。
と、あります。 これを使えば良さそうです。 次のようなコードを書きました。
response = JS.global.fetch(location.url).await if response[:status].to_i == 200 return false if @loaded_urls.include?(response[:url].to_s) code = response.text().await.to_s eval_code(code, location) @loaded_urls << response[:url].to_s true else raise LoadError.new "cannot load such url -- #{location.url}" end
@loaded_urls
に response.url
から取得したURLを保存しておきます。
次のfetchの response.url
が、@loaded_urls
に含まれていたら、Rubyスクリプトを実行せずにリターンします。
これで良さそうに思います。
実際に動かしてみる
しかし、E2Eテストでは失敗します。 失敗した結果 ruby.wasmのE2Eテストをデバッグする - @ledsun blog をしていました。 また、Response.urlの挙動を確認する - @ledsun blog で、Response.url単体では期待通りに動くことが確認できました。 ということは、ruby.wasmに組み込んでも期待通りに動きそうです。 確かめてみましょう。
次のようなサーバーを用意します。
require 'webrick' root = File.expand_path 'public' # 静的ファイルが置かれるディレクトリ server = WEBrick::HTTPServer.new :Port => 3000, :DocumentRoot => root # リダイレクトの設定 server.mount_proc '/redirect.rb' do |req, res| res.status = 302 res['Location'] = 'app.rb' end trap 'INT' do server.shutdown end server.start
このサーバーはpublicディレクトリにあるファイルを静的配信します。
さらに /redirect.rb
にきたリクエストにはリダイレクトレスポンスを返し app.rb
に誘導します。
publicディレクトリに、自分でビルドしたruby.wasmを実行する環境をつくる - @ledsun blogの要領で、browser.script.iife.js
とruby+stdlib.wsm
を用意します。
require_relativeの動作確認する - @ledsun blog の要領でrequire_relative
を使うindex.htmlを用意します。
<html> <script src="browser.script.iife.js"></script> <script type="text/ruby"> require 'js/require_remote' module Kernel alias original_require_relative require_relative # The require_relative may be used in the embedded Gem. # First try to load from the built-in filesystem, and if that fails, # load from the URL. def require_relative(path) caller_path = caller_locations(1, 1).first.absolute_path || '' dir = File.dirname(caller_path) file = File.absolute_path(path, dir) original_require_relative(file) rescue LoadError JS::RequireRemote.instance.load(path) end end </script> <script type="text/ruby" data-eval="async"> p require_relative 'redirect' p require_relative 'app' </script> </html>
ただし次のようにリダイレクトを交えたrequire_relativeを実行します。
p require_relative 'redirect' p require_relative 'app'
リダイレクト後の app.rb
がロード済みになっているはずです。
その後 app.rb
をロードしようとしてもスキップされて欲しいです。
つまり、開発コンソールに、最初にtrue
つぎにfalse
が表示されてほしいです。
サーバーを起動して動作を確認します。
ruby sever.rb
http://localhost:3000/ を開いて開発コンソールを確認します。
期待通りです。
最初にtrue
つぎにfalse
が表示されました。
まとめ
わかったことをまとめます。
- response.urlはfetchを単体で動かしたときリダイレクト後のURLが取得できる
- response.urlをruby.wasm版 require_relative に組み込むと、期待通りに動く
- E2Eでは期待通りに動かない
- 特にresponse.urlの値がリダイレクト前のまま
以上から、今後はE2Eテストの実行環境を重点的にしらべていくと良さそうです。