これについていくつか考えを述べます。
有料Discourse開発コースの作成
UdemyやCourseraのようなプラットフォームでDiscourse開発に関するコースを作成するというアイデアは興味深いです。しかし、Discourseチーム以外でDiscourse開発のコースを作成できる資格を持つ人はそれほど多くなく、コースの潜在的な受講者数もかなり少ないというのが主な問題点だと推測されます。とはいえ、Discourseのテーマやプラグイン開発に関する良いコースであれば、時間をかければ十分な受講者数を集め、コース作成の労力に見合うだけの価値を生み出すことができると確信しています。
また、Discourseのコースに料金を設定することが、このフォーラムの精神に反する可能性があるという問題も考えられます。これはあくまで推測ですが。
Discourse開発チュートリアル
多くのDiscourseプラグイン、テーマ、テーマコンポーネントの実装が非常にシンプルであるという観察は正しいと思います。他のプラットフォームの開発と同様に、問題は、各部分がどのように組み合わさっているのかを理解するという最初の障壁を乗り越えることです。Discourseチーム(または他の資格のある開発者)は、機能的なテーマ、テーマコンポーネント、およびプラグインを作成する全プロセスを案内するチュートリアルをいくつか書くことで、この点について支援できるでしょう。例えば、Discourse Placeholderテーマコンポーネントのようなものを作成するステップバイステップガイドです。
これには多大な時間投資が必要であることは理解しており、Discourseのビジネス目標と一致させる必要があります。
現在利用可能なリソース
少し検索すれば、このフォーラムにはDiscourse開発に関する良い情報がたくさんあります。Discourse GitHubリポジトリのコード例を見ることも、学習の良い方法です。
最近無視できないツールとしてGitHub Copilotがあります。開発環境を適切に構成すれば、Discourseのテーマやプラグインの開発方法を理解するのに役立ちます。Discourseテーマの開発については、私が発見した最良の方法は、ローカルのDiscourseインストールのルートディレクトリでテーマを開発することです(Discourse Theme CLIを使用)。このように構成することで、CopilotはDiscourseのコードベースに簡単にアクセスできます。(プラグイン開発については、pluginsフォルダはすでにルート/discourseディレクトリにあります。)(また、CopilotがIDEにロードしたDiscourseコードベースに実際にアクセスしているかどうかは、間違っている可能性もあります。いずれにしても、コアDiscourseコードを自身の参照用に利用できることは役立ちます。)
気を散らさないように、またCopilotを学習ツールとして活用することに集中するために、IDE(VS Code)のCopilotの補完機能をオフにし、チャット経由でのみCopilotと対話します。以下は、それが提供できる支援の例です。(shopify.jsは、Theme CLIによって私のテーマの/javascripts/discourse/api-initializers/ディレクトリに作成されたファイルです。)
Copilotとの会話
\u003escossar: shopify.jsのデフォルトエクスポートが何をしているのか説明してもらえますか?これは基本的に、discourse_theme gemでテーマが作成されたときにDiscourseによって提供される定型コードです。定型コードを変更して、ページ変更ごとにログを記録するようにしました。api.onPageChangeの呼び出しは理解していますが、apiオブジェクトがどのように私のコードに注入されているのか、明確には理解できていません。
\u003e GitHub Copilot: apiオブジェクトは、apiInitializerから返されるオブジェクトのinitializeメソッド内で呼び出されるwithPluginApi関数を通じてコードに注入されます。
\u003e 以下は、何が起こっているのかを簡略化したバージョンです。
\u003e 1. Discourseが起動すると、すべてのイニシャライザを実行します。
\u003e 2. apiInitializer関数は、"inject-objects"イニシャライザの後に実行されるイニシャライザを作成します。
\u003e 3. このイニシャライザが実行されると、version、cb、optsパラメータを渡してwithPluginApi関数を呼び出します。
\u003e 4. withPluginApi関数は、現在のDiscourseのバージョンが指定されたバージョンと互換性があるかどうかを確認します。互換性がある場合、コールバック関数(cb)を呼び出し、PluginApiインスタンスを引数として渡します。このPluginApiインスタンスが、コードで見られるapiオブジェクトです。
\u003e したがって、apiオブジェクトはPluginApiのインスタンスであり、withPluginApi関数によってコードに渡されています。このオブジェクトは、onPageChangeのように、Discourseと対話できる多くのメソッドを提供しています。
\u003escossar: では、shopify.jsのデフォルトエクスポートの2番目の引数である関数は、apiInitializerが受け入れるコールバック関数ということですか?
\u003eGitHub Copilot: はい、その通りです。apiInitializerの2番目の引数はコールバック関数です。この関数は、イニシャライザが実行されるときに(現在のDiscourseバージョンが指定されたバージョンと互換性がある場合)、PluginApiインスタンスを引数として呼び出されます。これが、apiオブジェクトがshopify.jsファイルで利用可能になる方法です。
それを理解した後…
\u003escossar: …もう一つ、api.decorateCookedを使って、外部アプリケーションでホストされているレーティングiframe(例えば、私が開発しているShopifyアプリでホストされているもの)を挿入できますか?
\u003e GitHub Copilot: はい、api.decorateCookedを使用して、投稿にiframeを挿入できます。以下にその方法の簡単な例を示します。
\u003e javascript \u003e api.decorateCooked($elem =\u003e { \u003e const postId = $elem.data('post-id'); \u003e const iframe = document.createElement('iframe'); \u003e iframe.src = `https://your-app.com/ratings?post_id=${postId}`; \u003e iframe.width = '100%'; \u003e iframe.height = '200'; // 必要に応じて調整 \u003e $elem.append(iframe); \u003e }, { id: 'rating-iframe' }); \u003e
\u003e この例では、api.decorateCookedを使用して、各投稿にiframeを追加しています。iframeのソースは、投稿IDをクエリパラメータとして含めて、外部アプリケーションのURLに設定されています。'https://your-app.com/ratings'をレーティングページの実際のURLに置き換える必要があります。
\u003e これは単純化された例であることに注意してください。必要に応じて調整する必要がある場合があり、正しく安全に機能するように、エラー処理やその他の必要な予防措置を追加する必要があるでしょう。
現時点では、Copilotにすべてのコードを実際に書くことを期待するのは合理的ではありませんが、Discourseコードの書き方を学ぶための優れたツールです。