アセットのERBファイルでのフルURL → マルチサイトの問題

新しい workbox サービスワーカーの実装では UrlHelper.absolute が使用されています。これはコンパイル済みアセットであるため、マルチサイト環境ではプライマリホストの完全なホスト名を含む完全な URL が保存されます。

https://github.com/discourse/discourse/blob/master/app/assets/javascripts/service-worker.js.erb#L3-L6

代わりに UrlHelper.local_cdn_url を使用するべきだと考えます。これにより、ホスト名を変更した後にアセットを再コンパイルする必要もなくなります。

「いいね!」 1

一般的には、Service Worker は CDN から配信すべきではないという認識が広まっています:

ああ、つまり importScripts で読み込むファイルのことですね?それぞれのサイトが異なる CDN URL を持つマルチサイトクラスターをお使いでしょうか?

「いいね!」 1

はい、その ERB ファイルの 3 行目と 6 行目の importScriptsmodulePathPrefix です。

しかし、私の意図を完全に理解されていないようです。問題は、マルチサイトクラスターで CDN が 存在しない 場所で発生しています。

UrlHelper.absoluteUrlHelper.local_cdn_url の両方は、CDN の有無に関わらず状況に対応できます。

absolute:

CDN なし: https://primarysite.ofmultisitecluster.com/javascripts/workbox/workbox-sw.js 悪 - プライマリサイト以外のすべてのサイトに対してリモートオリジンとなり、プライマリクラスターのホスト名を露出させる
CDN あり: //cdnurl/javascripts/workbox/workbox-sw.js

local_cdn_url:

CDN なし: /javascripts/workbox/workbox-sw.js 良 - 相対 URL
CDN あり: //cdnurl/javascripts/workbox/workbox-sw.js

したがって、後者が望ましいものです。

問題は、その2行(3行目と6行目)がサービスワーカーファイルそのものに関するものではないことです。

サービスワーカーはベースドメインから提供されます(CDNからは提供できないため)が、このサービスワーカーは実行時にスクリプトを遅延ロードします(この場合は workbox ライブラリファイルなど)。それらのスクリプトはCDNから提供可能です。

したがって、問題はあなたのマルチサイトクラスターにCDNが設定されていないため、このバグが露呈していることです。DISCOURSE_CDN が設定されている場合は、このバグは隠蔽されます。なぜ私たちの環境には影響しないのか知りたかっただけです。

「いいね!」 1

おっしゃる通りです。2 番目の投稿を編集して誤りを修正しました。
問題はサービスワーカーファイル自体ではなく、そのファイル内に存在します。

はい、まさにその時にバグが露呈します。

「いいね!」 3

確認させてください。私の診断は正しいでしょうか?これは修正されるバグでしょうか?私たちに何か必要なことはありますか?

「いいね!」 3

はい、修正が必要なバグのようです。今週中に対応します!

「いいね!」 3

ふむ、Meta コンソールで試してみました:

## 現在
[1] pry(main)> UrlHelper.absolute("/javascripts/workbox/workbox-sw.js")
=> "https://d3bpeqsaub0i6y.cloudfront.net/javascripts/workbox/workbox-sw.js"

### 提案される変更
[2] pry(main)> UrlHelper.local_cdn_url("/javascripts/workbox/workbox-sw.js")
=> "/javascripts/workbox/workbox-sw.js"

これらは互換性のある関数には見えません。

「いいね!」 3

おっしゃる通り、local_cdn_url はローカル URL を CDN URL に置き換えるものです。しかも、これはローカル URL ではなく相対 URL です。

なので、これらの UrlHelper の呼び出しの代わりに、以下で十分ではないでしょうか?

importScripts("<%= (Discourse.asset_host || '') + "/javascripts/workbox/workbox-sw.js" %>");

そして

modulePathPrefix: (Discourse.asset_host || '') + "/javascripts/workbox",

「いいね!」 1

UrlHelper.absolute の現在の実装を読むと:

CDN が nil の場合(あなたのケースに該当します)、Discourse.base_url_no_prefix とパラメータを連結して URL を構成しているようです。

つまり、問題は Discourse.base_url_no_prefix がマルチサイト環境で常に最初のホストを返していることでしょうか?

コードを調べてみます :eyes:

ここの変数名 current_hostname(288 行目)は、マルチサイト対応を強く示唆しています :thinking:

そして、

によると、実際に対応しているようです。今のところ行き詰まりですね…

他を探してみると、このルートはブラウザが激しくアクセスしてくるため、特別な処理が施されています。CDN に置くことが許されず、他者の問題にしてはいけません。この際、マルチサイト漏れに関するバグがあり、これは @sam によって 1 年前に修正されました:

あなたがこのマルチサイトクラスタを提供している方法が、2018 年初頭に私たちが遭遇していたような、漏れのある形でこのルートをキャッシュしている可能性はありませんか?

「いいね!」 2

いいえ、問題はアセットのプリコンパイル時にそれが行われてしまい、マルチサイト環境で問題となる点です。
したがって、解決策はアセットにホスト名を含めないことです(アセット CDN が設定されている場合を除きます。なぜなら、それはマルチサイトホスト間で常に共有されるためです)。

「いいね!」 1

@falco 2 つ前の投稿にある提案されたソリューションをご覧になりましたか?

はい、しかし私のテストでは CDN なしのサブフォルダはカバーされていません😭

おそらく以下を使用する必要があります:

"#{Discourse.asset_host}#{Discourse.base_prefix}/javascripts/workbox"
「いいね!」 1

サブフォルダについての良い指摘ですね。

でも…Discourse.asset_host は nil になる可能性がありますし、Discourse.base_prefix なんて聞いたことがありません。

どうでしょうか:

importScripts("<%= (Discourse.asset_host || GlobalSetting.relative_url_root) + "/javascripts/workbox/workbox-sw.js" %>");

modulePathPrefix: "<%= (Discourse.asset_host || GlobalSetting.relative_url_root) + "/javascripts/workbox" %>",

まさに、この場合それが望ましいのです:

irb(main):001:0> puts "a#{nil}bc"
abc

ああ、Discourse.base_path のことを言いたかったのです。
修正をコミットしましたので、ご確認ください。

「いいね!」 3

私たちのケースには良さそうです。ありがとうございます!

ただし念のため確認させてください。CDN 上のアセットをサブフォルダと組み合わせてどのように扱っているか明確ではありませんが、Discourse.asset_host を使用している場合、アセットホスト上のすべてのパスにサブフォルダのパスもプレフィックスとして付与しているのでしょうか?現在のコードはそのようになっています。
もしそれが実際に行われているのであれば、この段落は完全に無視してください :slight_smile:

「いいね!」 3

このサブフォルダとCDNの組み合わせは確かに多くの問題を引き起こしました。@featheredtoast がこれを整理する作業を行い、私たちはバケットやサブフォルダなど、奇妙な組み合わせでもアセット配信コードが正しく動作するように、多くの時間を費やしました。

おそらく大丈夫だと思います :smile: ですが、必要であればこの件を再オープンできます。

バグレポートありがとうございます!

「いいね!」 8

このトピックは 7 日後に自動的に閉鎖されました。新しい返信は許可されていません。