Dev Hub Trial Orgはトライアル期限が過ぎてしまうと無用の長物になるわけなので、削除したいことがあります。
~/.sfdx
の下にある、 {Dev Hub Orgのユーザ名}.json
を消せばいいみたいです。
あと、~/.sfdx/alias.json
の方も修正する必要もあるかもしれません。
Dev Hub Trial Orgはトライアル期限が過ぎてしまうと無用の長物になるわけなので、削除したいことがあります。
~/.sfdx
の下にある、 {Dev Hub Orgのユーザ名}.json
を消せばいいみたいです。
あと、~/.sfdx/alias.json
の方も修正する必要もあるかもしれません。
sfdxにも少しずつ慣れていきたいなと思い、色々試してみようとしているところです。
手始めに
$ sfdx help
とヘルプコマンドを打ち、そこで初めて、sfdxはプラグイン機構を備えていることを知りました。
sfdxのカスタムプラグインはどんな感じに作られるのか、試してみました。
https://github.com/tq-jappy/sfdx-hello-plugin
$ sfdx hello:sayHello
と打つと、
Hello sfdx!
とコンソールに出力するだけのものです。
これまで、趣味と実益を兼ねて、RedmineやJenkinsのプラグインの作成(や改修)に関わってきましたが、プラグインの作り方を学ぶには、似たような動作をする既存のプラグインを真似するのが一番の近道だと思っています。
とはいえ、sfdxの場合、まだそんなに数が豊富にあるわけではないので、「そもそもどうやって作ればいいんだろう?」と思って検索したところ、例えば以下のようなリポジトリが見つかりました。
あと、作者の方の紹介記事もありました。
これらを踏まえて、作りました。
基本的には、sfdxのプラグインは普通のNode.js開発の要領で作っていけばよいみたいですね。
エントリポイント(メイン) である index.js
の中で、 topics
, namespace
, commands
をそれぞれ exports してあげるのがルールなようです。
ただ、コマンド体系が複雑でなければ、namespaceは省略してもよいみたいです。プラグインの作法としてはさておき、動作上は問題ありませんでした。
コマンドのロジックは以下のコードです。 context
の中には認証情報なども含まれていそうなので、うまく駆使すれば色んな用途を満たすプラグインが作れるんじゃないかなと。
(function() { 'use strict'; module.exports = { topic: 'hello', command: 'sayHello', description: 'display hello message', run(context) { console.log('Hello sfdx!'); } } }());
JavaScriptで作成することから、jsforce(やその他のJS系のSalesforceライブラリ)と組み合わせるとよさそうですね。
今のプロジェクトでは、sfdxは実戦投入できていないものの、Jenkins, jsforce, gulp, jsforce-metadata-toolsを使ったCIを組んでおり、その中でApexのテスト結果をJenkinsのJunit/Coberturaレポート形式に出力する、みたいなこともしているのですが、そういう部分をsfdxのプラグイン化することで、sfdxへの移行も緩やかにしていけそうな気がしました。
昨日のエントリで検討した通り、シンプルな画面を新規開発する場合においては、Lightning基本コンポーネントを極力使って開発する、というのも、今後は一つの選択肢なんじゃないかなーという仮説を立ててみました。
Lightning基本コンポーネントについては、以下に書かれています。
しかし、実際に開発する場合、上記ドキュメント(リファレンス)を参照しながら、ということになると思うのですが、案外しんどいことに気づきます。
それはなぜかというと、ドキュメントがテキストのみであり、結果としてどういうUIになるか、仕上がりのプレビューがないことに起因します。
そのため、ちゃんとしたものを作ろうとすると、開発者ガイド、SLDSのドキュメント、場合によってはちょんプロを作ったりと、試行錯誤して作っていくことになりそうだなと予想しています。
(と、思っているんですけど、皆さんどうしているんでしょうね…?)
というわけで、本題です。
開発のハードルを下げるためには、「ライブエディタ(リアルタイムプレビュー)とかあったらいいんじゃない?」と思い立ち、空き時間を利用して作り始めてみました。
まぁ、車輪の再発明の気もしなくもないですが、練習も兼ねてなのでいいかなと。
作ってる画面の例として、lightning:layout
の場合は、以下のようなものです*1。
このライブエディタ自体も、極力Lightning基本コンポーネントを使って開発するように、意識しています。
動きとしては、コンポーネントの属性値 horizontalAlign
などを入力パラメータとして受け取って、その度にコントローラ側で $A.createComponents
でコンポーネントを再作成し、PreviewとCodeに反映しています。
実際に動かしてみると、 horizontalAlign
属性には center, space, spread, endの4つのオプションがあるわけですが、それぞれのオプションで配置にどのような違いがあるのかも一目瞭然で、なかなか便利そうな気がしています。
まだまだ作りが荒いですが、モチベを保つ意味で紹介してみました。 sfdxでCI/CDをやりつつ、年内くらいには形になるといいな…。
*1:PreviewとCodeで数字がズレているのはバグですね…
アプリをSalesforce ClassicからLightning Experience(LEX)に移行するにあたり、検討・整理した事項についてのメモです。
Salesforceの新しいUIであるLEXですが、開発する画面のLook & FeelをLEXに合わせるためには、私が知る範囲では少なくとも以下の4つの方法があります。
lightningStylesheets="true"
を宣言した上でSLDSを読み込み、Visualforceの標準コンポーネントをLEX風にスタイル設定するまぁ、どれも根底のスタイル装飾はSLDSなわけですが、作り方・扱い方の違いという観点で、4つを分けました。
主観でメリット、デメリットを整理するとこんな感じです(デメリットと言ってよいものか迷うものもありますが…)。
方式 | メリット | デメリット |
---|---|---|
SLDSスクラッチ | 開発方式や表現力の自由度が高い | マークアップが辛い。 SLDSのバージョンアップに追随する場合、コストをかけて対応が必要。 |
Reactライブラリ | 充実したフロントエンド開発のエコシステムに乗っかって開発ができる | SLDSのバージョンアップにライブラリが対応していく必要がある(利用については自己責任) |
Visualforce | ある程度成熟したVFの成果物を大きく変えずにLEX化できる | 完璧ではないので、SLDSを使って細かい調整が必要になることもある。 Visualforceなので、表示領域の高さを固定にしておく必要がある(必要なコンテンツの高さだけ確保する、というのが難しい) |
Lightning基本コンポーネント | 継続的なアップデートと後方互換性が見込まれる(多分) | 利用可能なコンポーネントには限りがある |
汎用性(適用範囲)と生産性の高さのバランスがよいので、総合的には2番目がベターかなー、という気がしています。
もう少し掘り下げると、それぞれの方式が適切な用途というのは、それぞれ次のような時かなと思っています。
方式 | あてはまるケース |
---|---|
SLDSスクラッチ | 慣れているSPA方式で開発したい場合(React以外のライブラリ利用時。Vue.jsとか…?) |
Reactライブラリ | 慣れているSPA方式で開発したい場合(React利用時) |
Visualforce | Visualforceの標準コンポーネントを駆使して作られた既存のVisualforceページをLEX対応したい場合 |
Lightning基本コンポーネント | 新規で作る画面であり、比較的シンプルな場合 |
また、4つの方式は排他的なものではなく、複数を組み合わせて開発することもあるかもしれません。
分かりにくい表ですが、その場合の組み合わせ方は下表のような手段を利用することになりそうです*1。
1番目と2番めは、成果物はSPA方式の静的リソースであるという観点では一緒なので、同一のものと見なしています。
取り込む側\取り込まれる側 | SLDSスクラッチ Reactライブラリ (=HTML,JS,CSS) |
Visualforce | Lightningコンポーネント |
---|---|---|---|
SLDSスクラッチ Reactライブラリ |
BrowserifyやWebpack等、普通のJSエコシステムの世界 | 無理(?) | Lightning Out |
Visualforce | 静的リソースとして読み込み | VFコンポーネント化すればVF in VFは可。もしくはiframe | Lightning Out |
Lightningコンポーネント | lightning:container, ltng:require | iframe | <lightning:コンポーネント名>, <c:コンポーネント名> |
*1:実際に試していないものもあるため、かなり雑なまとめです…。
Lightningコンポーネントには $A.createComponent
や $A.createComponents
メソッドを利用して、コントローラ(or ヘルパー)側で動的にコンポーネントを作成する手段が用意されています。
2つのメソッドの違いは単一のコンポーネントを作るか、複数の(特にネストした)コンポーネントを作るか、にあります。
$A.createComponents
メソッドを使って、どれくらい複雑なコンポーネントが作れるものなのか確認してみました。
試したサンプルは、lightning:layoutにあるものです(↓)。
<aura:component> <div class="c-container"> <lightning:layout horizontalAlign="space"> <lightning:layoutItem flexibility="auto" padding="around-small"> 1 </lightning:layoutItem> <lightning:layoutItem flexibility="auto" padding="around-small"> 2 </lightning:layoutItem> <lightning:layoutItem flexibility="auto" padding="around-small"> 3 </lightning:layoutItem> <lightning:layoutItem flexibility="auto" padding="around-small"> 4 </lightning:layoutItem> </lightning:layout> </div> </aura:component>
そこまで複雑というわけではないですね。。
ただ、公式の例( ui:message
と ui:outputText
)と比べ、複数の子要素( lightning:layoutItem
)を含んでいたりするので、これくらいのものができれば、後は応用が効きそうだということで選定しました。
Lightningコンポーネントはこんな感じになりました。
コントローラ(後述)で作成した lightning:layout
, lightning:layoutItem
を {! v.contents}
のところで出力させるようにします。
<aura:component implements="flexipage:availableForAllPageTypes" access="global"> <aura:attribute name="contents" type="String" /> <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> <div class="c-container"> {! v.contents } </div> </aura:component>
なお、 implements="flexipage:availableForAllPageTypes" access="global"
の部分に関しては、動作確認を適当なLightningページでするためのものなので、今回の本筋ではないです。
コンポーネントを作成する肝心のコントローラの doInit
は次のようになりました。
({ doInit : function(component, event, helper) { $A.createComponents([ ["lightning:layout", { "horizontalAlign" : "space" }], ["lightning:layoutItem", { "flexibility" : "auto", "padding" : "around-small" }], ["ui:outputText",{ "value" : "1" }], ["lightning:layoutItem", { "flexibility" : "auto", "padding" : "around-small" }], ["ui:outputText",{ "value" : "2" }], ["lightning:layoutItem", { "flexibility" : "auto", "padding" : "around-small" }], ["ui:outputText",{ "value" : "3" }], ["lightning:layoutItem", { "flexibility" : "auto", "padding" : "around-small" }], ["ui:outputText",{ "value" : "4" }], ], function(components, status, errorMessage){ if (status === "SUCCESS") { var layout = components[0]; var layoutItems = [ components[1], components[3], components[5], components[7] ]; var outputTexts = [ components[2], components[4], components[6], components[8] ]; // それぞれの lightning:layoutItem に値をセット for (var i=0; i<4; i++) { layoutItems[i].set("v.body", outputTexts[i]); } // lightning:layout の下に lightning:layoutItem をセット var layoutBody = layout.get("v.body"); for (var i =0; i<4; i++) { layoutBody.push(layoutItems[i]); } layout.set("v.body", layoutBody); component.set("v.contents", layout); } else if (status === "INCOMPLETE") { console.log("No response from server or client is offline.") // Show offline error } else if (status === "ERROR") { console.log("Error: " + errorMessage); // Show error message } } ); } })
長いですね…。
子要素が4つあるサンプルのため冗長であることをを抜きにしても、結構長いです。
注意する点として、 set("v.body", ...)
で中身をセットしたい場合、セットする値もコンポーネントである必要があります。
なので、lightning:layoutItem
の中身は表示したい文字列ではなく、 ui:outputText
コンポーネントになっています *1 。
もし、
layoutItems[i].set("v.body", "" + i);
のようにしてしまうと、
Uncaught Assertion Failed!: Descriptor for Config required for registration : undefined
といったエラーが起きます。
というわけで、複数の子要素を含んだLightningコンポーネントでも一応は動的に作成可能であることが確認できました。
*1:実はこのせいで、出力されるHTMLはオリジナルのものとは微妙に異なります。ui:outputText はspanタグを作ってしまうので。
Salesforce Platformの上でApexクラス・トリガやLightningコンポーネントを開発していく上でのデザインパターンについてのまとめ。
他にもあるかもしれないです(知っていたら教えてください)
先人の知恵、大事。
Trigger Frameworks and Apex Trigger Best Practices - developer.force.com
適用していないプロジェクトの方が少ないかもしれないくらい定番かもしれないですね。
複数のオブジェクトを操作するような混み入ったDMLを扱う時に、 bypass
, clearBypass
が役立ちます。
広範囲のパターン集(全部はまだ追えていません…)
ApexCallだとこちら。
早速今年のAdvent Calendarからですね。 なるほどー!と思いました(小並感)
パターンというよりもガッツリしたライブラリですが。使い所は選びそう。。
以上。
あとは、Apex言語そのものの進化にも期待したいところです。
re:Inventの流れが早くて見逃していたのですが、AWS CodeBuildで依存関係のキャッシュ機構が使えるようになっていました。
昔、自前で似たようなことをするためのやり方を試行錯誤してたのですが、もう不要ですね。
あとあるとすれば、ビルドにカスタムDockerイメージを使っている場合に、イメージのダウンロードに時間がかかってしまう課題が解消できると、最強な気がします。