はじめに
今までSalesforce Platform上でしかほぼ開発経験がなかったのですが、それなりに大きな案件となると、Salesforceだけで完結せずに外部のシステムと連携するパターンが多いと思うので、Node.js + Lightning Web Runtime(LWR)でWebアプリを開発してみました。一般的なWebアプリ開発知識が不足しているせいか、めちゃくちゃ初歩的な部分でいくつか躓いたので、それらをまとめたいと思います。
目次
1. 想定する読者
2. 執筆者のバックグラウンド
3. 使用したテクノロジー
4. 作成したアプリのデモ動画
5. npmが分からない
6. サーバーを起動するという概念が分からない
7. アプリケーションという単位が分からない
8. JSforceはとても簡単だった!
想定する読者
- 今までSalesforce Platform上でのみ開発をしてきたが、そろそろSalesforce一本足打法を脱却したいと考えているSalesforceエンジニア
- Salesforce開発経験しかないエンジニアをメンバーに持っているテックリードやマネージャー
- 単純に読み物として楽しみたい方
執筆者のバックグラウンド
- 非情報系出身
- Salesforceを触りだして4年だが、現場のエンジニア経験は1年半
- インフラ周りの知識が弱め
使用したテクノロジー
LWR, Node.js (Express), JSforce, Heroku等
作成したアプリのデモ動画
記事の内容には直接関係ないですが、興味ある人はどうぞ
npmが分からない
まず最初につまずいたのは、Node.jsのパッケージ管理の仕組みであるnpmです。Salesforce開発でも似たようなものとして、LWC上で必要なライブラリをimportするという作業がありますが、その場合は特にターミナルからコマンドを叩く必要はなくて、必要なものをJSファイル上で宣言すれば終わりです。一方で、npmパッケージの場合は、パッケージの使用をファイル上で宣言するだけでなく、 npm install
コマンドを叩いてインストールする必要があります。 しかも、別のレポジトリで同じパッケージを使おうと思ったら、基本的に再度インストールが必要になります。普段インターネットからダウンロードしたアプリをインストールする場合などは、一度インストールしたら再インストールの必要はないので、最初は少し戸惑いました。必要そうなものをどんどんインストールしてしまうと、依存関係が複雑になってしまうのも困りました。
またネット上のドキュメントや記事の中では、npmパッケージが特に明言されずに使われていることも多くあって、初学者としてはどこまでが、ピュアなNode.jsの機能なのかがいまいち分からずに苦労しました。
具体例としては、以下のようにSalesforceへの認証情報を.envファイルから参照しようとしたのですが、うまく参照できないという問題が発生しました。これには dotenv というnpmパッケージのインストールが必要なことに気づくのに時間がかかりました。
const SF_USERNAME = process.env.SF_USERNAME;
const SF_PASSWORD = process.env.SF_PASSWORD;
const SF_TOKEN = process.env.SF_TOKEN;
const SF_LOGIN_URL = process.env.SF_LOGIN_URL;
サーバーを起動するという概念が分からない
Salesforce上で開発をしていると、サーバーを起動するという作業をすることがありません。Salesforceは常にクラウド上で動いているので、開発用のDeveloper Edition組織やスクラッチ組織を一度作成してしまえば、そこにコードをデプロイするだけで作ったアプリは動くようになります。
しかし、Node.jsを使ってWebアプリを開発する場合は、サーバーを起動する必要があります。操作としてはnode index.js
というようなコマンドを打つだけなので簡単なのですが、つまづいたのは、フロントエンドとバックエンドの両方で、サーバーを起動する必要があったということです。
今回のケースで言うと、LWRサーバーとNode.jsサーバーをそれぞれに対応したコマンドを実行して、同時に起動する必要がありました。ただ何を思ったか、私は「サーバーは同時に一つしか起動できない」という謎の制約を自分にかけており、一つのターミナルで、LWRサーバーを起動して、一度停止させてからNode.jsサーバーを起動するという行為を繰り返していました。 今思うと本当に滑稽です。何時間も悩んだ後に図に書いて整理しようと思い、全体のシステム構成図を書いてる時に、「あれ、これ両方同時に立ち上げる必要あるんじゃね」と気づいたことで解決しました。
アプリケーションという単位が分からない
Salesforceにおける(Lightning)アプリケーションと言えば、単なるタブの集まりです。全然難しい概念ではありません。もちろん他の文脈でもアプリケーションやアプリという単語はよく登場しますが、今まで私はそれがどのような実体を指しているのかについてあまり意識していませんでした。
今回作ったアプリはフロントエンドとバックエンドに分かれてはいますが、自分の感覚としては両方合わせて1つのアプリだという認識でした。なのでHeroku上にアプリをデプロイする時も、それを1つのHerokuアプリとしてデプロイするということに何も疑問を抱きませんでした。 これが大幅につまずく原因となります。
前述した通り、LWRとNode.js それぞれのサーバーを起動させるためには2つのコマンドを実行する必要があります。ただ単純にProcfileに2つコマンドを書くだけではうまくいきません。複数アプリを同時に立ち上げる方法もあるっぽいのですが、原則としてはHerokuは1つのDynoに1つのアプリケーションを動作させるのが基本のようです。私はフロントエンドでバックエンド合わせて1つのアプリだという認識だったので、APIリクエストをLWR側からNode.js側にリダイレクトするためにプロキシを設定するなど、わけもわからずガチャガチャ作業して、沼にハマってしまいました。何時間か格闘したのちに、「ローカルで実行した時と同じで、それぞれを別のプロセスで立ち上げればいいんじゃね」と思い立ち、Herokuアプリを2つ用意してデプロイしたら、なんの問題もなく動作しました。なんでこんなことにも気づかなかったのだろうと少し残念な気持ちになりました。
JSforceはとても簡単だった
一つくらい良かったことも書いておくと、JSforceはとっても使いやすかったです。JavaScriptにそんなに成熟しているわけでもない私でも、「え、こんな簡単にSalesforceデータが取れるの!」と感動しました。
実際、以下のような10行以下のコードでデータが取れてしまいます。コードは公式サイトからの引用です。
var jsforce = require('jsforce');
var conn = new jsforce.Connection();
conn.login('username@domain.com', 'password', function(err, res) {
if (err) { return console.error(err); }
conn.query('SELECT Id, Name FROM Account', function(err, res) {
if (err) { return console.error(err); }
console.log(res);
});
});
データ取得だけでなくCRUD全てにおいて、直観的かつ簡単にデータ操作ができて、大変便利だなと思いました。デファクトとなっている理由がよく分かりました。
終わりに
かなり初歩的なところでのつまずきだったので、ネット上に公開するのに少し抵抗もありましたが、もしかしたら誰かの役に立つかもしれないので、恥を忍んで投稿してみました。
思ったより記事が長くなってしまったので、LWRに関してつまずいたことは別記事で書きたいなと思います。LWRの場合は一般的なWeb知識不足でつまずいたというよりも、単純に解説されてる記事やドキュメント不足で分かりにくかったなという印象です。あともし需要がありそうだったら、アプリの構成などより技術的な部分の記事も書くかもしれないです。